AbstractBasicWriter.h revision 360784
1219019Sgabor//==--- AbstractBasicWriter.h - Abstract basic value serialization --------===//
2219019Sgabor//
3219019Sgabor// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4219019Sgabor// See https://llvm.org/LICENSE.txt for license information.
5219019Sgabor// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6219019Sgabor//
7219019Sgabor//===----------------------------------------------------------------------===//
8219019Sgabor
9219019Sgabor#ifndef CLANG_AST_ABSTRACTBASICWRITER_H
10219019Sgabor#define CLANG_AST_ABSTRACTBASICWRITER_H
11219019Sgabor
12219019Sgabor#include "clang/AST/DeclTemplate.h"
13219019Sgabor
14219019Sgabornamespace clang {
15219019Sgabornamespace serialization {
16219019Sgabor
17219019Sgabortemplate <class T>
18219019Sgaborinline llvm::Optional<T> makeOptionalFromNullable(const T &value) {
19219019Sgabor  return (value.isNull()
20219019Sgabor            ? llvm::Optional<T>()
21219019Sgabor            : llvm::Optional<T>(value));
22219019Sgabor}
23219019Sgabor
24219019Sgabortemplate <class T>
25219019Sgaborinline llvm::Optional<T*> makeOptionalFromPointer(T *value) {
26219019Sgabor  return (value ? llvm::Optional<T*>(value) : llvm::Optional<T*>());
27219019Sgabor}
28219019Sgabor
29219019Sgabor// PropertyWriter is a class concept that requires the following method:
30219019Sgabor//   BasicWriter find(llvm::StringRef propertyName);
31219019Sgabor// where BasicWriter is some class conforming to the BasicWriter concept.
32219019Sgabor// An abstract AST-node writer is created with a PropertyWriter and
33219019Sgabor// performs a sequence of calls like so:
34219019Sgabor//   propertyWriter.find(propertyName).write##TypeName(value)
35219019Sgabor// to write the properties of the node it is serializing.
36219019Sgabor
37219019Sgabor// BasicWriter is a class concept that requires methods like:
38219019Sgabor//   void write##TypeName(ValueType value);
39219019Sgabor// where TypeName is the name of a PropertyType node from PropertiesBase.td
40219019Sgabor// and ValueType is the corresponding C++ type name.
41219019Sgabor//
42219019Sgabor// In addition to the concrete property types, BasicWriter is expected
43219019Sgabor// to implement these methods:
44219019Sgabor//
45219019Sgabor//   template <class EnumType>
46219019Sgabor//   void writeEnum(T value);
47219019Sgabor//
48219019Sgabor//     Writes an enum value as the current property.  EnumType will always
49219019Sgabor//     be an enum type.  Only necessary if the BasicWriter doesn't provide
50219019Sgabor//     type-specific writers for all the enum types.
51219019Sgabor//
52219019Sgabor//   template <class ValueType>
53219019Sgabor//   void writeOptional(Optional<ValueType> value);
54219019Sgabor//
55219019Sgabor//     Writes an optional value as the current property.
56219019Sgabor//
57219019Sgabor//   template <class ValueType>
58219019Sgabor//   void writeArray(ArrayRef<ValueType> value);
59219019Sgabor//
60219019Sgabor//     Writes an array of values as the current property.
61219019Sgabor//
62219019Sgabor//   PropertyWriter writeObject();
63219019Sgabor//
64219019Sgabor//     Writes an object as the current property; the returned property
65219019Sgabor//     writer will be subjected to a sequence of property writes and then
66219019Sgabor//     discarded before any other properties are written to the "outer"
67219019Sgabor//     property writer (which need not be the same type).  The sub-writer
68219019Sgabor//     will be used as if with the following code:
69219019Sgabor//
70219019Sgabor//       {
71219019Sgabor//         auto &&widget = W.find("widget").writeObject();
72219019Sgabor//         widget.find("kind").writeWidgetKind(...);
73219019Sgabor//         widget.find("declaration").writeDeclRef(...);
74219019Sgabor//       }
75219019Sgabor
76219019Sgabor// WriteDispatcher is a template which does type-based forwarding to one
77219019Sgabor// of the write methods of the BasicWriter passed in:
78219019Sgabor//
79219019Sgabor// template <class ValueType>
80219019Sgabor// struct WriteDispatcher {
81219019Sgabor//   template <class BasicWriter>
82219019Sgabor//   static void write(BasicWriter &W, ValueType value);
83219019Sgabor// };
84219019Sgabor
85219019Sgabor// BasicWriterBase provides convenience implementations of the write
86219019Sgabor// methods for EnumPropertyType and SubclassPropertyType types that just
87219019Sgabor// defer to the "underlying" implementations (for UInt32 and the base class,
88219019Sgabor// respectively).
89219019Sgabor//
90219019Sgabor// template <class Impl>
91219019Sgabor// class BasicWriterBase {
92219019Sgabor// protected:
93219019Sgabor//   Impl &asImpl();
94219019Sgabor// public:
95219019Sgabor//   ...
96219019Sgabor// };
97219019Sgabor
98219019Sgabor// The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp.
99219019Sgabor#include "clang/AST/AbstractBasicWriter.inc"
100219019Sgabor
101219019Sgabor/// DataStreamBasicWriter provides convenience implementations for many
102219019Sgabor/// BasicWriter methods based on the assumption that the
103219019Sgabor/// ultimate writer implementation is based on a variable-length stream
104219019Sgabor/// of unstructured data (like Clang's module files).  It is designed
105219019Sgabor/// to pair with DataStreamBasicReader.
106219019Sgabor///
107219019Sgabor/// This class can also act as a PropertyWriter, implementing find("...")
108219019Sgabor/// by simply forwarding to itself.
109219019Sgabor///
110219019Sgabor/// Unimplemented methods:
111219019Sgabor///   writeBool
112219019Sgabor///   writeUInt32
113219019Sgabor///   writeUInt64
114219019Sgabor///   writeIdentifier
115219019Sgabor///   writeSelector
116219019Sgabor///   writeSourceLocation
117219019Sgabor///   writeQualType
118219019Sgabor///   writeStmtRef
119219019Sgabor///   writeDeclRef
120219019Sgabortemplate <class Impl>
121219019Sgaborclass DataStreamBasicWriter : public BasicWriterBase<Impl> {
122219019Sgaborprotected:
123219019Sgabor  using BasicWriterBase<Impl>::asImpl;
124219019Sgabor
125219019Sgaborpublic:
126219019Sgabor  /// Implement property-find by ignoring it.  We rely on properties being
127219019Sgabor  /// serialized and deserialized in a reliable order instead.
128219019Sgabor  Impl &find(const char *propertyName) {
129219019Sgabor    return asImpl();
130219019Sgabor  }
131219019Sgabor
132219019Sgabor  // Implement object writing by forwarding to this, collapsing the
133219019Sgabor  // structure into a single data stream.
134219019Sgabor  Impl &writeObject() { return asImpl(); }
135219019Sgabor
136219019Sgabor  template <class T>
137219019Sgabor  void writeEnum(T value) {
138219019Sgabor    asImpl().writeUInt32(uint32_t(value));
139219019Sgabor  }
140219019Sgabor
141219019Sgabor  template <class T>
142219019Sgabor  void writeArray(llvm::ArrayRef<T> array) {
143219019Sgabor    asImpl().writeUInt32(array.size());
144219019Sgabor    for (const T &elt : array) {
145219019Sgabor      WriteDispatcher<T>::write(asImpl(), elt);
146219019Sgabor    }
147219019Sgabor  }
148219019Sgabor
149219019Sgabor  template <class T>
150219019Sgabor  void writeOptional(llvm::Optional<T> value) {
151219019Sgabor    WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value));
152219019Sgabor  }
153219019Sgabor
154219019Sgabor  void writeAPSInt(const llvm::APSInt &value) {
155219019Sgabor    asImpl().writeBool(value.isUnsigned());
156219019Sgabor    asImpl().writeAPInt(value);
157219019Sgabor  }
158219019Sgabor
159219019Sgabor  void writeAPInt(const llvm::APInt &value) {
160219019Sgabor    asImpl().writeUInt32(value.getBitWidth());
161219019Sgabor    const uint64_t *words = value.getRawData();
162219019Sgabor    for (size_t i = 0, e = value.getNumWords(); i != e; ++i)
163219019Sgabor      asImpl().writeUInt64(words[i]);
164219019Sgabor  }
165219019Sgabor
166219019Sgabor  void writeQualifiers(Qualifiers value) {
167219019Sgabor    static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t),
168219019Sgabor                  "update this if the value size changes");
169219019Sgabor    asImpl().writeUInt32(value.getAsOpaqueValue());
170219019Sgabor  }
171219019Sgabor
172219019Sgabor  void writeExceptionSpecInfo(
173219019Sgabor                        const FunctionProtoType::ExceptionSpecInfo &esi) {
174219019Sgabor    asImpl().writeUInt32(uint32_t(esi.Type));
175219019Sgabor    if (esi.Type == EST_Dynamic) {
176219019Sgabor      asImpl().writeArray(esi.Exceptions);
177219019Sgabor    } else if (isComputedNoexcept(esi.Type)) {
178219019Sgabor      asImpl().writeExprRef(esi.NoexceptExpr);
179219019Sgabor    } else if (esi.Type == EST_Uninstantiated) {
180219019Sgabor      asImpl().writeDeclRef(esi.SourceDecl);
181219019Sgabor      asImpl().writeDeclRef(esi.SourceTemplate);
182219019Sgabor    } else if (esi.Type == EST_Unevaluated) {
183219019Sgabor      asImpl().writeDeclRef(esi.SourceDecl);
184219019Sgabor    }
185219019Sgabor  }
186219019Sgabor
187219019Sgabor  void writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi) {
188219019Sgabor    static_assert(sizeof(epi.getOpaqueValue()) <= sizeof(uint32_t),
189219019Sgabor                  "opaque value doesn't fit into uint32_t");
190219019Sgabor    asImpl().writeUInt32(epi.getOpaqueValue());
191219019Sgabor  }
192219019Sgabor
193219019Sgabor  void writeNestedNameSpecifier(NestedNameSpecifier *NNS) {
194219019Sgabor    // Nested name specifiers usually aren't too long. I think that 8 would
195219019Sgabor    // typically accommodate the vast majority.
196219019Sgabor    SmallVector<NestedNameSpecifier *, 8> nestedNames;
197219019Sgabor
198219019Sgabor    // Push each of the NNS's onto a stack for serialization in reverse order.
199219019Sgabor    while (NNS) {
200219019Sgabor      nestedNames.push_back(NNS);
201219019Sgabor      NNS = NNS->getPrefix();
202219019Sgabor    }
203219019Sgabor
204219019Sgabor    asImpl().writeUInt32(nestedNames.size());
205219019Sgabor    while (!nestedNames.empty()) {
206219019Sgabor      NNS = nestedNames.pop_back_val();
207219019Sgabor      NestedNameSpecifier::SpecifierKind kind = NNS->getKind();
208219019Sgabor      asImpl().writeNestedNameSpecifierKind(kind);
209219019Sgabor      switch (kind) {
210219019Sgabor      case NestedNameSpecifier::Identifier:
211219019Sgabor        asImpl().writeIdentifier(NNS->getAsIdentifier());
212219019Sgabor        continue;
213219019Sgabor
214219019Sgabor      case NestedNameSpecifier::Namespace:
215219019Sgabor        asImpl().writeNamespaceDeclRef(NNS->getAsNamespace());
216219019Sgabor        continue;
217219019Sgabor
218219019Sgabor      case NestedNameSpecifier::NamespaceAlias:
219219019Sgabor        asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias());
220219019Sgabor        continue;
221219019Sgabor
222219019Sgabor      case NestedNameSpecifier::TypeSpec:
223219019Sgabor      case NestedNameSpecifier::TypeSpecWithTemplate:
224219019Sgabor        asImpl().writeQualType(QualType(NNS->getAsType(), 0));
225219019Sgabor        continue;
226219019Sgabor
227219019Sgabor      case NestedNameSpecifier::Global:
228219019Sgabor        // Don't need to write an associated value.
229219019Sgabor        continue;
230219019Sgabor
231219019Sgabor      case NestedNameSpecifier::Super:
232219019Sgabor        asImpl().writeDeclRef(NNS->getAsRecordDecl());
233219019Sgabor        continue;
234219019Sgabor      }
235219019Sgabor      llvm_unreachable("bad nested name specifier kind");
236219019Sgabor    }
237219019Sgabor  }
238219019Sgabor};
239219019Sgabor
240219019Sgabor} // end namespace serialization
241219019Sgabor} // end namespace clang
242219019Sgabor
243219019Sgabor#endif
244219019Sgabor