TypeLocBuilder.h revision 221345
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 "llvm/ADT/SmallVector.h"
20#include "clang/AST/ASTContext.h"
21
22namespace clang {
23
24class TypeLocBuilder {
25  enum { InlineCapacity = 8 * sizeof(SourceLocation) };
26
27  /// The underlying location-data buffer.  Data grows from the end
28  /// of the buffer backwards.
29  char *Buffer;
30
31  /// The capacity of the current buffer.
32  size_t Capacity;
33
34  /// The index of the first occupied byte in the buffer.
35  size_t Index;
36
37#ifndef NDEBUG
38  /// The last type pushed on this builder.
39  QualType LastTy;
40#endif
41
42  /// The inline buffer.
43  char InlineBuffer[InlineCapacity];
44
45 public:
46  TypeLocBuilder()
47    : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) {}
48
49  ~TypeLocBuilder() {
50    if (Buffer != InlineBuffer)
51      delete[] Buffer;
52  }
53
54  /// Ensures that this buffer has at least as much capacity as described.
55  void reserve(size_t Requested) {
56    if (Requested > Capacity)
57      // For now, match the request exactly.
58      grow(Requested);
59  }
60
61  /// Pushes a copy of the given TypeLoc onto this builder.  The builder
62  /// must be empty for this to work.
63  void pushFullCopy(TypeLoc L) {
64    size_t Size = L.getFullDataSize();
65    TypeLoc Copy = pushFullUninitializedImpl(L.getType(), Size);
66    memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size);
67  }
68
69  /// Pushes uninitialized space for the given type.  The builder must
70  /// be empty.
71  TypeLoc pushFullUninitialized(QualType T) {
72    return pushFullUninitializedImpl(T, TypeLoc::getFullDataSizeForType(T));
73  }
74
75  /// Pushes space for a typespec TypeLoc.  Invalidates any TypeLocs
76  /// previously retrieved from this builder.
77  TypeSpecTypeLoc pushTypeSpec(QualType T) {
78    size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
79    return cast<TypeSpecTypeLoc>(pushImpl(T, LocalSize));
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  }
89
90  /// Pushes space for a new TypeLoc of the given type.  Invalidates
91  /// any TypeLocs previously retrieved from this builder.
92  template <class TyLocType> TyLocType push(QualType T) {
93    size_t LocalSize = cast<TyLocType>(TypeLoc(T, 0)).getLocalDataSize();
94    return cast<TyLocType>(pushImpl(T, LocalSize));
95  }
96
97  /// Creates a TypeSourceInfo for the given type.
98  TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) {
99#ifndef NDEBUG
100    assert(T == LastTy && "type doesn't match last type pushed!");
101#endif
102
103    size_t FullDataSize = Capacity - Index;
104    TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize);
105    memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
106    return DI;
107  }
108
109  /// \brief Copies the type-location information to the given AST context and
110  /// returns a \c TypeLoc referring into the AST context.
111  TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) {
112#ifndef NDEBUG
113    assert(T == LastTy && "type doesn't match last type pushed!");
114#endif
115
116    size_t FullDataSize = Capacity - Index;
117    void *Mem = Context.Allocate(FullDataSize);
118    memcpy(Mem, &Buffer[Index], FullDataSize);
119    return TypeLoc(T, Mem);
120  }
121
122private:
123  TypeLoc pushImpl(QualType T, size_t LocalSize) {
124#ifndef NDEBUG
125    QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
126    assert(TLast == LastTy &&
127           "mismatch between last type and new type's inner type");
128    LastTy = T;
129#endif
130
131    // If we need to grow, grow by a factor of 2.
132    if (LocalSize > Index) {
133      size_t RequiredCapacity = Capacity + (LocalSize - Index);
134      size_t NewCapacity = Capacity * 2;
135      while (RequiredCapacity > NewCapacity)
136        NewCapacity *= 2;
137      grow(NewCapacity);
138    }
139
140    Index -= LocalSize;
141
142    return getTypeLoc(T);
143  }
144
145  /// Grow to the given capacity.
146  void grow(size_t NewCapacity) {
147    assert(NewCapacity > Capacity);
148
149    // Allocate the new buffer and copy the old data into it.
150    char *NewBuffer = new char[NewCapacity];
151    unsigned NewIndex = Index + NewCapacity - Capacity;
152    memcpy(&NewBuffer[NewIndex],
153           &Buffer[Index],
154           Capacity - Index);
155
156    if (Buffer != InlineBuffer)
157      delete[] Buffer;
158
159    Buffer = NewBuffer;
160    Capacity = NewCapacity;
161    Index = NewIndex;
162  }
163
164  TypeLoc pushFullUninitializedImpl(QualType T, size_t Size) {
165#ifndef NDEBUG
166    assert(LastTy.isNull() && "pushing full on non-empty TypeLocBuilder");
167    LastTy = T;
168#endif
169    assert(Index == Capacity && "pushing full on non-empty TypeLocBuilder");
170
171    reserve(Size);
172    Index -= Size;
173
174    return getTypeLoc(T);
175  }
176
177
178  // This is private because, when we kill off TypeSourceInfo in favor
179  // of TypeLoc, we'll want an interface that creates a TypeLoc given
180  // an ASTContext, and we don't want people to think they can just
181  // use this as an equivalent.
182  TypeLoc getTypeLoc(QualType T) {
183#ifndef NDEBUG
184    assert(LastTy == T && "type doesn't match last type pushed!");
185#endif
186    return TypeLoc(T, &Buffer[Index]);
187  }
188};
189
190}
191
192#endif
193