1356843Sdim//==--- AbstractBasiceReader.h - Abstract basic value deserialization -----===//
2356843Sdim//
3356843Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4356843Sdim// See https://llvm.org/LICENSE.txt for license information.
5356843Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6356843Sdim//
7356843Sdim//===----------------------------------------------------------------------===//
8356843Sdim
9356843Sdim#ifndef CLANG_AST_ABSTRACTBASICREADER_H
10356843Sdim#define CLANG_AST_ABSTRACTBASICREADER_H
11356843Sdim
12356843Sdim#include "clang/AST/DeclTemplate.h"
13356843Sdim
14356843Sdimnamespace clang {
15356843Sdimnamespace serialization {
16356843Sdim
17356843Sdimtemplate <class T>
18356843Sdiminline T makeNullableFromOptional(const Optional<T> &value) {
19356843Sdim  return (value ? *value : T());
20356843Sdim}
21356843Sdim
22356843Sdimtemplate <class T>
23356843Sdiminline T *makePointerFromOptional(Optional<T *> value) {
24356843Sdim  return (value ? *value : nullptr);
25356843Sdim}
26356843Sdim
27356843Sdim// PropertyReader is a class concept that requires the following method:
28356843Sdim//   BasicReader find(llvm::StringRef propertyName);
29356843Sdim// where BasicReader is some class conforming to the BasicReader concept.
30356843Sdim// An abstract AST-node reader is created with a PropertyReader and
31356843Sdim// performs a sequence of calls like so:
32356843Sdim//   propertyReader.find(propertyName).read##TypeName()
33356843Sdim// to read the properties of the node it is deserializing.
34356843Sdim
35356843Sdim// BasicReader is a class concept that requires methods like:
36356843Sdim//   ValueType read##TypeName();
37356843Sdim// where TypeName is the name of a PropertyType node from PropertiesBase.td
38356843Sdim// and ValueType is the corresponding C++ type name.  The read method may
39356843Sdim// require one or more buffer arguments.
40356843Sdim//
41356843Sdim// In addition to the concrete type names, BasicReader is expected to
42356843Sdim// implement these methods:
43356843Sdim//
44356843Sdim//   template <class EnumType>
45356843Sdim//   void writeEnum(T value);
46356843Sdim//
47356843Sdim//     Reads an enum value from the current property.  EnumType will always
48356843Sdim//     be an enum type.  Only necessary if the BasicReader doesn't provide
49356843Sdim//     type-specific readers for all the enum types.
50356843Sdim//
51356843Sdim//   template <class ValueType>
52356843Sdim//   Optional<ValueType> writeOptional();
53356843Sdim//
54356843Sdim//     Reads an optional value from the current property.
55356843Sdim//
56356843Sdim//   template <class ValueType>
57356843Sdim//   ArrayRef<ValueType> readArray(llvm::SmallVectorImpl<ValueType> &buffer);
58356843Sdim//
59356843Sdim//     Reads an array of values from the current property.
60356843Sdim//
61356843Sdim//   PropertyReader readObject();
62356843Sdim//
63356843Sdim//     Reads an object from the current property; the returned property
64356843Sdim//     reader will be subjected to a sequence of property reads and then
65356843Sdim//     discarded before any other properties are reader from the "outer"
66356843Sdim//     property reader (which need not be the same type).  The sub-reader
67356843Sdim//     will be used as if with the following code:
68356843Sdim//
69356843Sdim//       {
70356843Sdim//         auto &&widget = W.find("widget").readObject();
71356843Sdim//         auto kind = widget.find("kind").readWidgetKind();
72356843Sdim//         auto declaration = widget.find("declaration").readDeclRef();
73356843Sdim//         return Widget(kind, declaration);
74356843Sdim//       }
75356843Sdim
76356843Sdim// ReadDispatcher does type-based forwarding to one of the read methods
77356843Sdim// on the BasicReader passed in:
78356843Sdim//
79356843Sdim// template <class ValueType>
80356843Sdim// struct ReadDispatcher {
81356843Sdim//   template <class BasicReader, class... BufferTypes>
82356843Sdim//   static ValueType read(BasicReader &R, BufferTypes &&...);
83356843Sdim// };
84356843Sdim
85356843Sdim// BasicReaderBase provides convenience implementations of the read methods
86356843Sdim// for EnumPropertyType and SubclassPropertyType types that just defer to
87356843Sdim// the "underlying" implementations (for UInt32 and the base class,
88356843Sdim// respectively).
89356843Sdim//
90356843Sdim// template <class Impl>
91356843Sdim// class BasicReaderBase {
92356843Sdim// protected:
93356843Sdim//   BasicReaderBase(ASTContext &ctx);
94356843Sdim//   Impl &asImpl();
95356843Sdim// public:
96356843Sdim//   ASTContext &getASTContext();
97356843Sdim//   ...
98356843Sdim// };
99356843Sdim
100356843Sdim// The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp.
101356843Sdim#include "clang/AST/AbstractBasicReader.inc"
102356843Sdim
103356843Sdim/// DataStreamBasicReader provides convenience implementations for many
104356843Sdim/// BasicReader methods based on the assumption that the
105356843Sdim/// ultimate reader implementation is based on a variable-length stream
106356843Sdim/// of unstructured data (like Clang's module files).  It is designed
107356843Sdim/// to pair with DataStreamBasicWriter.
108356843Sdim///
109356843Sdim/// This class can also act as a PropertyReader, implementing find("...")
110356843Sdim/// by simply forwarding to itself.
111356843Sdim///
112356843Sdim/// Unimplemented methods:
113356843Sdim///   readBool
114356843Sdim///   readUInt32
115356843Sdim///   readUInt64
116356843Sdim///   readIdentifier
117356843Sdim///   readSelector
118356843Sdim///   readSourceLocation
119356843Sdim///   readQualType
120356843Sdim///   readStmtRef
121356843Sdim///   readDeclRef
122356843Sdimtemplate <class Impl>
123356843Sdimclass DataStreamBasicReader : public BasicReaderBase<Impl> {
124356843Sdimprotected:
125356843Sdim  using BasicReaderBase<Impl>::asImpl;
126356843Sdim  DataStreamBasicReader(ASTContext &ctx) : BasicReaderBase<Impl>(ctx) {}
127356843Sdim
128356843Sdimpublic:
129356843Sdim  using BasicReaderBase<Impl>::getASTContext;
130356843Sdim
131356843Sdim  /// Implement property-find by ignoring it.  We rely on properties being
132356843Sdim  /// serialized and deserialized in a reliable order instead.
133356843Sdim  Impl &find(const char *propertyName) {
134356843Sdim    return asImpl();
135356843Sdim  }
136356843Sdim
137356843Sdim  template <class T>
138356843Sdim  T readEnum() {
139356843Sdim    return T(asImpl().readUInt32());
140356843Sdim  }
141356843Sdim
142356843Sdim  // Implement object reading by forwarding to this, collapsing the
143356843Sdim  // structure into a single data stream.
144356843Sdim  Impl &readObject() { return asImpl(); }
145356843Sdim
146356843Sdim  template <class T>
147356843Sdim  llvm::ArrayRef<T> readArray(llvm::SmallVectorImpl<T> &buffer) {
148356843Sdim    assert(buffer.empty());
149356843Sdim
150356843Sdim    uint32_t size = asImpl().readUInt32();
151356843Sdim    buffer.reserve(size);
152356843Sdim
153356843Sdim    for (uint32_t i = 0; i != size; ++i) {
154356843Sdim      buffer.push_back(ReadDispatcher<T>::read(asImpl()));
155356843Sdim    }
156356843Sdim    return buffer;
157356843Sdim  }
158356843Sdim
159356843Sdim  template <class T, class... Args>
160356843Sdim  llvm::Optional<T> readOptional(Args &&...args) {
161356843Sdim    return UnpackOptionalValue<T>::unpack(
162356843Sdim             ReadDispatcher<T>::read(asImpl(), std::forward<Args>(args)...));
163356843Sdim  }
164356843Sdim
165356843Sdim  llvm::APSInt readAPSInt() {
166356843Sdim    bool isUnsigned = asImpl().readBool();
167356843Sdim    llvm::APInt value = asImpl().readAPInt();
168356843Sdim    return llvm::APSInt(std::move(value), isUnsigned);
169356843Sdim  }
170356843Sdim
171356843Sdim  llvm::APInt readAPInt() {
172356843Sdim    unsigned bitWidth = asImpl().readUInt32();
173356843Sdim    unsigned numWords = llvm::APInt::getNumWords(bitWidth);
174356843Sdim    llvm::SmallVector<uint64_t, 4> data;
175356843Sdim    for (uint32_t i = 0; i != numWords; ++i)
176356843Sdim      data.push_back(asImpl().readUInt64());
177356843Sdim    return llvm::APInt(bitWidth, numWords, &data[0]);
178356843Sdim  }
179356843Sdim
180356843Sdim  Qualifiers readQualifiers() {
181356843Sdim    static_assert(sizeof(Qualifiers().getAsOpaqueValue()) <= sizeof(uint32_t),
182356843Sdim                  "update this if the value size changes");
183356843Sdim    uint32_t value = asImpl().readUInt32();
184356843Sdim    return Qualifiers::fromOpaqueValue(value);
185356843Sdim  }
186356843Sdim
187356843Sdim  FunctionProtoType::ExceptionSpecInfo
188356843Sdim  readExceptionSpecInfo(llvm::SmallVectorImpl<QualType> &buffer) {
189356843Sdim    FunctionProtoType::ExceptionSpecInfo esi;
190356843Sdim    esi.Type = ExceptionSpecificationType(asImpl().readUInt32());
191356843Sdim    if (esi.Type == EST_Dynamic) {
192356843Sdim      esi.Exceptions = asImpl().template readArray<QualType>(buffer);
193356843Sdim    } else if (isComputedNoexcept(esi.Type)) {
194356843Sdim      esi.NoexceptExpr = asImpl().readExprRef();
195356843Sdim    } else if (esi.Type == EST_Uninstantiated) {
196356843Sdim      esi.SourceDecl = asImpl().readFunctionDeclRef();
197356843Sdim      esi.SourceTemplate = asImpl().readFunctionDeclRef();
198356843Sdim    } else if (esi.Type == EST_Unevaluated) {
199356843Sdim      esi.SourceDecl = asImpl().readFunctionDeclRef();
200356843Sdim    }
201356843Sdim    return esi;
202356843Sdim  }
203356843Sdim
204356843Sdim  FunctionProtoType::ExtParameterInfo readExtParameterInfo() {
205356843Sdim    static_assert(sizeof(FunctionProtoType::ExtParameterInfo().getOpaqueValue())
206356843Sdim                    <= sizeof(uint32_t),
207356843Sdim                  "opaque value doesn't fit into uint32_t");
208356843Sdim    uint32_t value = asImpl().readUInt32();
209356843Sdim    return FunctionProtoType::ExtParameterInfo::getFromOpaqueValue(value);
210356843Sdim  }
211356843Sdim
212356843Sdim  NestedNameSpecifier *readNestedNameSpecifier() {
213356843Sdim    auto &ctx = getASTContext();
214356843Sdim
215356843Sdim    // We build this up iteratively.
216356843Sdim    NestedNameSpecifier *cur = nullptr;
217356843Sdim
218356843Sdim    uint32_t depth = asImpl().readUInt32();
219356843Sdim    for (uint32_t i = 0; i != depth; ++i) {
220356843Sdim      auto kind = asImpl().readNestedNameSpecifierKind();
221356843Sdim      switch (kind) {
222356843Sdim      case NestedNameSpecifier::Identifier:
223356843Sdim        cur = NestedNameSpecifier::Create(ctx, cur,
224356843Sdim                                          asImpl().readIdentifier());
225356843Sdim        continue;
226356843Sdim
227356843Sdim      case NestedNameSpecifier::Namespace:
228356843Sdim        cur = NestedNameSpecifier::Create(ctx, cur,
229356843Sdim                                          asImpl().readNamespaceDeclRef());
230356843Sdim        continue;
231356843Sdim
232356843Sdim      case NestedNameSpecifier::NamespaceAlias:
233356843Sdim        cur = NestedNameSpecifier::Create(ctx, cur,
234356843Sdim                                     asImpl().readNamespaceAliasDeclRef());
235356843Sdim        continue;
236356843Sdim
237356843Sdim      case NestedNameSpecifier::TypeSpec:
238356843Sdim      case NestedNameSpecifier::TypeSpecWithTemplate:
239356843Sdim        cur = NestedNameSpecifier::Create(ctx, cur,
240356843Sdim                          kind == NestedNameSpecifier::TypeSpecWithTemplate,
241356843Sdim                          asImpl().readQualType().getTypePtr());
242356843Sdim        continue;
243356843Sdim
244356843Sdim      case NestedNameSpecifier::Global:
245356843Sdim        cur = NestedNameSpecifier::GlobalSpecifier(ctx);
246356843Sdim        continue;
247356843Sdim
248356843Sdim      case NestedNameSpecifier::Super:
249356843Sdim        cur = NestedNameSpecifier::SuperSpecifier(ctx,
250356843Sdim                                            asImpl().readCXXRecordDeclRef());
251356843Sdim        continue;
252356843Sdim      }
253356843Sdim      llvm_unreachable("bad nested name specifier kind");
254356843Sdim    }
255356843Sdim
256356843Sdim    return cur;
257356843Sdim  }
258356843Sdim};
259356843Sdim
260356843Sdim} // end namespace serialization
261356843Sdim} // end namespace clang
262356843Sdim
263356843Sdim#endif
264