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