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