1 //==--- AbstractBasicWriter.h - Abstract basic value serialization --------===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef CLANG_AST_ABSTRACTBASICWRITER_H
10 #define CLANG_AST_ABSTRACTBASICWRITER_H
12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/DeclTemplate.h"
16 namespace serialization {
19 inline llvm::Optional<T> makeOptionalFromNullable(const T &value) {
20 return (value.isNull()
22 : llvm::Optional<T>(value));
26 inline llvm::Optional<T*> makeOptionalFromPointer(T *value) {
27 return (value ? llvm::Optional<T*>(value) : llvm::Optional<T*>());
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.
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.
43 // In addition to the concrete property types, BasicWriter is expected
44 // to implement these methods:
46 // template <class EnumType>
47 // void writeEnum(T value);
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.
53 // template <class ValueType>
54 // void writeOptional(Optional<ValueType> value);
56 // Writes an optional value as the current property.
58 // template <class ValueType>
59 // void writeArray(ArrayRef<ValueType> value);
61 // Writes an array of values as the current property.
63 // PropertyWriter writeObject();
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:
72 // auto &&widget = W.find("widget").writeObject();
73 // widget.find("kind").writeWidgetKind(...);
74 // widget.find("declaration").writeDeclRef(...);
77 // WriteDispatcher is a template which does type-based forwarding to one
78 // of the write methods of the BasicWriter passed in:
80 // template <class ValueType>
81 // struct WriteDispatcher {
82 // template <class BasicWriter>
83 // static void write(BasicWriter &W, ValueType value);
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,
91 // template <class Impl>
92 // class BasicWriterBase {
99 // The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp.
100 #include "clang/AST/AbstractBasicWriter.inc"
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.
108 /// This class can also act as a PropertyWriter, implementing find("...")
109 /// by simply forwarding to itself.
111 /// Unimplemented methods:
117 /// writeSourceLocation
121 template <class Impl>
122 class DataStreamBasicWriter : public BasicWriterBase<Impl> {
124 using BasicWriterBase<Impl>::asImpl;
125 DataStreamBasicWriter(ASTContext &ctx) : BasicWriterBase<Impl>(ctx) {}
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) {
134 // Implement object writing by forwarding to this, collapsing the
135 // structure into a single data stream.
136 Impl &writeObject() { return asImpl(); }
139 void writeEnum(T value) {
140 asImpl().writeUInt32(uint32_t(value));
144 void writeArray(llvm::ArrayRef<T> array) {
145 asImpl().writeUInt32(array.size());
146 for (const T &elt : array) {
147 WriteDispatcher<T>::write(asImpl(), elt);
152 void writeOptional(llvm::Optional<T> value) {
153 WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value));
156 void writeAPSInt(const llvm::APSInt &value) {
157 asImpl().writeBool(value.isUnsigned());
158 asImpl().writeAPInt(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]);
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);
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);
190 const auto *valueDecl = cast<ValueDecl>(baseOrMember);
191 asImpl().writeDeclRef(valueDecl);
192 elemTy = valueDecl->getType();
195 asImpl().writeUInt32(elem.getAsArrayIndex());
196 elemTy = ctx.getAsArrayType(elemTy)->getElementType();
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());
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);
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());
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;
233 // Push each of the NNS's onto a stack for serialization in reverse order.
235 nestedNames.push_back(NNS);
236 NNS = NNS->getPrefix();
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);
245 case NestedNameSpecifier::Identifier:
246 asImpl().writeIdentifier(NNS->getAsIdentifier());
249 case NestedNameSpecifier::Namespace:
250 asImpl().writeNamespaceDeclRef(NNS->getAsNamespace());
253 case NestedNameSpecifier::NamespaceAlias:
254 asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias());
257 case NestedNameSpecifier::TypeSpec:
258 case NestedNameSpecifier::TypeSpecWithTemplate:
259 asImpl().writeQualType(QualType(NNS->getAsType(), 0));
262 case NestedNameSpecifier::Global:
263 // Don't need to write an associated value.
266 case NestedNameSpecifier::Super:
267 asImpl().writeDeclRef(NNS->getAsRecordDecl());
270 llvm_unreachable("bad nested name specifier kind");
275 } // end namespace serialization
276 } // end namespace clang