TypeLocBuilder.h revision 353358
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  llvm::AlignedCharArray<BufferMaxAlignment, InlineCapacity> InlineBuffer;
43  unsigned NumBytesAtAlign4, NumBytesAtAlign8;
44
45 public:
46  TypeLocBuilder()
47    : Buffer(InlineBuffer.buffer), Capacity(InlineCapacity),
48      Index(InlineCapacity), NumBytesAtAlign4(0), NumBytesAtAlign8(0)
49  {
50  }
51
52  ~TypeLocBuilder() {
53    if (Buffer != InlineBuffer.buffer)
54      delete[] Buffer;
55  }
56
57  /// Ensures that this buffer has at least as much capacity as described.
58  void reserve(size_t Requested) {
59    if (Requested > Capacity)
60      // For now, match the request exactly.
61      grow(Requested);
62  }
63
64  /// Pushes a copy of the given TypeLoc onto this builder.  The builder
65  /// must be empty for this to work.
66  void pushFullCopy(TypeLoc L);
67
68  /// Pushes space for a typespec TypeLoc.  Invalidates any TypeLocs
69  /// previously retrieved from this builder.
70  TypeSpecTypeLoc pushTypeSpec(QualType T) {
71    size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
72    unsigned LocalAlign = TypeSpecTypeLoc::LocalDataAlignment;
73    return pushImpl(T, LocalSize, LocalAlign).castAs<TypeSpecTypeLoc>();
74  }
75
76  /// Resets this builder to the newly-initialized state.
77  void clear() {
78#ifndef NDEBUG
79    LastTy = QualType();
80#endif
81    Index = Capacity;
82    NumBytesAtAlign4 = NumBytesAtAlign8 = 0;
83  }
84
85  /// Tell the TypeLocBuilder that the type it is storing has been
86  /// modified in some safe way that doesn't affect type-location information.
87  void TypeWasModifiedSafely(QualType T) {
88#ifndef NDEBUG
89    LastTy = T;
90#endif
91  }
92
93  /// Pushes space for a new TypeLoc of the given type.  Invalidates
94  /// any TypeLocs previously retrieved from this builder.
95  template <class TyLocType> TyLocType push(QualType T) {
96    TyLocType Loc = TypeLoc(T, nullptr).castAs<TyLocType>();
97    size_t LocalSize = Loc.getLocalDataSize();
98    unsigned LocalAlign = Loc.getLocalDataAlignment();
99    return pushImpl(T, LocalSize, LocalAlign).castAs<TyLocType>();
100  }
101
102  /// Creates a TypeSourceInfo for the given type.
103  TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) {
104#ifndef NDEBUG
105    assert(T == LastTy && "type doesn't match last type pushed!");
106#endif
107
108    size_t FullDataSize = Capacity - Index;
109    TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize);
110    memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
111    return DI;
112  }
113
114  /// Copies the type-location information to the given AST context and
115  /// returns a \c TypeLoc referring into the AST context.
116  TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) {
117#ifndef NDEBUG
118    assert(T == LastTy && "type doesn't match last type pushed!");
119#endif
120
121    size_t FullDataSize = Capacity - Index;
122    void *Mem = Context.Allocate(FullDataSize);
123    memcpy(Mem, &Buffer[Index], FullDataSize);
124    return TypeLoc(T, Mem);
125  }
126
127private:
128
129  TypeLoc pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment);
130
131  /// Grow to the given capacity.
132  void grow(size_t NewCapacity);
133
134  /// Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder
135  /// object.
136  ///
137  /// The resulting \c TypeLoc should only be used so long as the
138  /// \c TypeLocBuilder is active and has not had more type information
139  /// pushed into it.
140  TypeLoc getTemporaryTypeLoc(QualType T) {
141#ifndef NDEBUG
142    assert(LastTy == T && "type doesn't match last type pushed!");
143#endif
144    return TypeLoc(T, &Buffer[Index]);
145  }
146};
147
148}
149
150#endif
151