xref: /freebsd/contrib/llvm-project/clang/include/clang/AST/AbstractBasicWriter.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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