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 CLANG_AST_ABSTRACTBASICREADER_H
10#define CLANG_AST_ABSTRACTBASICREADER_H
11
12#include "clang/AST/DeclTemplate.h"
13
14namespace clang {
15namespace serialization {
16
17template <class T>
18inline T makeNullableFromOptional(const Optional<T> &value) {
19  return (value ? *value : T());
20}
21
22template <class T>
23inline T *makePointerFromOptional(Optional<T *> value) {
24  return (value ? *value : 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//   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
122template <class Impl>
123class DataStreamBasicReader : public BasicReaderBase<Impl> {
124protected:
125  using BasicReaderBase<Impl>::asImpl;
126  DataStreamBasicReader(ASTContext &ctx) : BasicReaderBase<Impl>(ctx) {}
127
128public:
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.
133  Impl &find(const char *propertyName) {
134    return asImpl();
135  }
136
137  template <class T>
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.
144  Impl &readObject() { return asImpl(); }
145
146  template <class T>
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>
160  llvm::Optional<T> readOptional(Args &&...args) {
161    return UnpackOptionalValue<T>::unpack(
162             ReadDispatcher<T>::read(asImpl(), std::forward<Args>(args)...));
163  }
164
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
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
180  Qualifiers readQualifiers() {
181    static_assert(sizeof(Qualifiers().getAsOpaqueValue()) <= sizeof(uint32_t),
182                  "update this if the value size changes");
183    uint32_t value = asImpl().readUInt32();
184    return Qualifiers::fromOpaqueValue(value);
185  }
186
187  FunctionProtoType::ExceptionSpecInfo
188  readExceptionSpecInfo(llvm::SmallVectorImpl<QualType> &buffer) {
189    FunctionProtoType::ExceptionSpecInfo esi;
190    esi.Type = ExceptionSpecificationType(asImpl().readUInt32());
191    if (esi.Type == EST_Dynamic) {
192      esi.Exceptions = asImpl().template readArray<QualType>(buffer);
193    } else if (isComputedNoexcept(esi.Type)) {
194      esi.NoexceptExpr = asImpl().readExprRef();
195    } else if (esi.Type == EST_Uninstantiated) {
196      esi.SourceDecl = asImpl().readFunctionDeclRef();
197      esi.SourceTemplate = asImpl().readFunctionDeclRef();
198    } else if (esi.Type == EST_Unevaluated) {
199      esi.SourceDecl = asImpl().readFunctionDeclRef();
200    }
201    return esi;
202  }
203
204  FunctionProtoType::ExtParameterInfo readExtParameterInfo() {
205    static_assert(sizeof(FunctionProtoType::ExtParameterInfo().getOpaqueValue())
206                    <= sizeof(uint32_t),
207                  "opaque value doesn't fit into uint32_t");
208    uint32_t value = asImpl().readUInt32();
209    return FunctionProtoType::ExtParameterInfo::getFromOpaqueValue(value);
210  }
211
212  NestedNameSpecifier *readNestedNameSpecifier() {
213    auto &ctx = getASTContext();
214
215    // We build this up iteratively.
216    NestedNameSpecifier *cur = nullptr;
217
218    uint32_t depth = asImpl().readUInt32();
219    for (uint32_t i = 0; i != depth; ++i) {
220      auto kind = asImpl().readNestedNameSpecifierKind();
221      switch (kind) {
222      case NestedNameSpecifier::Identifier:
223        cur = NestedNameSpecifier::Create(ctx, cur,
224                                          asImpl().readIdentifier());
225        continue;
226
227      case NestedNameSpecifier::Namespace:
228        cur = NestedNameSpecifier::Create(ctx, cur,
229                                          asImpl().readNamespaceDeclRef());
230        continue;
231
232      case NestedNameSpecifier::NamespaceAlias:
233        cur = NestedNameSpecifier::Create(ctx, cur,
234                                     asImpl().readNamespaceAliasDeclRef());
235        continue;
236
237      case NestedNameSpecifier::TypeSpec:
238      case NestedNameSpecifier::TypeSpecWithTemplate:
239        cur = NestedNameSpecifier::Create(ctx, cur,
240                          kind == NestedNameSpecifier::TypeSpecWithTemplate,
241                          asImpl().readQualType().getTypePtr());
242        continue;
243
244      case NestedNameSpecifier::Global:
245        cur = NestedNameSpecifier::GlobalSpecifier(ctx);
246        continue;
247
248      case NestedNameSpecifier::Super:
249        cur = NestedNameSpecifier::SuperSpecifier(ctx,
250                                            asImpl().readCXXRecordDeclRef());
251        continue;
252      }
253      llvm_unreachable("bad nested name specifier kind");
254    }
255
256    return cur;
257  }
258};
259
260} // end namespace serialization
261} // end namespace clang
262
263#endif
264