• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_SEMA_TYPELOCBUILDER_H
16 #define LLVM_CLANG_SEMA_TYPELOCBUILDER_H
17 
18 #include "clang/AST/TypeLoc.h"
19 #include "clang/AST/ASTContext.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   char InlineBuffer[InlineCapacity];
43 
44  public:
TypeLocBuilder()45   TypeLocBuilder()
46     : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) {}
47 
~TypeLocBuilder()48   ~TypeLocBuilder() {
49     if (Buffer != InlineBuffer)
50       delete[] Buffer;
51   }
52 
53   /// Ensures that this buffer has at least as much capacity as described.
reserve(size_t Requested)54   void reserve(size_t Requested) {
55     if (Requested > Capacity)
56       // For now, match the request exactly.
57       grow(Requested);
58   }
59 
60   /// Pushes a copy of the given TypeLoc onto this builder.  The builder
61   /// must be empty for this to work.
pushFullCopy(TypeLoc L)62   void pushFullCopy(TypeLoc L) {
63     size_t Size = L.getFullDataSize();
64     TypeLoc Copy = pushFullUninitializedImpl(L.getType(), Size);
65     memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size);
66   }
67 
68   /// Pushes uninitialized space for the given type.  The builder must
69   /// be empty.
pushFullUninitialized(QualType T)70   TypeLoc pushFullUninitialized(QualType T) {
71     return pushFullUninitializedImpl(T, TypeLoc::getFullDataSizeForType(T));
72   }
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     return cast<TypeSpecTypeLoc>(pushImpl(T, LocalSize));
79   }
80 
81   /// Resets this builder to the newly-initialized state.
clear()82   void clear() {
83 #ifndef NDEBUG
84     LastTy = QualType();
85 #endif
86     Index = Capacity;
87   }
88 
89   /// \brief Tell the TypeLocBuilder that the type it is storing has been
90   /// modified in some safe way that doesn't affect type-location information.
TypeWasModifiedSafely(QualType T)91   void TypeWasModifiedSafely(QualType T) {
92 #ifndef NDEBUG
93     LastTy = T;
94 #endif
95   }
96 
97   /// Pushes space for a new TypeLoc of the given type.  Invalidates
98   /// any TypeLocs previously retrieved from this builder.
push(QualType T)99   template <class TyLocType> TyLocType push(QualType T) {
100     size_t LocalSize = cast<TyLocType>(TypeLoc(T, 0)).getLocalDataSize();
101     return cast<TyLocType>(pushImpl(T, LocalSize));
102   }
103 
104   /// Creates a TypeSourceInfo for the given type.
getTypeSourceInfo(ASTContext & Context,QualType T)105   TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) {
106 #ifndef NDEBUG
107     assert(T == LastTy && "type doesn't match last type pushed!");
108 #endif
109 
110     size_t FullDataSize = Capacity - Index;
111     TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize);
112     memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
113     return DI;
114   }
115 
116   /// \brief Copies the type-location information to the given AST context and
117   /// returns a \c TypeLoc referring into the AST context.
getTypeLocInContext(ASTContext & Context,QualType T)118   TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) {
119 #ifndef NDEBUG
120     assert(T == LastTy && "type doesn't match last type pushed!");
121 #endif
122 
123     size_t FullDataSize = Capacity - Index;
124     void *Mem = Context.Allocate(FullDataSize);
125     memcpy(Mem, &Buffer[Index], FullDataSize);
126     return TypeLoc(T, Mem);
127   }
128 
129 private:
pushImpl(QualType T,size_t LocalSize)130   TypeLoc pushImpl(QualType T, size_t LocalSize) {
131 #ifndef NDEBUG
132     QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
133     assert(TLast == LastTy &&
134            "mismatch between last type and new type's inner type");
135     LastTy = T;
136 #endif
137 
138     // If we need to grow, grow by a factor of 2.
139     if (LocalSize > Index) {
140       size_t RequiredCapacity = Capacity + (LocalSize - Index);
141       size_t NewCapacity = Capacity * 2;
142       while (RequiredCapacity > NewCapacity)
143         NewCapacity *= 2;
144       grow(NewCapacity);
145     }
146 
147     Index -= LocalSize;
148 
149     return getTemporaryTypeLoc(T);
150   }
151 
152   /// Grow to the given capacity.
grow(size_t NewCapacity)153   void grow(size_t NewCapacity) {
154     assert(NewCapacity > Capacity);
155 
156     // Allocate the new buffer and copy the old data into it.
157     char *NewBuffer = new char[NewCapacity];
158     unsigned NewIndex = Index + NewCapacity - Capacity;
159     memcpy(&NewBuffer[NewIndex],
160            &Buffer[Index],
161            Capacity - Index);
162 
163     if (Buffer != InlineBuffer)
164       delete[] Buffer;
165 
166     Buffer = NewBuffer;
167     Capacity = NewCapacity;
168     Index = NewIndex;
169   }
170 
pushFullUninitializedImpl(QualType T,size_t Size)171   TypeLoc pushFullUninitializedImpl(QualType T, size_t Size) {
172 #ifndef NDEBUG
173     assert(LastTy.isNull() && "pushing full on non-empty TypeLocBuilder");
174     LastTy = T;
175 #endif
176     assert(Index == Capacity && "pushing full on non-empty TypeLocBuilder");
177 
178     reserve(Size);
179     Index -= Size;
180 
181     return getTemporaryTypeLoc(T);
182   }
183 
184 public:
185   /// \brief Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder
186   /// object.
187   ///
188   /// The resulting \c TypeLoc should only be used so long as the
189   /// \c TypeLocBuilder is active and has not had more type information
190   /// pushed into it.
getTemporaryTypeLoc(QualType T)191   TypeLoc getTemporaryTypeLoc(QualType T) {
192 #ifndef NDEBUG
193     assert(LastTy == T && "type doesn't match last type pushed!");
194 #endif
195     return TypeLoc(T, &Buffer[Index]);
196   }
197 };
198 
199 }
200 
201 #endif
202