1 //==--- AbstractBasicWriter.h - Abstract basic value serialization --------===//
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_ABSTRACTBASICWRITER_H
10 #define CLANG_AST_ABSTRACTBASICWRITER_H
11 
12 #include "clang/AST/DeclTemplate.h"
13 
14 namespace clang {
15 namespace serialization {
16 
17 template <class T>
18 inline llvm::Optional<T> makeOptionalFromNullable(const T &value) {
19   return (value.isNull()
20             ? llvm::Optional<T>()
21             : llvm::Optional<T>(value));
22 }
23 
24 template <class T>
25 inline llvm::Optional<T*> makeOptionalFromPointer(T *value) {
26   return (value ? llvm::Optional<T*>(value) : llvm::Optional<T*>());
27 }
28 
29 // PropertyWriter is a class concept that requires the following method:
30 //   BasicWriter find(llvm::StringRef propertyName);
31 // where BasicWriter is some class conforming to the BasicWriter concept.
32 // An abstract AST-node writer is created with a PropertyWriter and
33 // performs a sequence of calls like so:
34 //   propertyWriter.find(propertyName).write##TypeName(value)
35 // to write the properties of the node it is serializing.
36 
37 // BasicWriter is a class concept that requires methods like:
38 //   void write##TypeName(ValueType value);
39 // where TypeName is the name of a PropertyType node from PropertiesBase.td
40 // and ValueType is the corresponding C++ type name.
41 //
42 // In addition to the concrete property types, BasicWriter is expected
43 // to implement these methods:
44 //
45 //   template <class EnumType>
46 //   void writeEnum(T value);
47 //
48 //     Writes an enum value as the current property.  EnumType will always
49 //     be an enum type.  Only necessary if the BasicWriter doesn't provide
50 //     type-specific writers for all the enum types.
51 //
52 //   template <class ValueType>
53 //   void writeOptional(Optional<ValueType> value);
54 //
55 //     Writes an optional value as the current property.
56 //
57 //   template <class ValueType>
58 //   void writeArray(ArrayRef<ValueType> value);
59 //
60 //     Writes an array of values as the current property.
61 //
62 //   PropertyWriter writeObject();
63 //
64 //     Writes an object as the current property; the returned property
65 //     writer will be subjected to a sequence of property writes and then
66 //     discarded before any other properties are written to the "outer"
67 //     property writer (which need not be the same type).  The sub-writer
68 //     will be used as if with the following code:
69 //
70 //       {
71 //         auto &&widget = W.find("widget").writeObject();
72 //         widget.find("kind").writeWidgetKind(...);
73 //         widget.find("declaration").writeDeclRef(...);
74 //       }
75 
76 // WriteDispatcher is a template which does type-based forwarding to one
77 // of the write methods of the BasicWriter passed in:
78 //
79 // template <class ValueType>
80 // struct WriteDispatcher {
81 //   template <class BasicWriter>
82 //   static void write(BasicWriter &W, ValueType value);
83 // };
84 
85 // BasicWriterBase provides convenience implementations of the write
86 // methods for EnumPropertyType and SubclassPropertyType types that just
87 // defer to the "underlying" implementations (for UInt32 and the base class,
88 // respectively).
89 //
90 // template <class Impl>
91 // class BasicWriterBase {
92 // protected:
93 //   Impl &asImpl();
94 // public:
95 //   ...
96 // };
97 
98 // The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp.
99 #include "clang/AST/AbstractBasicWriter.inc"
100 
101 /// DataStreamBasicWriter provides convenience implementations for many
102 /// BasicWriter methods based on the assumption that the
103 /// ultimate writer implementation is based on a variable-length stream
104 /// of unstructured data (like Clang's module files).  It is designed
105 /// to pair with DataStreamBasicReader.
106 ///
107 /// This class can also act as a PropertyWriter, implementing find("...")
108 /// by simply forwarding to itself.
109 ///
110 /// Unimplemented methods:
111 ///   writeBool
112 ///   writeUInt32
113 ///   writeUInt64
114 ///   writeIdentifier
115 ///   writeSelector
116 ///   writeSourceLocation
117 ///   writeQualType
118 ///   writeStmtRef
119 ///   writeDeclRef
120 template <class Impl>
121 class DataStreamBasicWriter : public BasicWriterBase<Impl> {
122 protected:
123   using BasicWriterBase<Impl>::asImpl;
124 
125 public:
126   /// Implement property-find by ignoring it.  We rely on properties being
127   /// serialized and deserialized in a reliable order instead.
128   Impl &find(const char *propertyName) {
129     return asImpl();
130   }
131 
132   // Implement object writing by forwarding to this, collapsing the
133   // structure into a single data stream.
134   Impl &writeObject() { return asImpl(); }
135 
136   template <class T>
137   void writeEnum(T value) {
138     asImpl().writeUInt32(uint32_t(value));
139   }
140 
141   template <class T>
142   void writeArray(llvm::ArrayRef<T> array) {
143     asImpl().writeUInt32(array.size());
144     for (const T &elt : array) {
145       WriteDispatcher<T>::write(asImpl(), elt);
146     }
147   }
148 
149   template <class T>
150   void writeOptional(llvm::Optional<T> value) {
151     WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value));
152   }
153 
154   void writeAPSInt(const llvm::APSInt &value) {
155     asImpl().writeBool(value.isUnsigned());
156     asImpl().writeAPInt(value);
157   }
158 
159   void writeAPInt(const llvm::APInt &value) {
160     asImpl().writeUInt32(value.getBitWidth());
161     const uint64_t *words = value.getRawData();
162     for (size_t i = 0, e = value.getNumWords(); i != e; ++i)
163       asImpl().writeUInt64(words[i]);
164   }
165 
166   void writeQualifiers(Qualifiers value) {
167     static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t),
168                   "update this if the value size changes");
169     asImpl().writeUInt32(value.getAsOpaqueValue());
170   }
171 
172   void writeExceptionSpecInfo(
173                         const FunctionProtoType::ExceptionSpecInfo &esi) {
174     asImpl().writeUInt32(uint32_t(esi.Type));
175     if (esi.Type == EST_Dynamic) {
176       asImpl().writeArray(esi.Exceptions);
177     } else if (isComputedNoexcept(esi.Type)) {
178       asImpl().writeExprRef(esi.NoexceptExpr);
179     } else if (esi.Type == EST_Uninstantiated) {
180       asImpl().writeDeclRef(esi.SourceDecl);
181       asImpl().writeDeclRef(esi.SourceTemplate);
182     } else if (esi.Type == EST_Unevaluated) {
183       asImpl().writeDeclRef(esi.SourceDecl);
184     }
185   }
186 
187   void writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi) {
188     static_assert(sizeof(epi.getOpaqueValue()) <= sizeof(uint32_t),
189                   "opaque value doesn't fit into uint32_t");
190     asImpl().writeUInt32(epi.getOpaqueValue());
191   }
192 
193   void writeNestedNameSpecifier(NestedNameSpecifier *NNS) {
194     // Nested name specifiers usually aren't too long. I think that 8 would
195     // typically accommodate the vast majority.
196     SmallVector<NestedNameSpecifier *, 8> nestedNames;
197 
198     // Push each of the NNS's onto a stack for serialization in reverse order.
199     while (NNS) {
200       nestedNames.push_back(NNS);
201       NNS = NNS->getPrefix();
202     }
203 
204     asImpl().writeUInt32(nestedNames.size());
205     while (!nestedNames.empty()) {
206       NNS = nestedNames.pop_back_val();
207       NestedNameSpecifier::SpecifierKind kind = NNS->getKind();
208       asImpl().writeNestedNameSpecifierKind(kind);
209       switch (kind) {
210       case NestedNameSpecifier::Identifier:
211         asImpl().writeIdentifier(NNS->getAsIdentifier());
212         continue;
213 
214       case NestedNameSpecifier::Namespace:
215         asImpl().writeNamespaceDeclRef(NNS->getAsNamespace());
216         continue;
217 
218       case NestedNameSpecifier::NamespaceAlias:
219         asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias());
220         continue;
221 
222       case NestedNameSpecifier::TypeSpec:
223       case NestedNameSpecifier::TypeSpecWithTemplate:
224         asImpl().writeQualType(QualType(NNS->getAsType(), 0));
225         continue;
226 
227       case NestedNameSpecifier::Global:
228         // Don't need to write an associated value.
229         continue;
230 
231       case NestedNameSpecifier::Super:
232         asImpl().writeDeclRef(NNS->getAsRecordDecl());
233         continue;
234       }
235       llvm_unreachable("bad nested name specifier kind");
236     }
237   }
238 };
239 
240 } // end namespace serialization
241 } // end namespace clang
242 
243 #endif
244