Home | History | Annotate | Line # | Download | only in Sema
      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, NumBytesAtAlign8;
     44 
     45 public:
     46   TypeLocBuilder()
     47       : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity),
     48         NumBytesAtAlign4(0), NumBytesAtAlign8(0) {}
     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 
     66   /// Pushes space for a typespec TypeLoc.  Invalidates any TypeLocs
     67   /// previously retrieved from this builder.
     68   TypeSpecTypeLoc pushTypeSpec(QualType T) {
     69     size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
     70     unsigned LocalAlign = TypeSpecTypeLoc::LocalDataAlignment;
     71     return pushImpl(T, LocalSize, LocalAlign).castAs<TypeSpecTypeLoc>();
     72   }
     73 
     74   /// Resets this builder to the newly-initialized state.
     75   void clear() {
     76 #ifndef NDEBUG
     77     LastTy = QualType();
     78 #endif
     79     Index = Capacity;
     80     NumBytesAtAlign4 = NumBytesAtAlign8 = 0;
     81   }
     82 
     83   /// Tell the TypeLocBuilder that the type it is storing has been
     84   /// modified in some safe way that doesn't affect type-location information.
     85   void TypeWasModifiedSafely(QualType T) {
     86 #ifndef NDEBUG
     87     LastTy = T;
     88 #endif
     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     TyLocType Loc = TypeLoc(T, nullptr).castAs<TyLocType>();
     95     size_t LocalSize = Loc.getLocalDataSize();
     96     unsigned LocalAlign = Loc.getLocalDataAlignment();
     97     return pushImpl(T, LocalSize, LocalAlign).castAs<TyLocType>();
     98   }
     99 
    100   /// Creates a TypeSourceInfo for the given type.
    101   TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) {
    102 #ifndef NDEBUG
    103     assert(T == LastTy && "type doesn't match last type pushed!");
    104 #endif
    105 
    106     size_t FullDataSize = Capacity - Index;
    107     TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize);
    108     memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
    109     return DI;
    110   }
    111 
    112   /// Copies the type-location information to the given AST context and
    113   /// returns a \c TypeLoc referring into the AST context.
    114   TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) {
    115 #ifndef NDEBUG
    116     assert(T == LastTy && "type doesn't match last type pushed!");
    117 #endif
    118 
    119     size_t FullDataSize = Capacity - Index;
    120     void *Mem = Context.Allocate(FullDataSize);
    121     memcpy(Mem, &Buffer[Index], FullDataSize);
    122     return TypeLoc(T, Mem);
    123   }
    124 
    125 private:
    126 
    127   TypeLoc pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment);
    128 
    129   /// Grow to the given capacity.
    130   void grow(size_t NewCapacity);
    131 
    132   /// Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder
    133   /// object.
    134   ///
    135   /// The resulting \c TypeLoc should only be used so long as the
    136   /// \c TypeLocBuilder is active and has not had more type information
    137   /// pushed into it.
    138   TypeLoc getTemporaryTypeLoc(QualType T) {
    139 #ifndef NDEBUG
    140     assert(LastTy == T && "type doesn't match last type pushed!");
    141 #endif
    142     return TypeLoc(T, &Buffer[Index]);
    143   }
    144 };
    145 
    146 }
    147 
    148 #endif
    149