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 20namespace clang { 21 22class 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 46public: 47 TypeLocBuilder() 48 : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity), 49 NumBytesAtAlign4(0), AtAlign8(false) {} 50 51 ~TypeLocBuilder() { 52 if (Buffer != InlineBuffer) 53 delete[] Buffer; 54 } 55 56 TypeLocBuilder(const TypeLocBuilder &) = delete; 57 TypeLocBuilder &operator=(const TypeLocBuilder &) = delete; 58 59 /// Ensures that this buffer has at least as much capacity as described. 60 void reserve(size_t Requested) { 61 if (Requested > Capacity) 62 // For now, match the request exactly. 63 grow(Requested); 64 } 65 66 /// Pushes a copy of the given TypeLoc onto this builder. The builder 67 /// must be empty for this to work. 68 void pushFullCopy(TypeLoc L); 69 70 /// Pushes 'T' with all locations pointing to 'Loc'. 71 /// The builder must be empty for this to work. 72 void pushTrivial(ASTContext &Context, QualType T, SourceLocation Loc); 73 74 /// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs 75 /// previously retrieved from this builder. 76 TypeSpecTypeLoc pushTypeSpec(QualType T) { 77 size_t LocalSize = TypeSpecTypeLoc::LocalDataSize; 78 unsigned LocalAlign = TypeSpecTypeLoc::LocalDataAlignment; 79 return pushImpl(T, LocalSize, LocalAlign).castAs<TypeSpecTypeLoc>(); 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 NumBytesAtAlign4 = 0; 89 AtAlign8 = false; 90 } 91 92 /// Tell the TypeLocBuilder that the type it is storing has been 93 /// modified in some safe way that doesn't affect type-location information. 94 void TypeWasModifiedSafely(QualType T) { 95#ifndef NDEBUG 96 LastTy = T; 97#endif 98 } 99 100 /// Pushes space for a new TypeLoc of the given type. Invalidates 101 /// any TypeLocs previously retrieved from this builder. 102 template <class TyLocType> TyLocType push(QualType T) { 103 TyLocType Loc = TypeLoc(T, nullptr).castAs<TyLocType>(); 104 size_t LocalSize = Loc.getLocalDataSize(); 105 unsigned LocalAlign = Loc.getLocalDataAlignment(); 106 return pushImpl(T, LocalSize, LocalAlign).castAs<TyLocType>(); 107 } 108 109 /// Creates a TypeSourceInfo for the given type. 110 TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) { 111#ifndef NDEBUG 112 assert(T == LastTy && "type doesn't match last type pushed!"); 113#endif 114 115 size_t FullDataSize = Capacity - Index; 116 TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize); 117 memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize); 118 return DI; 119 } 120 121 /// Copies the type-location information to the given AST context and 122 /// returns a \c TypeLoc referring into the AST context. 123 TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) { 124#ifndef NDEBUG 125 assert(T == LastTy && "type doesn't match last type pushed!"); 126#endif 127 128 size_t FullDataSize = Capacity - Index; 129 void *Mem = Context.Allocate(FullDataSize); 130 memcpy(Mem, &Buffer[Index], FullDataSize); 131 return TypeLoc(T, Mem); 132 } 133 134private: 135 136 TypeLoc pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment); 137 138 /// Grow to the given capacity. 139 void grow(size_t NewCapacity); 140 141 /// Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder 142 /// object. 143 /// 144 /// The resulting \c TypeLoc should only be used so long as the 145 /// \c TypeLocBuilder is active and has not had more type information 146 /// pushed into it. 147 TypeLoc getTemporaryTypeLoc(QualType T) { 148#ifndef NDEBUG 149 assert(LastTy == T && "type doesn't match last type pushed!"); 150#endif 151 return TypeLoc(T, &Buffer[Index]); 152 } 153}; 154 155} 156 157#endif 158