xref: /freebsd/contrib/llvm-project/clang/include/clang/AST/AbstractBasicWriter.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
writeArray(ArrayRef<T> array)141   template <class T> void writeArray(ArrayRef<T> array) {
142     asImpl().writeUInt32(array.size());
143     for (const T &elt : array) {
144       WriteDispatcher<T>::write(asImpl(), elt);
145     }
146   }
147 
writeOptional(std::optional<T> value)148   template <class T> void writeOptional(std::optional<T> value) {
149     WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value));
150   }
151 
writeAPSInt(const llvm::APSInt & value)152   void writeAPSInt(const llvm::APSInt &value) {
153     asImpl().writeBool(value.isUnsigned());
154     asImpl().writeAPInt(value);
155   }
156 
writeAPInt(const llvm::APInt & value)157   void writeAPInt(const llvm::APInt &value) {
158     asImpl().writeUInt32(value.getBitWidth());
159     const uint64_t *words = value.getRawData();
160     for (size_t i = 0, e = value.getNumWords(); i != e; ++i)
161       asImpl().writeUInt64(words[i]);
162   }
163 
writeFixedPointSemantics(const llvm::FixedPointSemantics & sema)164   void writeFixedPointSemantics(const llvm::FixedPointSemantics &sema) {
165     asImpl().writeUInt32(sema.getWidth());
166     asImpl().writeUInt32(sema.getScale());
167     asImpl().writeUInt32(sema.isSigned() | sema.isSaturated() << 1 |
168                          sema.hasUnsignedPadding() << 2);
169   }
170 
writeLValuePathSerializationHelper(APValue::LValuePathSerializationHelper lvaluePath)171   void writeLValuePathSerializationHelper(
172       APValue::LValuePathSerializationHelper lvaluePath) {
173     ArrayRef<APValue::LValuePathEntry> path = lvaluePath.Path;
174     QualType elemTy = lvaluePath.getType();
175     asImpl().writeQualType(elemTy);
176     asImpl().writeUInt32(path.size());
177     auto &ctx = ((BasicWriterBase<Impl> *)this)->getASTContext();
178     for (auto elem : path) {
179       if (elemTy->getAs<RecordType>()) {
180         asImpl().writeUInt32(elem.getAsBaseOrMember().getInt());
181         const Decl *baseOrMember = elem.getAsBaseOrMember().getPointer();
182         if (const auto *recordDecl = dyn_cast<CXXRecordDecl>(baseOrMember)) {
183           asImpl().writeDeclRef(recordDecl);
184           elemTy = ctx.getRecordType(recordDecl);
185         } else {
186           const auto *valueDecl = cast<ValueDecl>(baseOrMember);
187           asImpl().writeDeclRef(valueDecl);
188           elemTy = valueDecl->getType();
189         }
190       } else {
191         asImpl().writeUInt32(elem.getAsArrayIndex());
192         elemTy = ctx.getAsArrayType(elemTy)->getElementType();
193       }
194     }
195   }
196 
writeQualifiers(Qualifiers value)197   void writeQualifiers(Qualifiers value) {
198     static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint64_t),
199                   "update this if the value size changes");
200     asImpl().writeUInt64(value.getAsOpaqueValue());
201   }
202 
writeExceptionSpecInfo(const FunctionProtoType::ExceptionSpecInfo & esi)203   void writeExceptionSpecInfo(
204                         const FunctionProtoType::ExceptionSpecInfo &esi) {
205     asImpl().writeUInt32(uint32_t(esi.Type));
206     if (esi.Type == EST_Dynamic) {
207       asImpl().writeArray(esi.Exceptions);
208     } else if (isComputedNoexcept(esi.Type)) {
209       asImpl().writeExprRef(esi.NoexceptExpr);
210     } else if (esi.Type == EST_Uninstantiated) {
211       asImpl().writeDeclRef(esi.SourceDecl);
212       asImpl().writeDeclRef(esi.SourceTemplate);
213     } else if (esi.Type == EST_Unevaluated) {
214       asImpl().writeDeclRef(esi.SourceDecl);
215     }
216   }
217 
writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi)218   void writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi) {
219     static_assert(sizeof(epi.getOpaqueValue()) <= sizeof(uint32_t),
220                   "opaque value doesn't fit into uint32_t");
221     asImpl().writeUInt32(epi.getOpaqueValue());
222   }
223 
writeFunctionEffect(FunctionEffect E)224   void writeFunctionEffect(FunctionEffect E) {
225     asImpl().writeUInt32(E.toOpaqueInt32());
226   }
227 
writeEffectConditionExpr(EffectConditionExpr CE)228   void writeEffectConditionExpr(EffectConditionExpr CE) {
229     asImpl().writeExprRef(CE.getCondition());
230   }
231 
writeNestedNameSpecifier(NestedNameSpecifier * NNS)232   void writeNestedNameSpecifier(NestedNameSpecifier *NNS) {
233     // Nested name specifiers usually aren't too long. I think that 8 would
234     // typically accommodate the vast majority.
235     SmallVector<NestedNameSpecifier *, 8> nestedNames;
236 
237     // Push each of the NNS's onto a stack for serialization in reverse order.
238     while (NNS) {
239       nestedNames.push_back(NNS);
240       NNS = NNS->getPrefix();
241     }
242 
243     asImpl().writeUInt32(nestedNames.size());
244     while (!nestedNames.empty()) {
245       NNS = nestedNames.pop_back_val();
246       NestedNameSpecifier::SpecifierKind kind = NNS->getKind();
247       asImpl().writeNestedNameSpecifierKind(kind);
248       switch (kind) {
249       case NestedNameSpecifier::Identifier:
250         asImpl().writeIdentifier(NNS->getAsIdentifier());
251         continue;
252 
253       case NestedNameSpecifier::Namespace:
254         asImpl().writeNamespaceDeclRef(NNS->getAsNamespace());
255         continue;
256 
257       case NestedNameSpecifier::NamespaceAlias:
258         asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias());
259         continue;
260 
261       case NestedNameSpecifier::TypeSpec:
262         asImpl().writeQualType(QualType(NNS->getAsType(), 0));
263         continue;
264 
265       case NestedNameSpecifier::Global:
266         // Don't need to write an associated value.
267         continue;
268 
269       case NestedNameSpecifier::Super:
270         asImpl().writeDeclRef(NNS->getAsRecordDecl());
271         continue;
272       }
273       llvm_unreachable("bad nested name specifier kind");
274     }
275   }
276 };
277 
278 } // end namespace serialization
279 } // end namespace clang
280 
281 #endif
282