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