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>
makeOptionalFromNullable(const T & value)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>
makeOptionalFromPointer(T * value)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.
find(const char * propertyName)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.
writeObject()134 Impl &writeObject() { return asImpl(); }
135
136 template <class T>
writeEnum(T value)137 void writeEnum(T value) {
138 asImpl().writeUInt32(uint32_t(value));
139 }
140
141 template <class T>
writeArray(llvm::ArrayRef<T> array)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>
writeOptional(llvm::Optional<T> value)150 void writeOptional(llvm::Optional<T> value) {
151 WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value));
152 }
153
writeAPSInt(const llvm::APSInt & value)154 void writeAPSInt(const llvm::APSInt &value) {
155 asImpl().writeBool(value.isUnsigned());
156 asImpl().writeAPInt(value);
157 }
158
writeAPInt(const llvm::APInt & value)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
writeQualifiers(Qualifiers value)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
writeExceptionSpecInfo(const FunctionProtoType::ExceptionSpecInfo & esi)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
writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi)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
writeNestedNameSpecifier(NestedNameSpecifier * NNS)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