1//===--- TypeLocBuilder.h - Type Source Info collector ----------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9//  This file defines TypeLocBuilder, a class for building TypeLocs
10//  bottom-up.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_LIB_SEMA_TYPELOCBUILDER_H
15#define LLVM_CLANG_LIB_SEMA_TYPELOCBUILDER_H
16
17#include "clang/AST/ASTContext.h"
18#include "clang/AST/TypeLoc.h"
19
20namespace clang {
21
22class TypeLocBuilder {
23  enum { InlineCapacity = 8 * sizeof(SourceLocation) };
24
25  /// The underlying location-data buffer.  Data grows from the end
26  /// of the buffer backwards.
27  char *Buffer;
28
29  /// The capacity of the current buffer.
30  size_t Capacity;
31
32  /// The index of the first occupied byte in the buffer.
33  size_t Index;
34
35#ifndef NDEBUG
36  /// The last type pushed on this builder.
37  QualType LastTy;
38#endif
39
40  /// The inline buffer.
41  enum { BufferMaxAlignment = alignof(void *) };
42  alignas(BufferMaxAlignment) char InlineBuffer[InlineCapacity];
43  unsigned NumBytesAtAlign4;
44  bool AtAlign8;
45
46public:
47  TypeLocBuilder()
48      : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity),
49        NumBytesAtAlign4(0), AtAlign8(false) {}
50
51  ~TypeLocBuilder() {
52    if (Buffer != InlineBuffer)
53      delete[] Buffer;
54  }
55
56  TypeLocBuilder(const TypeLocBuilder &) = delete;
57  TypeLocBuilder &operator=(const TypeLocBuilder &) = delete;
58
59  /// Ensures that this buffer has at least as much capacity as described.
60  void reserve(size_t Requested) {
61    if (Requested > Capacity)
62      // For now, match the request exactly.
63      grow(Requested);
64  }
65
66  /// Pushes a copy of the given TypeLoc onto this builder.  The builder
67  /// must be empty for this to work.
68  void pushFullCopy(TypeLoc L);
69
70  /// Pushes 'T' with all locations pointing to 'Loc'.
71  /// The builder must be empty for this to work.
72  void pushTrivial(ASTContext &Context, QualType T, SourceLocation Loc);
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    unsigned LocalAlign = TypeSpecTypeLoc::LocalDataAlignment;
79    return pushImpl(T, LocalSize, LocalAlign).castAs<TypeSpecTypeLoc>();
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    NumBytesAtAlign4 = 0;
89    AtAlign8 = false;
90  }
91
92  /// Tell the TypeLocBuilder that the type it is storing has been
93  /// modified in some safe way that doesn't affect type-location information.
94  void TypeWasModifiedSafely(QualType T) {
95#ifndef NDEBUG
96    LastTy = T;
97#endif
98  }
99
100  /// Pushes space for a new TypeLoc of the given type.  Invalidates
101  /// any TypeLocs previously retrieved from this builder.
102  template <class TyLocType> TyLocType push(QualType T) {
103    TyLocType Loc = TypeLoc(T, nullptr).castAs<TyLocType>();
104    size_t LocalSize = Loc.getLocalDataSize();
105    unsigned LocalAlign = Loc.getLocalDataAlignment();
106    return pushImpl(T, LocalSize, LocalAlign).castAs<TyLocType>();
107  }
108
109  /// Creates a TypeSourceInfo for the given type.
110  TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) {
111#ifndef NDEBUG
112    assert(T == LastTy && "type doesn't match last type pushed!");
113#endif
114
115    size_t FullDataSize = Capacity - Index;
116    TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize);
117    memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
118    return DI;
119  }
120
121  /// Copies the type-location information to the given AST context and
122  /// returns a \c TypeLoc referring into the AST context.
123  TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) {
124#ifndef NDEBUG
125    assert(T == LastTy && "type doesn't match last type pushed!");
126#endif
127
128    size_t FullDataSize = Capacity - Index;
129    void *Mem = Context.Allocate(FullDataSize);
130    memcpy(Mem, &Buffer[Index], FullDataSize);
131    return TypeLoc(T, Mem);
132  }
133
134private:
135
136  TypeLoc pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment);
137
138  /// Grow to the given capacity.
139  void grow(size_t NewCapacity);
140
141  /// Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder
142  /// object.
143  ///
144  /// The resulting \c TypeLoc should only be used so long as the
145  /// \c TypeLocBuilder is active and has not had more type information
146  /// pushed into it.
147  TypeLoc getTemporaryTypeLoc(QualType T) {
148#ifndef NDEBUG
149    assert(LastTy == T && "type doesn't match last type pushed!");
150#endif
151    return TypeLoc(T, &Buffer[Index]);
152  }
153};
154
155}
156
157#endif
158