1 //===--- TypeLocBuilder.h - Type Source Info collector ----------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines TypeLocBuilder, a class for building TypeLocs 10 // bottom-up. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_LIB_SEMA_TYPELOCBUILDER_H 15 #define LLVM_CLANG_LIB_SEMA_TYPELOCBUILDER_H 16 17 #include "clang/AST/ASTContext.h" 18 #include "clang/AST/TypeLoc.h" 19 20 namespace clang { 21 22 class TypeLocBuilder { 23 enum { InlineCapacity = 8 * sizeof(SourceLocation) }; 24 25 /// The underlying location-data buffer. Data grows from the end 26 /// of the buffer backwards. 27 char *Buffer; 28 29 /// The capacity of the current buffer. 30 size_t Capacity; 31 32 /// The index of the first occupied byte in the buffer. 33 size_t Index; 34 35 #ifndef NDEBUG 36 /// The last type pushed on this builder. 37 QualType LastTy; 38 #endif 39 40 /// The inline buffer. 41 enum { BufferMaxAlignment = alignof(void *) }; 42 alignas(BufferMaxAlignment) char InlineBuffer[InlineCapacity]; 43 unsigned NumBytesAtAlign4; 44 bool AtAlign8; 45 46 public: TypeLocBuilder()47 TypeLocBuilder() 48 : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity), 49 NumBytesAtAlign4(0), AtAlign8(false) {} 50 ~TypeLocBuilder()51 ~TypeLocBuilder() { 52 if (Buffer != InlineBuffer) 53 delete[] Buffer; 54 } 55 56 /// Ensures that this buffer has at least as much capacity as described. reserve(size_t Requested)57 void reserve(size_t Requested) { 58 if (Requested > Capacity) 59 // For now, match the request exactly. 60 grow(Requested); 61 } 62 63 /// Pushes a copy of the given TypeLoc onto this builder. The builder 64 /// must be empty for this to work. 65 void pushFullCopy(TypeLoc L); 66 67 /// Pushes 'T' with all locations pointing to 'Loc'. 68 /// The builder must be empty for this to work. 69 void pushTrivial(ASTContext &Context, QualType T, SourceLocation Loc); 70 71 /// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs 72 /// previously retrieved from this builder. pushTypeSpec(QualType T)73 TypeSpecTypeLoc pushTypeSpec(QualType T) { 74 size_t LocalSize = TypeSpecTypeLoc::LocalDataSize; 75 unsigned LocalAlign = TypeSpecTypeLoc::LocalDataAlignment; 76 return pushImpl(T, LocalSize, LocalAlign).castAs<TypeSpecTypeLoc>(); 77 } 78 79 /// Resets this builder to the newly-initialized state. clear()80 void clear() { 81 #ifndef NDEBUG 82 LastTy = QualType(); 83 #endif 84 Index = Capacity; 85 NumBytesAtAlign4 = 0; 86 AtAlign8 = false; 87 } 88 89 /// 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 TyLocType Loc = TypeLoc(T, nullptr).castAs<TyLocType>(); 101 size_t LocalSize = Loc.getLocalDataSize(); 102 unsigned LocalAlign = Loc.getLocalDataAlignment(); 103 return pushImpl(T, LocalSize, LocalAlign).castAs<TyLocType>(); 104 } 105 106 /// Creates a TypeSourceInfo for the given type. getTypeSourceInfo(ASTContext & Context,QualType T)107 TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) { 108 #ifndef NDEBUG 109 assert(T == LastTy && "type doesn't match last type pushed!"); 110 #endif 111 112 size_t FullDataSize = Capacity - Index; 113 TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize); 114 memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize); 115 return DI; 116 } 117 118 /// Copies the type-location information to the given AST context and 119 /// returns a \c TypeLoc referring into the AST context. getTypeLocInContext(ASTContext & Context,QualType T)120 TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) { 121 #ifndef NDEBUG 122 assert(T == LastTy && "type doesn't match last type pushed!"); 123 #endif 124 125 size_t FullDataSize = Capacity - Index; 126 void *Mem = Context.Allocate(FullDataSize); 127 memcpy(Mem, &Buffer[Index], FullDataSize); 128 return TypeLoc(T, Mem); 129 } 130 131 private: 132 133 TypeLoc pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment); 134 135 /// Grow to the given capacity. 136 void grow(size_t NewCapacity); 137 138 /// Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder 139 /// object. 140 /// 141 /// The resulting \c TypeLoc should only be used so long as the 142 /// \c TypeLocBuilder is active and has not had more type information 143 /// pushed into it. getTemporaryTypeLoc(QualType T)144 TypeLoc getTemporaryTypeLoc(QualType T) { 145 #ifndef NDEBUG 146 assert(LastTy == T && "type doesn't match last type pushed!"); 147 #endif 148 return TypeLoc(T, &Buffer[Index]); 149 } 150 }; 151 152 } 153 154 #endif 155