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/ASTContext.h"
13 #include "clang/AST/DeclTemplate.h"
14
15 namespace clang {
16 namespace serialization {
17
18 template <class T>
makeOptionalFromNullable(const T & value)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>
makeOptionalFromPointer(T * value)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;
DataStreamBasicWriter(ASTContext & ctx)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.
find(const char * propertyName)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.
writeObject()136 Impl &writeObject() { return asImpl(); }
137
138 template <class T>
writeEnum(T value)139 void writeEnum(T value) {
140 asImpl().writeUInt32(uint32_t(value));
141 }
142
143 template <class T>
writeArray(llvm::ArrayRef<T> array)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>
writeOptional(llvm::Optional<T> value)152 void writeOptional(llvm::Optional<T> value) {
153 WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value));
154 }
155
writeAPSInt(const llvm::APSInt & value)156 void writeAPSInt(const llvm::APSInt &value) {
157 asImpl().writeBool(value.isUnsigned());
158 asImpl().writeAPInt(value);
159 }
160
writeAPInt(const llvm::APInt & value)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
writeFixedPointSemantics(const llvm::FixedPointSemantics & sema)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
writeLValuePathSerializationHelper(APValue::LValuePathSerializationHelper lvaluePath)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
writeQualifiers(Qualifiers value)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
writeExceptionSpecInfo(const FunctionProtoType::ExceptionSpecInfo & esi)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
writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi)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
writeNestedNameSpecifier(NestedNameSpecifier * NNS)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