1218887Sdim//===--- TypeLocBuilder.h - Type Source Info collector ----------*- C++ -*-===//
2218887Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6218887Sdim//
7218887Sdim//===----------------------------------------------------------------------===//
8218887Sdim//
9309124Sdim//  This file defines TypeLocBuilder, a class for building TypeLocs
10218887Sdim//  bottom-up.
11218887Sdim//
12218887Sdim//===----------------------------------------------------------------------===//
13218887Sdim
14280031Sdim#ifndef LLVM_CLANG_LIB_SEMA_TYPELOCBUILDER_H
15280031Sdim#define LLVM_CLANG_LIB_SEMA_TYPELOCBUILDER_H
16218887Sdim
17249423Sdim#include "clang/AST/ASTContext.h"
18218887Sdim#include "clang/AST/TypeLoc.h"
19218887Sdim
20218887Sdimnamespace clang {
21218887Sdim
22218887Sdimclass TypeLocBuilder {
23218887Sdim  enum { InlineCapacity = 8 * sizeof(SourceLocation) };
24218887Sdim
25218887Sdim  /// The underlying location-data buffer.  Data grows from the end
26218887Sdim  /// of the buffer backwards.
27218887Sdim  char *Buffer;
28218887Sdim
29218887Sdim  /// The capacity of the current buffer.
30218887Sdim  size_t Capacity;
31218887Sdim
32218887Sdim  /// The index of the first occupied byte in the buffer.
33218887Sdim  size_t Index;
34218887Sdim
35218887Sdim#ifndef NDEBUG
36218887Sdim  /// The last type pushed on this builder.
37218887Sdim  QualType LastTy;
38218887Sdim#endif
39341825Sdim
40218887Sdim  /// The inline buffer.
41314564Sdim  enum { BufferMaxAlignment = alignof(void *) };
42360784Sdim  alignas(BufferMaxAlignment) char InlineBuffer[InlineCapacity];
43261991Sdim  unsigned NumBytesAtAlign4, NumBytesAtAlign8;
44218887Sdim
45360784Sdimpublic:
46218887Sdim  TypeLocBuilder()
47360784Sdim      : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity),
48360784Sdim        NumBytesAtAlign4(0), NumBytesAtAlign8(0) {}
49218887Sdim
50218887Sdim  ~TypeLocBuilder() {
51360784Sdim    if (Buffer != InlineBuffer)
52218887Sdim      delete[] Buffer;
53218887Sdim  }
54218887Sdim
55218887Sdim  /// Ensures that this buffer has at least as much capacity as described.
56218887Sdim  void reserve(size_t Requested) {
57218887Sdim    if (Requested > Capacity)
58218887Sdim      // For now, match the request exactly.
59218887Sdim      grow(Requested);
60218887Sdim  }
61218887Sdim
62218887Sdim  /// Pushes a copy of the given TypeLoc onto this builder.  The builder
63218887Sdim  /// must be empty for this to work.
64261991Sdim  void pushFullCopy(TypeLoc L);
65218887Sdim
66218887Sdim  /// Pushes space for a typespec TypeLoc.  Invalidates any TypeLocs
67218887Sdim  /// previously retrieved from this builder.
68218887Sdim  TypeSpecTypeLoc pushTypeSpec(QualType T) {
69218887Sdim    size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
70261991Sdim    unsigned LocalAlign = TypeSpecTypeLoc::LocalDataAlignment;
71261991Sdim    return pushImpl(T, LocalSize, LocalAlign).castAs<TypeSpecTypeLoc>();
72218887Sdim  }
73218887Sdim
74218887Sdim  /// Resets this builder to the newly-initialized state.
75218887Sdim  void clear() {
76218887Sdim#ifndef NDEBUG
77218887Sdim    LastTy = QualType();
78218887Sdim#endif
79218887Sdim    Index = Capacity;
80261991Sdim    NumBytesAtAlign4 = NumBytesAtAlign8 = 0;
81341825Sdim  }
82218887Sdim
83341825Sdim  /// Tell the TypeLocBuilder that the type it is storing has been
84224145Sdim  /// modified in some safe way that doesn't affect type-location information.
85224145Sdim  void TypeWasModifiedSafely(QualType T) {
86224145Sdim#ifndef NDEBUG
87224145Sdim    LastTy = T;
88224145Sdim#endif
89224145Sdim  }
90341825Sdim
91218887Sdim  /// Pushes space for a new TypeLoc of the given type.  Invalidates
92218887Sdim  /// any TypeLocs previously retrieved from this builder.
93218887Sdim  template <class TyLocType> TyLocType push(QualType T) {
94276479Sdim    TyLocType Loc = TypeLoc(T, nullptr).castAs<TyLocType>();
95261991Sdim    size_t LocalSize = Loc.getLocalDataSize();
96261991Sdim    unsigned LocalAlign = Loc.getLocalDataAlignment();
97261991Sdim    return pushImpl(T, LocalSize, LocalAlign).castAs<TyLocType>();
98218887Sdim  }
99218887Sdim
100218887Sdim  /// Creates a TypeSourceInfo for the given type.
101218887Sdim  TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) {
102218887Sdim#ifndef NDEBUG
103218887Sdim    assert(T == LastTy && "type doesn't match last type pushed!");
104218887Sdim#endif
105218887Sdim
106218887Sdim    size_t FullDataSize = Capacity - Index;
107218887Sdim    TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize);
108218887Sdim    memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
109218887Sdim    return DI;
110218887Sdim  }
111218887Sdim
112341825Sdim  /// Copies the type-location information to the given AST context and
113219077Sdim  /// returns a \c TypeLoc referring into the AST context.
114219077Sdim  TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) {
115219077Sdim#ifndef NDEBUG
116219077Sdim    assert(T == LastTy && "type doesn't match last type pushed!");
117219077Sdim#endif
118341825Sdim
119219077Sdim    size_t FullDataSize = Capacity - Index;
120219077Sdim    void *Mem = Context.Allocate(FullDataSize);
121219077Sdim    memcpy(Mem, &Buffer[Index], FullDataSize);
122219077Sdim    return TypeLoc(T, Mem);
123219077Sdim  }
124219077Sdim
125218887Sdimprivate:
126218887Sdim
127261991Sdim  TypeLoc pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment);
128218887Sdim
129218887Sdim  /// Grow to the given capacity.
130261991Sdim  void grow(size_t NewCapacity);
131218887Sdim
132341825Sdim  /// Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder
133224145Sdim  /// object.
134224145Sdim  ///
135341825Sdim  /// The resulting \c TypeLoc should only be used so long as the
136224145Sdim  /// \c TypeLocBuilder is active and has not had more type information
137224145Sdim  /// pushed into it.
138224145Sdim  TypeLoc getTemporaryTypeLoc(QualType T) {
139218887Sdim#ifndef NDEBUG
140218887Sdim    assert(LastTy == T && "type doesn't match last type pushed!");
141218887Sdim#endif
142218887Sdim    return TypeLoc(T, &Buffer[Index]);
143218887Sdim  }
144218887Sdim};
145218887Sdim
146218887Sdim}
147218887Sdim
148218887Sdim#endif
149