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