TypeLocBuilder.h revision 249423
1218887Sdim//===--- TypeLocBuilder.h - Type Source Info collector ----------*- C++ -*-===// 2218887Sdim// 3218887Sdim// The LLVM Compiler Infrastructure 4218887Sdim// 5218887Sdim// This file is distributed under the University of Illinois Open Source 6218887Sdim// License. See LICENSE.TXT for details. 7218887Sdim// 8218887Sdim//===----------------------------------------------------------------------===// 9218887Sdim// 10218887Sdim// This files defines TypeLocBuilder, a class for building TypeLocs 11218887Sdim// bottom-up. 12218887Sdim// 13218887Sdim//===----------------------------------------------------------------------===// 14218887Sdim 15218887Sdim#ifndef LLVM_CLANG_SEMA_TYPELOCBUILDER_H 16218887Sdim#define LLVM_CLANG_SEMA_TYPELOCBUILDER_H 17218887Sdim 18249423Sdim#include "clang/AST/ASTContext.h" 19218887Sdim#include "clang/AST/TypeLoc.h" 20218887Sdim 21218887Sdimnamespace clang { 22218887Sdim 23218887Sdimclass TypeLocBuilder { 24218887Sdim enum { InlineCapacity = 8 * sizeof(SourceLocation) }; 25218887Sdim 26218887Sdim /// The underlying location-data buffer. Data grows from the end 27218887Sdim /// of the buffer backwards. 28218887Sdim char *Buffer; 29218887Sdim 30218887Sdim /// The capacity of the current buffer. 31218887Sdim size_t Capacity; 32218887Sdim 33218887Sdim /// The index of the first occupied byte in the buffer. 34218887Sdim size_t Index; 35218887Sdim 36218887Sdim#ifndef NDEBUG 37218887Sdim /// The last type pushed on this builder. 38218887Sdim QualType LastTy; 39218887Sdim#endif 40218887Sdim 41218887Sdim /// The inline buffer. 42218887Sdim char InlineBuffer[InlineCapacity]; 43218887Sdim 44218887Sdim public: 45218887Sdim TypeLocBuilder() 46221345Sdim : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) {} 47218887Sdim 48218887Sdim ~TypeLocBuilder() { 49218887Sdim if (Buffer != InlineBuffer) 50218887Sdim delete[] Buffer; 51218887Sdim } 52218887Sdim 53218887Sdim /// Ensures that this buffer has at least as much capacity as described. 54218887Sdim void reserve(size_t Requested) { 55218887Sdim if (Requested > Capacity) 56218887Sdim // For now, match the request exactly. 57218887Sdim grow(Requested); 58218887Sdim } 59218887Sdim 60218887Sdim /// Pushes a copy of the given TypeLoc onto this builder. The builder 61218887Sdim /// must be empty for this to work. 62218887Sdim void pushFullCopy(TypeLoc L) { 63218887Sdim size_t Size = L.getFullDataSize(); 64218887Sdim TypeLoc Copy = pushFullUninitializedImpl(L.getType(), Size); 65218887Sdim memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size); 66218887Sdim } 67218887Sdim 68218887Sdim /// Pushes uninitialized space for the given type. The builder must 69218887Sdim /// be empty. 70218887Sdim TypeLoc pushFullUninitialized(QualType T) { 71218887Sdim return pushFullUninitializedImpl(T, TypeLoc::getFullDataSizeForType(T)); 72218887Sdim } 73218887Sdim 74218887Sdim /// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs 75218887Sdim /// previously retrieved from this builder. 76218887Sdim TypeSpecTypeLoc pushTypeSpec(QualType T) { 77218887Sdim size_t LocalSize = TypeSpecTypeLoc::LocalDataSize; 78249423Sdim return pushImpl(T, LocalSize).castAs<TypeSpecTypeLoc>(); 79218887Sdim } 80218887Sdim 81218887Sdim /// Resets this builder to the newly-initialized state. 82218887Sdim void clear() { 83218887Sdim#ifndef NDEBUG 84218887Sdim LastTy = QualType(); 85218887Sdim#endif 86218887Sdim Index = Capacity; 87218887Sdim } 88218887Sdim 89224145Sdim /// \brief Tell the TypeLocBuilder that the type it is storing has been 90224145Sdim /// modified in some safe way that doesn't affect type-location information. 91224145Sdim void TypeWasModifiedSafely(QualType T) { 92224145Sdim#ifndef NDEBUG 93224145Sdim LastTy = T; 94224145Sdim#endif 95224145Sdim } 96224145Sdim 97218887Sdim /// Pushes space for a new TypeLoc of the given type. Invalidates 98218887Sdim /// any TypeLocs previously retrieved from this builder. 99218887Sdim template <class TyLocType> TyLocType push(QualType T) { 100249423Sdim size_t LocalSize = TypeLoc(T, 0).castAs<TyLocType>().getLocalDataSize(); 101249423Sdim return pushImpl(T, LocalSize).castAs<TyLocType>(); 102218887Sdim } 103218887Sdim 104218887Sdim /// Creates a TypeSourceInfo for the given type. 105218887Sdim TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) { 106218887Sdim#ifndef NDEBUG 107218887Sdim assert(T == LastTy && "type doesn't match last type pushed!"); 108218887Sdim#endif 109218887Sdim 110218887Sdim size_t FullDataSize = Capacity - Index; 111218887Sdim TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize); 112218887Sdim memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize); 113218887Sdim return DI; 114218887Sdim } 115218887Sdim 116219077Sdim /// \brief Copies the type-location information to the given AST context and 117219077Sdim /// returns a \c TypeLoc referring into the AST context. 118219077Sdim TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) { 119219077Sdim#ifndef NDEBUG 120219077Sdim assert(T == LastTy && "type doesn't match last type pushed!"); 121219077Sdim#endif 122219077Sdim 123219077Sdim size_t FullDataSize = Capacity - Index; 124219077Sdim void *Mem = Context.Allocate(FullDataSize); 125219077Sdim memcpy(Mem, &Buffer[Index], FullDataSize); 126219077Sdim return TypeLoc(T, Mem); 127219077Sdim } 128219077Sdim 129218887Sdimprivate: 130218887Sdim TypeLoc pushImpl(QualType T, size_t LocalSize) { 131218887Sdim#ifndef NDEBUG 132218887Sdim QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType(); 133218887Sdim assert(TLast == LastTy && 134218887Sdim "mismatch between last type and new type's inner type"); 135218887Sdim LastTy = T; 136218887Sdim#endif 137218887Sdim 138218887Sdim // If we need to grow, grow by a factor of 2. 139218887Sdim if (LocalSize > Index) { 140218887Sdim size_t RequiredCapacity = Capacity + (LocalSize - Index); 141218887Sdim size_t NewCapacity = Capacity * 2; 142218887Sdim while (RequiredCapacity > NewCapacity) 143218887Sdim NewCapacity *= 2; 144218887Sdim grow(NewCapacity); 145218887Sdim } 146218887Sdim 147218887Sdim Index -= LocalSize; 148218887Sdim 149224145Sdim return getTemporaryTypeLoc(T); 150218887Sdim } 151218887Sdim 152218887Sdim /// Grow to the given capacity. 153218887Sdim void grow(size_t NewCapacity) { 154218887Sdim assert(NewCapacity > Capacity); 155218887Sdim 156218887Sdim // Allocate the new buffer and copy the old data into it. 157218887Sdim char *NewBuffer = new char[NewCapacity]; 158218887Sdim unsigned NewIndex = Index + NewCapacity - Capacity; 159218887Sdim memcpy(&NewBuffer[NewIndex], 160218887Sdim &Buffer[Index], 161218887Sdim Capacity - Index); 162218887Sdim 163218887Sdim if (Buffer != InlineBuffer) 164218887Sdim delete[] Buffer; 165218887Sdim 166218887Sdim Buffer = NewBuffer; 167218887Sdim Capacity = NewCapacity; 168218887Sdim Index = NewIndex; 169218887Sdim } 170218887Sdim 171218887Sdim TypeLoc pushFullUninitializedImpl(QualType T, size_t Size) { 172218887Sdim#ifndef NDEBUG 173218887Sdim assert(LastTy.isNull() && "pushing full on non-empty TypeLocBuilder"); 174218887Sdim LastTy = T; 175218887Sdim#endif 176218887Sdim assert(Index == Capacity && "pushing full on non-empty TypeLocBuilder"); 177218887Sdim 178218887Sdim reserve(Size); 179218887Sdim Index -= Size; 180218887Sdim 181224145Sdim return getTemporaryTypeLoc(T); 182218887Sdim } 183218887Sdim 184224145Sdimpublic: 185224145Sdim /// \brief Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder 186224145Sdim /// object. 187224145Sdim /// 188224145Sdim /// The resulting \c TypeLoc should only be used so long as the 189224145Sdim /// \c TypeLocBuilder is active and has not had more type information 190224145Sdim /// pushed into it. 191224145Sdim TypeLoc getTemporaryTypeLoc(QualType T) { 192218887Sdim#ifndef NDEBUG 193218887Sdim assert(LastTy == T && "type doesn't match last type pushed!"); 194218887Sdim#endif 195218887Sdim return TypeLoc(T, &Buffer[Index]); 196218887Sdim } 197218887Sdim}; 198218887Sdim 199218887Sdim} 200218887Sdim 201218887Sdim#endif 202