1 //==--- AbstractBasiceReader.h - Abstract basic value deserialization -----===//
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 #ifndef LLVM_CLANG_AST_ABSTRACTBASICREADER_H
10 #define LLVM_CLANG_AST_ABSTRACTBASICREADER_H
11
12 #include "clang/AST/DeclTemplate.h"
13 #include <optional>
14
15 namespace clang {
16 namespace serialization {
17
18 template <class T>
makeNullableFromOptional(const std::optional<T> & value)19 inline T makeNullableFromOptional(const std::optional<T> &value) {
20 return (value ? *value : T());
21 }
22
makePointerFromOptional(std::optional<T * > value)23 template <class T> inline T *makePointerFromOptional(std::optional<T *> value) {
24 return value.value_or(nullptr);
25 }
26
27 // PropertyReader is a class concept that requires the following method:
28 // BasicReader find(llvm::StringRef propertyName);
29 // where BasicReader is some class conforming to the BasicReader concept.
30 // An abstract AST-node reader is created with a PropertyReader and
31 // performs a sequence of calls like so:
32 // propertyReader.find(propertyName).read##TypeName()
33 // to read the properties of the node it is deserializing.
34
35 // BasicReader is a class concept that requires methods like:
36 // ValueType read##TypeName();
37 // where TypeName is the name of a PropertyType node from PropertiesBase.td
38 // and ValueType is the corresponding C++ type name. The read method may
39 // require one or more buffer arguments.
40 //
41 // In addition to the concrete type names, BasicReader is expected to
42 // implement these methods:
43 //
44 // template <class EnumType>
45 // void writeEnum(T value);
46 //
47 // Reads an enum value from the current property. EnumType will always
48 // be an enum type. Only necessary if the BasicReader doesn't provide
49 // type-specific readers for all the enum types.
50 //
51 // template <class ValueType>
52 // std::optional<ValueType> writeOptional();
53 //
54 // Reads an optional value from the current property.
55 //
56 // template <class ValueType>
57 // ArrayRef<ValueType> readArray(llvm::SmallVectorImpl<ValueType> &buffer);
58 //
59 // Reads an array of values from the current property.
60 //
61 // PropertyReader readObject();
62 //
63 // Reads an object from the current property; the returned property
64 // reader will be subjected to a sequence of property reads and then
65 // discarded before any other properties are reader from the "outer"
66 // property reader (which need not be the same type). The sub-reader
67 // will be used as if with the following code:
68 //
69 // {
70 // auto &&widget = W.find("widget").readObject();
71 // auto kind = widget.find("kind").readWidgetKind();
72 // auto declaration = widget.find("declaration").readDeclRef();
73 // return Widget(kind, declaration);
74 // }
75
76 // ReadDispatcher does type-based forwarding to one of the read methods
77 // on the BasicReader passed in:
78 //
79 // template <class ValueType>
80 // struct ReadDispatcher {
81 // template <class BasicReader, class... BufferTypes>
82 // static ValueType read(BasicReader &R, BufferTypes &&...);
83 // };
84
85 // BasicReaderBase provides convenience implementations of the read methods
86 // for EnumPropertyType and SubclassPropertyType types that just defer to
87 // the "underlying" implementations (for UInt32 and the base class,
88 // respectively).
89 //
90 // template <class Impl>
91 // class BasicReaderBase {
92 // protected:
93 // BasicReaderBase(ASTContext &ctx);
94 // Impl &asImpl();
95 // public:
96 // ASTContext &getASTContext();
97 // ...
98 // };
99
100 // The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp.
101 #include "clang/AST/AbstractBasicReader.inc"
102
103 /// DataStreamBasicReader provides convenience implementations for many
104 /// BasicReader methods based on the assumption that the
105 /// ultimate reader implementation is based on a variable-length stream
106 /// of unstructured data (like Clang's module files). It is designed
107 /// to pair with DataStreamBasicWriter.
108 ///
109 /// This class can also act as a PropertyReader, implementing find("...")
110 /// by simply forwarding to itself.
111 ///
112 /// Unimplemented methods:
113 /// readBool
114 /// readUInt32
115 /// readUInt64
116 /// readIdentifier
117 /// readSelector
118 /// readSourceLocation
119 /// readQualType
120 /// readStmtRef
121 /// readDeclRef
122 template <class Impl>
123 class DataStreamBasicReader : public BasicReaderBase<Impl> {
124 protected:
125 using BasicReaderBase<Impl>::asImpl;
DataStreamBasicReader(ASTContext & ctx)126 DataStreamBasicReader(ASTContext &ctx) : BasicReaderBase<Impl>(ctx) {}
127
128 public:
129 using BasicReaderBase<Impl>::getASTContext;
130
131 /// Implement property-find by ignoring it. We rely on properties being
132 /// serialized and deserialized in a reliable order instead.
find(const char * propertyName)133 Impl &find(const char *propertyName) {
134 return asImpl();
135 }
136
137 template <class T>
readEnum()138 T readEnum() {
139 return T(asImpl().readUInt32());
140 }
141
142 // Implement object reading by forwarding to this, collapsing the
143 // structure into a single data stream.
readObject()144 Impl &readObject() { return asImpl(); }
145
146 template <class T>
readArray(llvm::SmallVectorImpl<T> & buffer)147 llvm::ArrayRef<T> readArray(llvm::SmallVectorImpl<T> &buffer) {
148 assert(buffer.empty());
149
150 uint32_t size = asImpl().readUInt32();
151 buffer.reserve(size);
152
153 for (uint32_t i = 0; i != size; ++i) {
154 buffer.push_back(ReadDispatcher<T>::read(asImpl()));
155 }
156 return buffer;
157 }
158
159 template <class T, class... Args>
readOptional(Args &&...args)160 std::optional<T> readOptional(Args &&...args) {
161 return UnpackOptionalValue<T>::unpack(
162 ReadDispatcher<T>::read(asImpl(), std::forward<Args>(args)...));
163 }
164
readAPSInt()165 llvm::APSInt readAPSInt() {
166 bool isUnsigned = asImpl().readBool();
167 llvm::APInt value = asImpl().readAPInt();
168 return llvm::APSInt(std::move(value), isUnsigned);
169 }
170
readAPInt()171 llvm::APInt readAPInt() {
172 unsigned bitWidth = asImpl().readUInt32();
173 unsigned numWords = llvm::APInt::getNumWords(bitWidth);
174 llvm::SmallVector<uint64_t, 4> data;
175 for (uint32_t i = 0; i != numWords; ++i)
176 data.push_back(asImpl().readUInt64());
177 return llvm::APInt(bitWidth, numWords, &data[0]);
178 }
179
readFixedPointSemantics()180 llvm::FixedPointSemantics readFixedPointSemantics() {
181 unsigned width = asImpl().readUInt32();
182 unsigned scale = asImpl().readUInt32();
183 unsigned tmp = asImpl().readUInt32();
184 bool isSigned = tmp & 0x1;
185 bool isSaturated = tmp & 0x2;
186 bool hasUnsignedPadding = tmp & 0x4;
187 return llvm::FixedPointSemantics(width, scale, isSigned, isSaturated,
188 hasUnsignedPadding);
189 }
190
readLValuePathSerializationHelper(SmallVectorImpl<APValue::LValuePathEntry> & path)191 APValue::LValuePathSerializationHelper readLValuePathSerializationHelper(
192 SmallVectorImpl<APValue::LValuePathEntry> &path) {
193 auto origTy = asImpl().readQualType();
194 auto elemTy = origTy;
195 unsigned pathLength = asImpl().readUInt32();
196 for (unsigned i = 0; i < pathLength; ++i) {
197 if (elemTy->template getAs<RecordType>()) {
198 unsigned int_ = asImpl().readUInt32();
199 Decl *decl = asImpl().template readDeclAs<Decl>();
200 if (auto *recordDecl = dyn_cast<CXXRecordDecl>(decl))
201 elemTy = getASTContext().getRecordType(recordDecl);
202 else
203 elemTy = cast<ValueDecl>(decl)->getType();
204 path.push_back(
205 APValue::LValuePathEntry(APValue::BaseOrMemberType(decl, int_)));
206 } else {
207 elemTy = getASTContext().getAsArrayType(elemTy)->getElementType();
208 path.push_back(
209 APValue::LValuePathEntry::ArrayIndex(asImpl().readUInt32()));
210 }
211 }
212 return APValue::LValuePathSerializationHelper(path, origTy);
213 }
214
readQualifiers()215 Qualifiers readQualifiers() {
216 static_assert(sizeof(Qualifiers().getAsOpaqueValue()) <= sizeof(uint64_t),
217 "update this if the value size changes");
218 uint64_t value = asImpl().readUInt64();
219 return Qualifiers::fromOpaqueValue(value);
220 }
221
222 FunctionProtoType::ExceptionSpecInfo
readExceptionSpecInfo(llvm::SmallVectorImpl<QualType> & buffer)223 readExceptionSpecInfo(llvm::SmallVectorImpl<QualType> &buffer) {
224 FunctionProtoType::ExceptionSpecInfo esi;
225 esi.Type = ExceptionSpecificationType(asImpl().readUInt32());
226 if (esi.Type == EST_Dynamic) {
227 esi.Exceptions = asImpl().template readArray<QualType>(buffer);
228 } else if (isComputedNoexcept(esi.Type)) {
229 esi.NoexceptExpr = asImpl().readExprRef();
230 } else if (esi.Type == EST_Uninstantiated) {
231 esi.SourceDecl = asImpl().readFunctionDeclRef();
232 esi.SourceTemplate = asImpl().readFunctionDeclRef();
233 } else if (esi.Type == EST_Unevaluated) {
234 esi.SourceDecl = asImpl().readFunctionDeclRef();
235 }
236 return esi;
237 }
238
readExtParameterInfo()239 FunctionProtoType::ExtParameterInfo readExtParameterInfo() {
240 static_assert(sizeof(FunctionProtoType::ExtParameterInfo().getOpaqueValue())
241 <= sizeof(uint32_t),
242 "opaque value doesn't fit into uint32_t");
243 uint32_t value = asImpl().readUInt32();
244 return FunctionProtoType::ExtParameterInfo::getFromOpaqueValue(value);
245 }
246
readFunctionEffect()247 FunctionEffect readFunctionEffect() {
248 uint32_t value = asImpl().readUInt32();
249 return FunctionEffect::fromOpaqueInt32(value);
250 }
251
readEffectConditionExpr()252 EffectConditionExpr readEffectConditionExpr() {
253 return EffectConditionExpr{asImpl().readExprRef()};
254 }
255
readNestedNameSpecifier()256 NestedNameSpecifier *readNestedNameSpecifier() {
257 auto &ctx = getASTContext();
258
259 // We build this up iteratively.
260 NestedNameSpecifier *cur = nullptr;
261
262 uint32_t depth = asImpl().readUInt32();
263 for (uint32_t i = 0; i != depth; ++i) {
264 auto kind = asImpl().readNestedNameSpecifierKind();
265 switch (kind) {
266 case NestedNameSpecifier::Identifier:
267 cur = NestedNameSpecifier::Create(ctx, cur,
268 asImpl().readIdentifier());
269 continue;
270
271 case NestedNameSpecifier::Namespace:
272 cur = NestedNameSpecifier::Create(ctx, cur,
273 asImpl().readNamespaceDeclRef());
274 continue;
275
276 case NestedNameSpecifier::NamespaceAlias:
277 cur = NestedNameSpecifier::Create(ctx, cur,
278 asImpl().readNamespaceAliasDeclRef());
279 continue;
280
281 case NestedNameSpecifier::TypeSpec:
282 case NestedNameSpecifier::TypeSpecWithTemplate:
283 cur = NestedNameSpecifier::Create(ctx, cur,
284 kind == NestedNameSpecifier::TypeSpecWithTemplate,
285 asImpl().readQualType().getTypePtr());
286 continue;
287
288 case NestedNameSpecifier::Global:
289 cur = NestedNameSpecifier::GlobalSpecifier(ctx);
290 continue;
291
292 case NestedNameSpecifier::Super:
293 cur = NestedNameSpecifier::SuperSpecifier(ctx,
294 asImpl().readCXXRecordDeclRef());
295 continue;
296 }
297 llvm_unreachable("bad nested name specifier kind");
298 }
299
300 return cur;
301 }
302 };
303
304 } // end namespace serialization
305 } // end namespace clang
306
307 #endif
308