TypeLocBuilder.h revision 249423
1218887Sdim//===--- TypeLocBuilder.h - Type Source Info collector ----------*- C++ -*-===//
2218887Sdim//
3218887Sdim//                     The LLVM Compiler Infrastructure
4218887Sdim//
5218887Sdim// This file is distributed under the University of Illinois Open Source
6218887Sdim// License. See LICENSE.TXT for details.
7218887Sdim//
8218887Sdim//===----------------------------------------------------------------------===//
9218887Sdim//
10218887Sdim//  This files defines TypeLocBuilder, a class for building TypeLocs
11218887Sdim//  bottom-up.
12218887Sdim//
13218887Sdim//===----------------------------------------------------------------------===//
14218887Sdim
15218887Sdim#ifndef LLVM_CLANG_SEMA_TYPELOCBUILDER_H
16218887Sdim#define LLVM_CLANG_SEMA_TYPELOCBUILDER_H
17218887Sdim
18249423Sdim#include "clang/AST/ASTContext.h"
19218887Sdim#include "clang/AST/TypeLoc.h"
20218887Sdim
21218887Sdimnamespace clang {
22218887Sdim
23218887Sdimclass TypeLocBuilder {
24218887Sdim  enum { InlineCapacity = 8 * sizeof(SourceLocation) };
25218887Sdim
26218887Sdim  /// The underlying location-data buffer.  Data grows from the end
27218887Sdim  /// of the buffer backwards.
28218887Sdim  char *Buffer;
29218887Sdim
30218887Sdim  /// The capacity of the current buffer.
31218887Sdim  size_t Capacity;
32218887Sdim
33218887Sdim  /// The index of the first occupied byte in the buffer.
34218887Sdim  size_t Index;
35218887Sdim
36218887Sdim#ifndef NDEBUG
37218887Sdim  /// The last type pushed on this builder.
38218887Sdim  QualType LastTy;
39218887Sdim#endif
40218887Sdim
41218887Sdim  /// The inline buffer.
42218887Sdim  char InlineBuffer[InlineCapacity];
43218887Sdim
44218887Sdim public:
45218887Sdim  TypeLocBuilder()
46221345Sdim    : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) {}
47218887Sdim
48218887Sdim  ~TypeLocBuilder() {
49218887Sdim    if (Buffer != InlineBuffer)
50218887Sdim      delete[] Buffer;
51218887Sdim  }
52218887Sdim
53218887Sdim  /// Ensures that this buffer has at least as much capacity as described.
54218887Sdim  void reserve(size_t Requested) {
55218887Sdim    if (Requested > Capacity)
56218887Sdim      // For now, match the request exactly.
57218887Sdim      grow(Requested);
58218887Sdim  }
59218887Sdim
60218887Sdim  /// Pushes a copy of the given TypeLoc onto this builder.  The builder
61218887Sdim  /// must be empty for this to work.
62218887Sdim  void pushFullCopy(TypeLoc L) {
63218887Sdim    size_t Size = L.getFullDataSize();
64218887Sdim    TypeLoc Copy = pushFullUninitializedImpl(L.getType(), Size);
65218887Sdim    memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size);
66218887Sdim  }
67218887Sdim
68218887Sdim  /// Pushes uninitialized space for the given type.  The builder must
69218887Sdim  /// be empty.
70218887Sdim  TypeLoc pushFullUninitialized(QualType T) {
71218887Sdim    return pushFullUninitializedImpl(T, TypeLoc::getFullDataSizeForType(T));
72218887Sdim  }
73218887Sdim
74218887Sdim  /// Pushes space for a typespec TypeLoc.  Invalidates any TypeLocs
75218887Sdim  /// previously retrieved from this builder.
76218887Sdim  TypeSpecTypeLoc pushTypeSpec(QualType T) {
77218887Sdim    size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
78249423Sdim    return pushImpl(T, LocalSize).castAs<TypeSpecTypeLoc>();
79218887Sdim  }
80218887Sdim
81218887Sdim  /// Resets this builder to the newly-initialized state.
82218887Sdim  void clear() {
83218887Sdim#ifndef NDEBUG
84218887Sdim    LastTy = QualType();
85218887Sdim#endif
86218887Sdim    Index = Capacity;
87218887Sdim  }
88218887Sdim
89224145Sdim  /// \brief Tell the TypeLocBuilder that the type it is storing has been
90224145Sdim  /// modified in some safe way that doesn't affect type-location information.
91224145Sdim  void TypeWasModifiedSafely(QualType T) {
92224145Sdim#ifndef NDEBUG
93224145Sdim    LastTy = T;
94224145Sdim#endif
95224145Sdim  }
96224145Sdim
97218887Sdim  /// Pushes space for a new TypeLoc of the given type.  Invalidates
98218887Sdim  /// any TypeLocs previously retrieved from this builder.
99218887Sdim  template <class TyLocType> TyLocType push(QualType T) {
100249423Sdim    size_t LocalSize = TypeLoc(T, 0).castAs<TyLocType>().getLocalDataSize();
101249423Sdim    return pushImpl(T, LocalSize).castAs<TyLocType>();
102218887Sdim  }
103218887Sdim
104218887Sdim  /// Creates a TypeSourceInfo for the given type.
105218887Sdim  TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) {
106218887Sdim#ifndef NDEBUG
107218887Sdim    assert(T == LastTy && "type doesn't match last type pushed!");
108218887Sdim#endif
109218887Sdim
110218887Sdim    size_t FullDataSize = Capacity - Index;
111218887Sdim    TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize);
112218887Sdim    memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
113218887Sdim    return DI;
114218887Sdim  }
115218887Sdim
116219077Sdim  /// \brief Copies the type-location information to the given AST context and
117219077Sdim  /// returns a \c TypeLoc referring into the AST context.
118219077Sdim  TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) {
119219077Sdim#ifndef NDEBUG
120219077Sdim    assert(T == LastTy && "type doesn't match last type pushed!");
121219077Sdim#endif
122219077Sdim
123219077Sdim    size_t FullDataSize = Capacity - Index;
124219077Sdim    void *Mem = Context.Allocate(FullDataSize);
125219077Sdim    memcpy(Mem, &Buffer[Index], FullDataSize);
126219077Sdim    return TypeLoc(T, Mem);
127219077Sdim  }
128219077Sdim
129218887Sdimprivate:
130218887Sdim  TypeLoc pushImpl(QualType T, size_t LocalSize) {
131218887Sdim#ifndef NDEBUG
132218887Sdim    QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
133218887Sdim    assert(TLast == LastTy &&
134218887Sdim           "mismatch between last type and new type's inner type");
135218887Sdim    LastTy = T;
136218887Sdim#endif
137218887Sdim
138218887Sdim    // If we need to grow, grow by a factor of 2.
139218887Sdim    if (LocalSize > Index) {
140218887Sdim      size_t RequiredCapacity = Capacity + (LocalSize - Index);
141218887Sdim      size_t NewCapacity = Capacity * 2;
142218887Sdim      while (RequiredCapacity > NewCapacity)
143218887Sdim        NewCapacity *= 2;
144218887Sdim      grow(NewCapacity);
145218887Sdim    }
146218887Sdim
147218887Sdim    Index -= LocalSize;
148218887Sdim
149224145Sdim    return getTemporaryTypeLoc(T);
150218887Sdim  }
151218887Sdim
152218887Sdim  /// Grow to the given capacity.
153218887Sdim  void grow(size_t NewCapacity) {
154218887Sdim    assert(NewCapacity > Capacity);
155218887Sdim
156218887Sdim    // Allocate the new buffer and copy the old data into it.
157218887Sdim    char *NewBuffer = new char[NewCapacity];
158218887Sdim    unsigned NewIndex = Index + NewCapacity - Capacity;
159218887Sdim    memcpy(&NewBuffer[NewIndex],
160218887Sdim           &Buffer[Index],
161218887Sdim           Capacity - Index);
162218887Sdim
163218887Sdim    if (Buffer != InlineBuffer)
164218887Sdim      delete[] Buffer;
165218887Sdim
166218887Sdim    Buffer = NewBuffer;
167218887Sdim    Capacity = NewCapacity;
168218887Sdim    Index = NewIndex;
169218887Sdim  }
170218887Sdim
171218887Sdim  TypeLoc pushFullUninitializedImpl(QualType T, size_t Size) {
172218887Sdim#ifndef NDEBUG
173218887Sdim    assert(LastTy.isNull() && "pushing full on non-empty TypeLocBuilder");
174218887Sdim    LastTy = T;
175218887Sdim#endif
176218887Sdim    assert(Index == Capacity && "pushing full on non-empty TypeLocBuilder");
177218887Sdim
178218887Sdim    reserve(Size);
179218887Sdim    Index -= Size;
180218887Sdim
181224145Sdim    return getTemporaryTypeLoc(T);
182218887Sdim  }
183218887Sdim
184224145Sdimpublic:
185224145Sdim  /// \brief Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder
186224145Sdim  /// object.
187224145Sdim  ///
188224145Sdim  /// The resulting \c TypeLoc should only be used so long as the
189224145Sdim  /// \c TypeLocBuilder is active and has not had more type information
190224145Sdim  /// pushed into it.
191224145Sdim  TypeLoc getTemporaryTypeLoc(QualType T) {
192218887Sdim#ifndef NDEBUG
193218887Sdim    assert(LastTy == T && "type doesn't match last type pushed!");
194218887Sdim#endif
195218887Sdim    return TypeLoc(T, &Buffer[Index]);
196218887Sdim  }
197218887Sdim};
198218887Sdim
199218887Sdim}
200218887Sdim
201218887Sdim#endif
202