1480093f4SDimitry Andric //==--- AbstractBasicWriter.h - Abstract basic value serialization --------===//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric 
904eeddc0SDimitry Andric #ifndef LLVM_CLANG_AST_ABSTRACTBASICWRITER_H
1004eeddc0SDimitry Andric #define LLVM_CLANG_AST_ABSTRACTBASICWRITER_H
11480093f4SDimitry Andric 
12e8d8bef9SDimitry Andric #include "clang/AST/ASTContext.h"
13480093f4SDimitry Andric #include "clang/AST/DeclTemplate.h"
14*bdd1243dSDimitry Andric #include <optional>
15480093f4SDimitry Andric 
16480093f4SDimitry Andric namespace clang {
17480093f4SDimitry Andric namespace serialization {
18480093f4SDimitry Andric 
19480093f4SDimitry Andric template <class T>
makeOptionalFromNullable(const T & value)20*bdd1243dSDimitry Andric inline std::optional<T> makeOptionalFromNullable(const T &value) {
21*bdd1243dSDimitry Andric   return (value.isNull() ? std::optional<T>() : std::optional<T>(value));
22480093f4SDimitry Andric }
23480093f4SDimitry Andric 
makeOptionalFromPointer(T * value)24*bdd1243dSDimitry Andric template <class T> inline std::optional<T *> makeOptionalFromPointer(T *value) {
25*bdd1243dSDimitry Andric   return (value ? std::optional<T *>(value) : std::optional<T *>());
26480093f4SDimitry Andric }
27480093f4SDimitry Andric 
28480093f4SDimitry Andric // PropertyWriter is a class concept that requires the following method:
29480093f4SDimitry Andric //   BasicWriter find(llvm::StringRef propertyName);
30480093f4SDimitry Andric // where BasicWriter is some class conforming to the BasicWriter concept.
31480093f4SDimitry Andric // An abstract AST-node writer is created with a PropertyWriter and
32480093f4SDimitry Andric // performs a sequence of calls like so:
33480093f4SDimitry Andric //   propertyWriter.find(propertyName).write##TypeName(value)
34480093f4SDimitry Andric // to write the properties of the node it is serializing.
35480093f4SDimitry Andric 
36480093f4SDimitry Andric // BasicWriter is a class concept that requires methods like:
37480093f4SDimitry Andric //   void write##TypeName(ValueType value);
38480093f4SDimitry Andric // where TypeName is the name of a PropertyType node from PropertiesBase.td
39480093f4SDimitry Andric // and ValueType is the corresponding C++ type name.
40480093f4SDimitry Andric //
41480093f4SDimitry Andric // In addition to the concrete property types, BasicWriter is expected
42480093f4SDimitry Andric // to implement these methods:
43480093f4SDimitry Andric //
44480093f4SDimitry Andric //   template <class EnumType>
45480093f4SDimitry Andric //   void writeEnum(T value);
46480093f4SDimitry Andric //
47480093f4SDimitry Andric //     Writes an enum value as the current property.  EnumType will always
48480093f4SDimitry Andric //     be an enum type.  Only necessary if the BasicWriter doesn't provide
49480093f4SDimitry Andric //     type-specific writers for all the enum types.
50480093f4SDimitry Andric //
51480093f4SDimitry Andric //   template <class ValueType>
52*bdd1243dSDimitry Andric //   void writeOptional(std::optional<ValueType> value);
53480093f4SDimitry Andric //
54480093f4SDimitry Andric //     Writes an optional value as the current property.
55480093f4SDimitry Andric //
56480093f4SDimitry Andric //   template <class ValueType>
57480093f4SDimitry Andric //   void writeArray(ArrayRef<ValueType> value);
58480093f4SDimitry Andric //
59480093f4SDimitry Andric //     Writes an array of values as the current property.
60480093f4SDimitry Andric //
61480093f4SDimitry Andric //   PropertyWriter writeObject();
62480093f4SDimitry Andric //
63480093f4SDimitry Andric //     Writes an object as the current property; the returned property
64480093f4SDimitry Andric //     writer will be subjected to a sequence of property writes and then
65480093f4SDimitry Andric //     discarded before any other properties are written to the "outer"
66480093f4SDimitry Andric //     property writer (which need not be the same type).  The sub-writer
67480093f4SDimitry Andric //     will be used as if with the following code:
68480093f4SDimitry Andric //
69480093f4SDimitry Andric //       {
70480093f4SDimitry Andric //         auto &&widget = W.find("widget").writeObject();
71480093f4SDimitry Andric //         widget.find("kind").writeWidgetKind(...);
72480093f4SDimitry Andric //         widget.find("declaration").writeDeclRef(...);
73480093f4SDimitry Andric //       }
74480093f4SDimitry Andric 
75480093f4SDimitry Andric // WriteDispatcher is a template which does type-based forwarding to one
76480093f4SDimitry Andric // of the write methods of the BasicWriter passed in:
77480093f4SDimitry Andric //
78480093f4SDimitry Andric // template <class ValueType>
79480093f4SDimitry Andric // struct WriteDispatcher {
80480093f4SDimitry Andric //   template <class BasicWriter>
81480093f4SDimitry Andric //   static void write(BasicWriter &W, ValueType value);
82480093f4SDimitry Andric // };
83480093f4SDimitry Andric 
84480093f4SDimitry Andric // BasicWriterBase provides convenience implementations of the write
85480093f4SDimitry Andric // methods for EnumPropertyType and SubclassPropertyType types that just
86480093f4SDimitry Andric // defer to the "underlying" implementations (for UInt32 and the base class,
87480093f4SDimitry Andric // respectively).
88480093f4SDimitry Andric //
89480093f4SDimitry Andric // template <class Impl>
90480093f4SDimitry Andric // class BasicWriterBase {
91480093f4SDimitry Andric // protected:
92480093f4SDimitry Andric //   Impl &asImpl();
93480093f4SDimitry Andric // public:
94480093f4SDimitry Andric //   ...
95480093f4SDimitry Andric // };
96480093f4SDimitry Andric 
97480093f4SDimitry Andric // The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp.
98480093f4SDimitry Andric #include "clang/AST/AbstractBasicWriter.inc"
99480093f4SDimitry Andric 
100480093f4SDimitry Andric /// DataStreamBasicWriter provides convenience implementations for many
101480093f4SDimitry Andric /// BasicWriter methods based on the assumption that the
102480093f4SDimitry Andric /// ultimate writer implementation is based on a variable-length stream
103480093f4SDimitry Andric /// of unstructured data (like Clang's module files).  It is designed
104480093f4SDimitry Andric /// to pair with DataStreamBasicReader.
105480093f4SDimitry Andric ///
106480093f4SDimitry Andric /// This class can also act as a PropertyWriter, implementing find("...")
107480093f4SDimitry Andric /// by simply forwarding to itself.
108480093f4SDimitry Andric ///
109480093f4SDimitry Andric /// Unimplemented methods:
110480093f4SDimitry Andric ///   writeBool
111480093f4SDimitry Andric ///   writeUInt32
112480093f4SDimitry Andric ///   writeUInt64
113480093f4SDimitry Andric ///   writeIdentifier
114480093f4SDimitry Andric ///   writeSelector
115480093f4SDimitry Andric ///   writeSourceLocation
116480093f4SDimitry Andric ///   writeQualType
117480093f4SDimitry Andric ///   writeStmtRef
118480093f4SDimitry Andric ///   writeDeclRef
119480093f4SDimitry Andric template <class Impl>
120480093f4SDimitry Andric class DataStreamBasicWriter : public BasicWriterBase<Impl> {
121480093f4SDimitry Andric protected:
122480093f4SDimitry Andric   using BasicWriterBase<Impl>::asImpl;
DataStreamBasicWriter(ASTContext & ctx)123e8d8bef9SDimitry Andric   DataStreamBasicWriter(ASTContext &ctx) : BasicWriterBase<Impl>(ctx) {}
124480093f4SDimitry Andric 
125480093f4SDimitry Andric public:
126480093f4SDimitry Andric   /// Implement property-find by ignoring it.  We rely on properties being
127480093f4SDimitry Andric   /// serialized and deserialized in a reliable order instead.
find(const char * propertyName)128480093f4SDimitry Andric   Impl &find(const char *propertyName) {
129480093f4SDimitry Andric     return asImpl();
130480093f4SDimitry Andric   }
131480093f4SDimitry Andric 
132480093f4SDimitry Andric   // Implement object writing by forwarding to this, collapsing the
133480093f4SDimitry Andric   // structure into a single data stream.
writeObject()134480093f4SDimitry Andric   Impl &writeObject() { return asImpl(); }
135480093f4SDimitry Andric 
136480093f4SDimitry Andric   template <class T>
writeEnum(T value)137480093f4SDimitry Andric   void writeEnum(T value) {
138480093f4SDimitry Andric     asImpl().writeUInt32(uint32_t(value));
139480093f4SDimitry Andric   }
140480093f4SDimitry Andric 
141480093f4SDimitry Andric   template <class T>
writeArray(llvm::ArrayRef<T> array)142480093f4SDimitry Andric   void writeArray(llvm::ArrayRef<T> array) {
143480093f4SDimitry Andric     asImpl().writeUInt32(array.size());
144480093f4SDimitry Andric     for (const T &elt : array) {
145480093f4SDimitry Andric       WriteDispatcher<T>::write(asImpl(), elt);
146480093f4SDimitry Andric     }
147480093f4SDimitry Andric   }
148480093f4SDimitry Andric 
writeOptional(std::optional<T> value)149*bdd1243dSDimitry Andric   template <class T> void writeOptional(std::optional<T> value) {
150480093f4SDimitry Andric     WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value));
151480093f4SDimitry Andric   }
152480093f4SDimitry Andric 
writeAPSInt(const llvm::APSInt & value)153480093f4SDimitry Andric   void writeAPSInt(const llvm::APSInt &value) {
154480093f4SDimitry Andric     asImpl().writeBool(value.isUnsigned());
155480093f4SDimitry Andric     asImpl().writeAPInt(value);
156480093f4SDimitry Andric   }
157480093f4SDimitry Andric 
writeAPInt(const llvm::APInt & value)158480093f4SDimitry Andric   void writeAPInt(const llvm::APInt &value) {
159480093f4SDimitry Andric     asImpl().writeUInt32(value.getBitWidth());
160480093f4SDimitry Andric     const uint64_t *words = value.getRawData();
161480093f4SDimitry Andric     for (size_t i = 0, e = value.getNumWords(); i != e; ++i)
162480093f4SDimitry Andric       asImpl().writeUInt64(words[i]);
163480093f4SDimitry Andric   }
164480093f4SDimitry Andric 
writeFixedPointSemantics(const llvm::FixedPointSemantics & sema)165e8d8bef9SDimitry Andric   void writeFixedPointSemantics(const llvm::FixedPointSemantics &sema) {
166e8d8bef9SDimitry Andric     asImpl().writeUInt32(sema.getWidth());
167e8d8bef9SDimitry Andric     asImpl().writeUInt32(sema.getScale());
168e8d8bef9SDimitry Andric     asImpl().writeUInt32(sema.isSigned() | sema.isSaturated() << 1 |
169e8d8bef9SDimitry Andric                          sema.hasUnsignedPadding() << 2);
170e8d8bef9SDimitry Andric   }
171e8d8bef9SDimitry Andric 
writeLValuePathSerializationHelper(APValue::LValuePathSerializationHelper lvaluePath)172e8d8bef9SDimitry Andric   void writeLValuePathSerializationHelper(
173e8d8bef9SDimitry Andric       APValue::LValuePathSerializationHelper lvaluePath) {
174e8d8bef9SDimitry Andric     ArrayRef<APValue::LValuePathEntry> path = lvaluePath.Path;
175e8d8bef9SDimitry Andric     QualType elemTy = lvaluePath.getType();
176e8d8bef9SDimitry Andric     asImpl().writeQualType(elemTy);
177e8d8bef9SDimitry Andric     asImpl().writeUInt32(path.size());
178e8d8bef9SDimitry Andric     auto &ctx = ((BasicWriterBase<Impl> *)this)->getASTContext();
179e8d8bef9SDimitry Andric     for (auto elem : path) {
180e8d8bef9SDimitry Andric       if (elemTy->getAs<RecordType>()) {
181e8d8bef9SDimitry Andric         asImpl().writeUInt32(elem.getAsBaseOrMember().getInt());
182e8d8bef9SDimitry Andric         const Decl *baseOrMember = elem.getAsBaseOrMember().getPointer();
183e8d8bef9SDimitry Andric         if (const auto *recordDecl = dyn_cast<CXXRecordDecl>(baseOrMember)) {
184e8d8bef9SDimitry Andric           asImpl().writeDeclRef(recordDecl);
185e8d8bef9SDimitry Andric           elemTy = ctx.getRecordType(recordDecl);
186e8d8bef9SDimitry Andric         } else {
187e8d8bef9SDimitry Andric           const auto *valueDecl = cast<ValueDecl>(baseOrMember);
188e8d8bef9SDimitry Andric           asImpl().writeDeclRef(valueDecl);
189e8d8bef9SDimitry Andric           elemTy = valueDecl->getType();
190e8d8bef9SDimitry Andric         }
191e8d8bef9SDimitry Andric       } else {
192e8d8bef9SDimitry Andric         asImpl().writeUInt32(elem.getAsArrayIndex());
193e8d8bef9SDimitry Andric         elemTy = ctx.getAsArrayType(elemTy)->getElementType();
194e8d8bef9SDimitry Andric       }
195e8d8bef9SDimitry Andric     }
196e8d8bef9SDimitry Andric   }
197e8d8bef9SDimitry Andric 
writeQualifiers(Qualifiers value)198480093f4SDimitry Andric   void writeQualifiers(Qualifiers value) {
199480093f4SDimitry Andric     static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t),
200480093f4SDimitry Andric                   "update this if the value size changes");
201480093f4SDimitry Andric     asImpl().writeUInt32(value.getAsOpaqueValue());
202480093f4SDimitry Andric   }
203480093f4SDimitry Andric 
writeExceptionSpecInfo(const FunctionProtoType::ExceptionSpecInfo & esi)204480093f4SDimitry Andric   void writeExceptionSpecInfo(
205480093f4SDimitry Andric                         const FunctionProtoType::ExceptionSpecInfo &esi) {
206480093f4SDimitry Andric     asImpl().writeUInt32(uint32_t(esi.Type));
207480093f4SDimitry Andric     if (esi.Type == EST_Dynamic) {
208480093f4SDimitry Andric       asImpl().writeArray(esi.Exceptions);
209480093f4SDimitry Andric     } else if (isComputedNoexcept(esi.Type)) {
210480093f4SDimitry Andric       asImpl().writeExprRef(esi.NoexceptExpr);
211480093f4SDimitry Andric     } else if (esi.Type == EST_Uninstantiated) {
212480093f4SDimitry Andric       asImpl().writeDeclRef(esi.SourceDecl);
213480093f4SDimitry Andric       asImpl().writeDeclRef(esi.SourceTemplate);
214480093f4SDimitry Andric     } else if (esi.Type == EST_Unevaluated) {
215480093f4SDimitry Andric       asImpl().writeDeclRef(esi.SourceDecl);
216480093f4SDimitry Andric     }
217480093f4SDimitry Andric   }
218480093f4SDimitry Andric 
writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi)219480093f4SDimitry Andric   void writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi) {
220480093f4SDimitry Andric     static_assert(sizeof(epi.getOpaqueValue()) <= sizeof(uint32_t),
221480093f4SDimitry Andric                   "opaque value doesn't fit into uint32_t");
222480093f4SDimitry Andric     asImpl().writeUInt32(epi.getOpaqueValue());
223480093f4SDimitry Andric   }
224480093f4SDimitry Andric 
writeNestedNameSpecifier(NestedNameSpecifier * NNS)225480093f4SDimitry Andric   void writeNestedNameSpecifier(NestedNameSpecifier *NNS) {
226480093f4SDimitry Andric     // Nested name specifiers usually aren't too long. I think that 8 would
227480093f4SDimitry Andric     // typically accommodate the vast majority.
228480093f4SDimitry Andric     SmallVector<NestedNameSpecifier *, 8> nestedNames;
229480093f4SDimitry Andric 
230480093f4SDimitry Andric     // Push each of the NNS's onto a stack for serialization in reverse order.
231480093f4SDimitry Andric     while (NNS) {
232480093f4SDimitry Andric       nestedNames.push_back(NNS);
233480093f4SDimitry Andric       NNS = NNS->getPrefix();
234480093f4SDimitry Andric     }
235480093f4SDimitry Andric 
236480093f4SDimitry Andric     asImpl().writeUInt32(nestedNames.size());
237480093f4SDimitry Andric     while (!nestedNames.empty()) {
238480093f4SDimitry Andric       NNS = nestedNames.pop_back_val();
239480093f4SDimitry Andric       NestedNameSpecifier::SpecifierKind kind = NNS->getKind();
240480093f4SDimitry Andric       asImpl().writeNestedNameSpecifierKind(kind);
241480093f4SDimitry Andric       switch (kind) {
242480093f4SDimitry Andric       case NestedNameSpecifier::Identifier:
243480093f4SDimitry Andric         asImpl().writeIdentifier(NNS->getAsIdentifier());
244480093f4SDimitry Andric         continue;
245480093f4SDimitry Andric 
246480093f4SDimitry Andric       case NestedNameSpecifier::Namespace:
247480093f4SDimitry Andric         asImpl().writeNamespaceDeclRef(NNS->getAsNamespace());
248480093f4SDimitry Andric         continue;
249480093f4SDimitry Andric 
250480093f4SDimitry Andric       case NestedNameSpecifier::NamespaceAlias:
251480093f4SDimitry Andric         asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias());
252480093f4SDimitry Andric         continue;
253480093f4SDimitry Andric 
254480093f4SDimitry Andric       case NestedNameSpecifier::TypeSpec:
255480093f4SDimitry Andric       case NestedNameSpecifier::TypeSpecWithTemplate:
256480093f4SDimitry Andric         asImpl().writeQualType(QualType(NNS->getAsType(), 0));
257480093f4SDimitry Andric         continue;
258480093f4SDimitry Andric 
259480093f4SDimitry Andric       case NestedNameSpecifier::Global:
260480093f4SDimitry Andric         // Don't need to write an associated value.
261480093f4SDimitry Andric         continue;
262480093f4SDimitry Andric 
263480093f4SDimitry Andric       case NestedNameSpecifier::Super:
264480093f4SDimitry Andric         asImpl().writeDeclRef(NNS->getAsRecordDecl());
265480093f4SDimitry Andric         continue;
266480093f4SDimitry Andric       }
267480093f4SDimitry Andric       llvm_unreachable("bad nested name specifier kind");
268480093f4SDimitry Andric     }
269480093f4SDimitry Andric   }
270480093f4SDimitry Andric };
271480093f4SDimitry Andric 
272480093f4SDimitry Andric } // end namespace serialization
273480093f4SDimitry Andric } // end namespace clang
274480093f4SDimitry Andric 
275480093f4SDimitry Andric #endif
276