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