TypeLocBuilder.h revision 224145
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/TypeLoc.h"
19#include "clang/AST/ASTContext.h"
20
21namespace clang {
22
23class 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 cast<TypeSpecTypeLoc>(pushImpl(T, LocalSize));
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 = cast<TyLocType>(TypeLoc(T, 0)).getLocalDataSize();
101    return cast<TyLocType>(pushImpl(T, LocalSize));
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
129private:
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
184public:
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