1 //===--- TypeLocBuilder.h - Type Source Info collector ----------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //  This file defines TypeLocBuilder, a class for building TypeLocs
10 //  bottom-up.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_LIB_SEMA_TYPELOCBUILDER_H
15 #define LLVM_CLANG_LIB_SEMA_TYPELOCBUILDER_H
16 
17 #include "clang/AST/ASTContext.h"
18 #include "clang/AST/TypeLoc.h"
19 
20 namespace clang {
21 
22 class TypeLocBuilder {
23   enum { InlineCapacity = 8 * sizeof(SourceLocation) };
24 
25   /// The underlying location-data buffer.  Data grows from the end
26   /// of the buffer backwards.
27   char *Buffer;
28 
29   /// The capacity of the current buffer.
30   size_t Capacity;
31 
32   /// The index of the first occupied byte in the buffer.
33   size_t Index;
34 
35 #ifndef NDEBUG
36   /// The last type pushed on this builder.
37   QualType LastTy;
38 #endif
39 
40   /// The inline buffer.
41   enum { BufferMaxAlignment = alignof(void *) };
42   alignas(BufferMaxAlignment) char InlineBuffer[InlineCapacity];
43   unsigned NumBytesAtAlign4;
44   bool AtAlign8;
45 
46 public:
TypeLocBuilder()47   TypeLocBuilder()
48       : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity),
49         NumBytesAtAlign4(0), AtAlign8(false) {}
50 
~TypeLocBuilder()51   ~TypeLocBuilder() {
52     if (Buffer != InlineBuffer)
53       delete[] Buffer;
54   }
55 
56   TypeLocBuilder(const TypeLocBuilder &) = delete;
57   TypeLocBuilder &operator=(const TypeLocBuilder &) = delete;
58 
59   /// Ensures that this buffer has at least as much capacity as described.
reserve(size_t Requested)60   void reserve(size_t Requested) {
61     if (Requested > Capacity)
62       // For now, match the request exactly.
63       grow(Requested);
64   }
65 
66   /// Pushes a copy of the given TypeLoc onto this builder.  The builder
67   /// must be empty for this to work.
68   void pushFullCopy(TypeLoc L);
69 
70   /// Pushes 'T' with all locations pointing to 'Loc'.
71   /// The builder must be empty for this to work.
72   void pushTrivial(ASTContext &Context, QualType T, SourceLocation Loc);
73 
74   /// Pushes space for a typespec TypeLoc.  Invalidates any TypeLocs
75   /// previously retrieved from this builder.
pushTypeSpec(QualType T)76   TypeSpecTypeLoc pushTypeSpec(QualType T) {
77     size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
78     unsigned LocalAlign = TypeSpecTypeLoc::LocalDataAlignment;
79     return pushImpl(T, LocalSize, LocalAlign).castAs<TypeSpecTypeLoc>();
80   }
81 
82   /// Resets this builder to the newly-initialized state.
clear()83   void clear() {
84 #ifndef NDEBUG
85     LastTy = QualType();
86 #endif
87     Index = Capacity;
88     NumBytesAtAlign4 = 0;
89     AtAlign8 = false;
90   }
91 
92   /// Tell the TypeLocBuilder that the type it is storing has been
93   /// modified in some safe way that doesn't affect type-location information.
TypeWasModifiedSafely(QualType T)94   void TypeWasModifiedSafely(QualType T) {
95 #ifndef NDEBUG
96     LastTy = T;
97 #endif
98   }
99 
100   /// Pushes space for a new TypeLoc of the given type.  Invalidates
101   /// any TypeLocs previously retrieved from this builder.
push(QualType T)102   template <class TyLocType> TyLocType push(QualType T) {
103     TyLocType Loc = TypeLoc(T, nullptr).castAs<TyLocType>();
104     size_t LocalSize = Loc.getLocalDataSize();
105     unsigned LocalAlign = Loc.getLocalDataAlignment();
106     return pushImpl(T, LocalSize, LocalAlign).castAs<TyLocType>();
107   }
108 
109   /// Creates a TypeSourceInfo for the given type.
getTypeSourceInfo(ASTContext & Context,QualType T)110   TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) {
111 #ifndef NDEBUG
112     assert(T == LastTy && "type doesn't match last type pushed!");
113 #endif
114 
115     size_t FullDataSize = Capacity - Index;
116     TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize);
117     memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
118     return DI;
119   }
120 
121   /// Copies the type-location information to the given AST context and
122   /// returns a \c TypeLoc referring into the AST context.
getTypeLocInContext(ASTContext & Context,QualType T)123   TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) {
124 #ifndef NDEBUG
125     assert(T == LastTy && "type doesn't match last type pushed!");
126 #endif
127 
128     size_t FullDataSize = Capacity - Index;
129     void *Mem = Context.Allocate(FullDataSize);
130     memcpy(Mem, &Buffer[Index], FullDataSize);
131     return TypeLoc(T, Mem);
132   }
133 
134 private:
135 
136   TypeLoc pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment);
137 
138   /// Grow to the given capacity.
139   void grow(size_t NewCapacity);
140 
141   /// Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder
142   /// object.
143   ///
144   /// The resulting \c TypeLoc should only be used so long as the
145   /// \c TypeLocBuilder is active and has not had more type information
146   /// pushed into it.
getTemporaryTypeLoc(QualType T)147   TypeLoc getTemporaryTypeLoc(QualType T) {
148 #ifndef NDEBUG
149     assert(LastTy == T && "type doesn't match last type pushed!");
150 #endif
151     return TypeLoc(T, &Buffer[Index]);
152   }
153 };
154 
155 }
156 
157 #endif
158