TypeLocBuilder.h revision 219077
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 "llvm/ADT/SmallVector.h" 20#include "clang/AST/ASTContext.h" 21 22namespace clang { 23 24class TypeLocBuilder { 25 enum { InlineCapacity = 8 * sizeof(SourceLocation) }; 26 27 /// The underlying location-data buffer. Data grows from the end 28 /// of the buffer backwards. 29 char *Buffer; 30 31 /// The capacity of the current buffer. 32 size_t Capacity; 33 34 /// The index of the first occupied byte in the buffer. 35 size_t Index; 36 37#ifndef NDEBUG 38 /// The last type pushed on this builder. 39 QualType LastTy; 40#endif 41 42 /// The inline buffer. 43 char InlineBuffer[InlineCapacity]; 44 45 public: 46 TypeLocBuilder() 47 : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) 48 {} 49 50 ~TypeLocBuilder() { 51 if (Buffer != InlineBuffer) 52 delete[] Buffer; 53 } 54 55 /// Ensures that this buffer has at least as much capacity as described. 56 void reserve(size_t Requested) { 57 if (Requested > Capacity) 58 // For now, match the request exactly. 59 grow(Requested); 60 } 61 62 /// Pushes a copy of the given TypeLoc onto this builder. The builder 63 /// must be empty for this to work. 64 void pushFullCopy(TypeLoc L) { 65 size_t Size = L.getFullDataSize(); 66 TypeLoc Copy = pushFullUninitializedImpl(L.getType(), Size); 67 memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size); 68 } 69 70 /// Pushes uninitialized space for the given type. The builder must 71 /// be empty. 72 TypeLoc pushFullUninitialized(QualType T) { 73 return pushFullUninitializedImpl(T, TypeLoc::getFullDataSizeForType(T)); 74 } 75 76 /// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs 77 /// previously retrieved from this builder. 78 TypeSpecTypeLoc pushTypeSpec(QualType T) { 79 size_t LocalSize = TypeSpecTypeLoc::LocalDataSize; 80 return cast<TypeSpecTypeLoc>(pushImpl(T, LocalSize)); 81 } 82 83 /// Resets this builder to the newly-initialized state. 84 void clear() { 85#ifndef NDEBUG 86 LastTy = QualType(); 87#endif 88 Index = Capacity; 89 } 90 91 /// Pushes space for a new TypeLoc of the given type. Invalidates 92 /// any TypeLocs previously retrieved from this builder. 93 template <class TyLocType> TyLocType push(QualType T) { 94 size_t LocalSize = cast<TyLocType>(TypeLoc(T, 0)).getLocalDataSize(); 95 return cast<TyLocType>(pushImpl(T, LocalSize)); 96 } 97 98 /// Creates a TypeSourceInfo for the given type. 99 TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) { 100#ifndef NDEBUG 101 assert(T == LastTy && "type doesn't match last type pushed!"); 102#endif 103 104 size_t FullDataSize = Capacity - Index; 105 TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize); 106 memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize); 107 return DI; 108 } 109 110 /// \brief Copies the type-location information to the given AST context and 111 /// returns a \c TypeLoc referring into the AST context. 112 TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) { 113#ifndef NDEBUG 114 assert(T == LastTy && "type doesn't match last type pushed!"); 115#endif 116 117 size_t FullDataSize = Capacity - Index; 118 void *Mem = Context.Allocate(FullDataSize); 119 memcpy(Mem, &Buffer[Index], FullDataSize); 120 return TypeLoc(T, Mem); 121 } 122 123private: 124 TypeLoc pushImpl(QualType T, size_t LocalSize) { 125#ifndef NDEBUG 126 QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType(); 127 assert(TLast == LastTy && 128 "mismatch between last type and new type's inner type"); 129 LastTy = T; 130#endif 131 132 // If we need to grow, grow by a factor of 2. 133 if (LocalSize > Index) { 134 size_t RequiredCapacity = Capacity + (LocalSize - Index); 135 size_t NewCapacity = Capacity * 2; 136 while (RequiredCapacity > NewCapacity) 137 NewCapacity *= 2; 138 grow(NewCapacity); 139 } 140 141 Index -= LocalSize; 142 143 return getTypeLoc(T); 144 } 145 146 /// Grow to the given capacity. 147 void grow(size_t NewCapacity) { 148 assert(NewCapacity > Capacity); 149 150 // Allocate the new buffer and copy the old data into it. 151 char *NewBuffer = new char[NewCapacity]; 152 unsigned NewIndex = Index + NewCapacity - Capacity; 153 memcpy(&NewBuffer[NewIndex], 154 &Buffer[Index], 155 Capacity - Index); 156 157 if (Buffer != InlineBuffer) 158 delete[] Buffer; 159 160 Buffer = NewBuffer; 161 Capacity = NewCapacity; 162 Index = NewIndex; 163 } 164 165 TypeLoc pushFullUninitializedImpl(QualType T, size_t Size) { 166#ifndef NDEBUG 167 assert(LastTy.isNull() && "pushing full on non-empty TypeLocBuilder"); 168 LastTy = T; 169#endif 170 assert(Index == Capacity && "pushing full on non-empty TypeLocBuilder"); 171 172 reserve(Size); 173 Index -= Size; 174 175 return getTypeLoc(T); 176 } 177 178 179 // This is private because, when we kill off TypeSourceInfo in favor 180 // of TypeLoc, we'll want an interface that creates a TypeLoc given 181 // an ASTContext, and we don't want people to think they can just 182 // use this as an equivalent. 183 TypeLoc getTypeLoc(QualType T) { 184#ifndef NDEBUG 185 assert(LastTy == T && "type doesn't match last type pushed!"); 186#endif 187 return TypeLoc(T, &Buffer[Index]); 188 } 189}; 190 191} 192 193#endif 194