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