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.
42263508Sdim  enum { BufferMaxAlignment = llvm::AlignOf<void*>::Alignment };
43263508Sdim  llvm::AlignedCharArray<BufferMaxAlignment, InlineCapacity> InlineBuffer;
44263508Sdim  unsigned NumBytesAtAlign4, NumBytesAtAlign8;
45218887Sdim
46218887Sdim public:
47218887Sdim  TypeLocBuilder()
48263508Sdim    : Buffer(InlineBuffer.buffer), Capacity(InlineCapacity),
49263508Sdim      Index(InlineCapacity), NumBytesAtAlign4(0), NumBytesAtAlign8(0)
50263508Sdim  {
51263508Sdim  }
52218887Sdim
53218887Sdim  ~TypeLocBuilder() {
54263508Sdim    if (Buffer != InlineBuffer.buffer)
55218887Sdim      delete[] Buffer;
56218887Sdim  }
57218887Sdim
58218887Sdim  /// Ensures that this buffer has at least as much capacity as described.
59218887Sdim  void reserve(size_t Requested) {
60218887Sdim    if (Requested > Capacity)
61218887Sdim      // For now, match the request exactly.
62218887Sdim      grow(Requested);
63218887Sdim  }
64218887Sdim
65218887Sdim  /// Pushes a copy of the given TypeLoc onto this builder.  The builder
66218887Sdim  /// must be empty for this to work.
67263508Sdim  void pushFullCopy(TypeLoc L);
68218887Sdim
69218887Sdim  /// Pushes space for a typespec TypeLoc.  Invalidates any TypeLocs
70218887Sdim  /// previously retrieved from this builder.
71218887Sdim  TypeSpecTypeLoc pushTypeSpec(QualType T) {
72218887Sdim    size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
73263508Sdim    unsigned LocalAlign = TypeSpecTypeLoc::LocalDataAlignment;
74263508Sdim    return pushImpl(T, LocalSize, LocalAlign).castAs<TypeSpecTypeLoc>();
75218887Sdim  }
76218887Sdim
77218887Sdim  /// Resets this builder to the newly-initialized state.
78218887Sdim  void clear() {
79218887Sdim#ifndef NDEBUG
80218887Sdim    LastTy = QualType();
81218887Sdim#endif
82218887Sdim    Index = Capacity;
83263508Sdim    NumBytesAtAlign4 = NumBytesAtAlign8 = 0;
84218887Sdim  }
85218887Sdim
86224145Sdim  /// \brief Tell the TypeLocBuilder that the type it is storing has been
87224145Sdim  /// modified in some safe way that doesn't affect type-location information.
88224145Sdim  void TypeWasModifiedSafely(QualType T) {
89224145Sdim#ifndef NDEBUG
90224145Sdim    LastTy = T;
91224145Sdim#endif
92224145Sdim  }
93224145Sdim
94218887Sdim  /// Pushes space for a new TypeLoc of the given type.  Invalidates
95218887Sdim  /// any TypeLocs previously retrieved from this builder.
96218887Sdim  template <class TyLocType> TyLocType push(QualType T) {
97263508Sdim    TyLocType Loc = TypeLoc(T, 0).castAs<TyLocType>();
98263508Sdim    size_t LocalSize = Loc.getLocalDataSize();
99263508Sdim    unsigned LocalAlign = Loc.getLocalDataAlignment();
100263508Sdim    return pushImpl(T, LocalSize, LocalAlign).castAs<TyLocType>();
101218887Sdim  }
102218887Sdim
103218887Sdim  /// Creates a TypeSourceInfo for the given type.
104218887Sdim  TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) {
105218887Sdim#ifndef NDEBUG
106218887Sdim    assert(T == LastTy && "type doesn't match last type pushed!");
107218887Sdim#endif
108218887Sdim
109218887Sdim    size_t FullDataSize = Capacity - Index;
110218887Sdim    TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize);
111218887Sdim    memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
112218887Sdim    return DI;
113218887Sdim  }
114218887Sdim
115219077Sdim  /// \brief Copies the type-location information to the given AST context and
116219077Sdim  /// returns a \c TypeLoc referring into the AST context.
117219077Sdim  TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) {
118219077Sdim#ifndef NDEBUG
119219077Sdim    assert(T == LastTy && "type doesn't match last type pushed!");
120219077Sdim#endif
121219077Sdim
122219077Sdim    size_t FullDataSize = Capacity - Index;
123219077Sdim    void *Mem = Context.Allocate(FullDataSize);
124219077Sdim    memcpy(Mem, &Buffer[Index], FullDataSize);
125219077Sdim    return TypeLoc(T, Mem);
126219077Sdim  }
127219077Sdim
128218887Sdimprivate:
129218887Sdim
130263508Sdim  TypeLoc pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment);
131218887Sdim
132218887Sdim  /// Grow to the given capacity.
133263508Sdim  void grow(size_t NewCapacity);
134218887Sdim
135224145Sdim  /// \brief Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder
136224145Sdim  /// object.
137224145Sdim  ///
138224145Sdim  /// The resulting \c TypeLoc should only be used so long as the
139224145Sdim  /// \c TypeLocBuilder is active and has not had more type information
140224145Sdim  /// pushed into it.
141224145Sdim  TypeLoc getTemporaryTypeLoc(QualType T) {
142218887Sdim#ifndef NDEBUG
143218887Sdim    assert(LastTy == T && "type doesn't match last type pushed!");
144218887Sdim#endif
145218887Sdim    return TypeLoc(T, &Buffer[Index]);
146218887Sdim  }
147218887Sdim};
148218887Sdim
149218887Sdim}
150218887Sdim
151218887Sdim#endif
152