Home | History | Annotate | Download | only in Sema
      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/ASTContext.h"
     19 #include "clang/AST/TypeLoc.h"
     20 
     21 namespace clang {
     22 
     23 class TypeLocBuilder {
     24   enum { InlineCapacity = 8 * sizeof(SourceLocation) };
     25 
     26   /// The underlying location-data buffer.  Data grows from the end
     27   /// of the buffer backwards.
     28   char *Buffer;
     29 
     30   /// The capacity of the current buffer.
     31   size_t Capacity;
     32 
     33   /// The index of the first occupied byte in the buffer.
     34   size_t Index;
     35 
     36 #ifndef NDEBUG
     37   /// The last type pushed on this builder.
     38   QualType LastTy;
     39 #endif
     40 
     41   /// The inline buffer.
     42   char InlineBuffer[InlineCapacity];
     43 
     44  public:
     45   TypeLocBuilder()
     46     : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) {}
     47 
     48   ~TypeLocBuilder() {
     49     if (Buffer != InlineBuffer)
     50       delete[] Buffer;
     51   }
     52 
     53   /// Ensures that this buffer has at least as much capacity as described.
     54   void reserve(size_t Requested) {
     55     if (Requested > Capacity)
     56       // For now, match the request exactly.
     57       grow(Requested);
     58   }
     59 
     60   /// Pushes a copy of the given TypeLoc onto this builder.  The builder
     61   /// must be empty for this to work.
     62   void pushFullCopy(TypeLoc L) {
     63     size_t Size = L.getFullDataSize();
     64     TypeLoc Copy = pushFullUninitializedImpl(L.getType(), Size);
     65     memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size);
     66   }
     67 
     68   /// Pushes uninitialized space for the given type.  The builder must
     69   /// be empty.
     70   TypeLoc pushFullUninitialized(QualType T) {
     71     return pushFullUninitializedImpl(T, TypeLoc::getFullDataSizeForType(T));
     72   }
     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     return pushImpl(T, LocalSize).castAs<TypeSpecTypeLoc>();
     79   }
     80 
     81   /// Resets this builder to the newly-initialized state.
     82   void clear() {
     83 #ifndef NDEBUG
     84     LastTy = QualType();
     85 #endif
     86     Index = Capacity;
     87   }
     88 
     89   /// \brief Tell the TypeLocBuilder that the type it is storing has been
     90   /// modified in some safe way that doesn't affect type-location information.
     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.
     99   template <class TyLocType> TyLocType push(QualType T) {
    100     size_t LocalSize = TypeLoc(T, 0).castAs<TyLocType>().getLocalDataSize();
    101     return pushImpl(T, LocalSize).castAs<TyLocType>();
    102   }
    103 
    104   /// Creates a TypeSourceInfo for the given type.
    105   TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) {
    106 #ifndef NDEBUG
    107     assert(T == LastTy && "type doesn't match last type pushed!");
    108 #endif
    109 
    110     size_t FullDataSize = Capacity - Index;
    111     TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize);
    112     memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
    113     return DI;
    114   }
    115 
    116   /// \brief Copies the type-location information to the given AST context and
    117   /// returns a \c TypeLoc referring into the AST context.
    118   TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) {
    119 #ifndef NDEBUG
    120     assert(T == LastTy && "type doesn't match last type pushed!");
    121 #endif
    122 
    123     size_t FullDataSize = Capacity - Index;
    124     void *Mem = Context.Allocate(FullDataSize);
    125     memcpy(Mem, &Buffer[Index], FullDataSize);
    126     return TypeLoc(T, Mem);
    127   }
    128 
    129 private:
    130   TypeLoc pushImpl(QualType T, size_t LocalSize) {
    131 #ifndef NDEBUG
    132     QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
    133     assert(TLast == LastTy &&
    134            "mismatch between last type and new type's inner type");
    135     LastTy = T;
    136 #endif
    137 
    138     // If we need to grow, grow by a factor of 2.
    139     if (LocalSize > Index) {
    140       size_t RequiredCapacity = Capacity + (LocalSize - Index);
    141       size_t NewCapacity = Capacity * 2;
    142       while (RequiredCapacity > NewCapacity)
    143         NewCapacity *= 2;
    144       grow(NewCapacity);
    145     }
    146 
    147     Index -= LocalSize;
    148 
    149     return getTemporaryTypeLoc(T);
    150   }
    151 
    152   /// Grow to the given capacity.
    153   void grow(size_t NewCapacity) {
    154     assert(NewCapacity > Capacity);
    155 
    156     // Allocate the new buffer and copy the old data into it.
    157     char *NewBuffer = new char[NewCapacity];
    158     unsigned NewIndex = Index + NewCapacity - Capacity;
    159     memcpy(&NewBuffer[NewIndex],
    160            &Buffer[Index],
    161            Capacity - Index);
    162 
    163     if (Buffer != InlineBuffer)
    164       delete[] Buffer;
    165 
    166     Buffer = NewBuffer;
    167     Capacity = NewCapacity;
    168     Index = NewIndex;
    169   }
    170 
    171   TypeLoc pushFullUninitializedImpl(QualType T, size_t Size) {
    172 #ifndef NDEBUG
    173     assert(LastTy.isNull() && "pushing full on non-empty TypeLocBuilder");
    174     LastTy = T;
    175 #endif
    176     assert(Index == Capacity && "pushing full on non-empty TypeLocBuilder");
    177 
    178     reserve(Size);
    179     Index -= Size;
    180 
    181     return getTemporaryTypeLoc(T);
    182   }
    183 
    184 public:
    185   /// \brief Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder
    186   /// object.
    187   ///
    188   /// The resulting \c TypeLoc should only be used so long as the
    189   /// \c TypeLocBuilder is active and has not had more type information
    190   /// pushed into it.
    191   TypeLoc getTemporaryTypeLoc(QualType T) {
    192 #ifndef NDEBUG
    193     assert(LastTy == T && "type doesn't match last type pushed!");
    194 #endif
    195     return TypeLoc(T, &Buffer[Index]);
    196   }
    197 };
    198 
    199 }
    200 
    201 #endif
    202