clang 20.0.0git
AbstractBasicWriter.h
Go to the documentation of this file.
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
14#include <optional>
15
16namespace clang {
17namespace serialization {
18
19template <class T>
20inline std::optional<T> makeOptionalFromNullable(const T &value) {
21 return (value.isNull() ? std::optional<T>() : std::optional<T>(value));
22}
23
24template <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
119template <class Impl>
120class DataStreamBasicWriter : public BasicWriterBase<Impl> {
121protected:
122 using BasicWriterBase<Impl>::asImpl;
123 DataStreamBasicWriter(ASTContext &ctx) : BasicWriterBase<Impl>(ctx) {}
124
125public:
126 /// Implement property-find by ignoring it. We rely on properties being
127 /// serialized and deserialized in a reliable order instead.
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.
134 Impl &writeObject() { return asImpl(); }
135
136 template <class T>
137 void writeEnum(T value) {
138 asImpl().writeUInt32(uint32_t(value));
139 }
140
141 template <class T>
143 asImpl().writeUInt32(array.size());
144 for (const T &elt : array) {
145 WriteDispatcher<T>::write(asImpl(), elt);
146 }
147 }
148
149 template <class T> void writeOptional(std::optional<T> value) {
150 WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value));
151 }
152
153 void writeAPSInt(const llvm::APSInt &value) {
154 asImpl().writeBool(value.isUnsigned());
155 asImpl().writeAPInt(value);
156 }
157
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
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
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
199 static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint64_t),
200 "update this if the value size changes");
201 asImpl().writeUInt64(value.getAsOpaqueValue());
202 }
203
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
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
226 asImpl().writeUInt32(E.toOpaqueInt32());
227 }
228
230 asImpl().writeExprRef(CE.getCondition());
231 }
232
234 // Nested name specifiers usually aren't too long. I think that 8 would
235 // typically accommodate the vast majority.
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();
248 asImpl().writeNestedNameSpecifierKind(kind);
249 switch (kind) {
251 asImpl().writeIdentifier(NNS->getAsIdentifier());
252 continue;
253
255 asImpl().writeNamespaceDeclRef(NNS->getAsNamespace());
256 continue;
257
259 asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias());
260 continue;
261
264 asImpl().writeQualType(QualType(NNS->getAsType(), 0));
265 continue;
266
268 // Don't need to write an associated value.
269 continue;
270
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
Defines the clang::ASTContext interface.
Expr * E
Defines the C++ template declaration subclasses.
ArrayRef< LValuePathEntry > Path
Definition: APValue.h:244
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:187
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
Wrap a function effect's condition expression in another struct so that FunctionProtoType's TrailingO...
Definition: Type.h:4803
Expr * getCondition() const
Definition: Type.h:4810
Represents an abstract function effect, using just an enumeration describing its kind.
Definition: Type.h:4703
Interesting information about a specific parameter that can't simply be reflected in parameter's type...
Definition: Type.h:4334
unsigned char getOpaqueValue() const
Definition: Type.h:4383
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
CXXRecordDecl * getAsRecordDecl() const
Retrieve the record declaration stored in this nested name specifier.
SpecifierKind getKind() const
Determine what kind of nested name specifier is stored.
NamespaceAliasDecl * getAsNamespaceAlias() const
Retrieve the namespace alias stored in this nested name specifier.
IdentifierInfo * getAsIdentifier() const
Retrieve the identifier stored in this nested name specifier.
NestedNameSpecifier * getPrefix() const
Return the prefix of this nested name specifier.
SpecifierKind
The kind of specifier that completes this nested name specifier.
@ NamespaceAlias
A namespace alias, stored as a NamespaceAliasDecl*.
@ TypeSpec
A type, stored as a Type*.
@ TypeSpecWithTemplate
A type that was preceded by the 'template' keyword, stored as a Type*.
@ Super
Microsoft's '__super' specifier, stored as a CXXRecordDecl* of the class it appeared in.
@ Identifier
An identifier, stored as an IdentifierInfo*.
@ Global
The global specifier '::'. There is no stored value.
@ Namespace
A namespace, stored as a NamespaceDecl*.
NamespaceDecl * getAsNamespace() const
Retrieve the namespace stored in this nested name specifier.
const Type * getAsType() const
Retrieve the type stored in this nested name specifier.
A (possibly-)qualified type.
Definition: Type.h:941
The collection of all-type qualifiers we support.
Definition: Type.h:319
uint64_t getAsOpaqueValue() const
Definition: Type.h:442
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:5965
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:8540
DataStreamBasicWriter provides convenience implementations for many BasicWriter methods based on the ...
void writeEffectConditionExpr(EffectConditionExpr CE)
void writeExceptionSpecInfo(const FunctionProtoType::ExceptionSpecInfo &esi)
void writeFixedPointSemantics(const llvm::FixedPointSemantics &sema)
void writeArray(llvm::ArrayRef< T > array)
void writeOptional(std::optional< T > value)
void writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi)
Impl & find(const char *propertyName)
Implement property-find by ignoring it.
void writeAPSInt(const llvm::APSInt &value)
void writeLValuePathSerializationHelper(APValue::LValuePathSerializationHelper lvaluePath)
void writeNestedNameSpecifier(NestedNameSpecifier *NNS)
const internal::VariadicDynCastAllOfMatcher< Decl, ValueDecl > valueDecl
Matches any value declaration.
const internal::VariadicDynCastAllOfMatcher< Decl, RecordDecl > recordDecl
Matches class, struct, and union declarations.
std::optional< T > makeOptionalFromNullable(const T &value)
std::optional< T * > makeOptionalFromPointer(T *value)
The JSON file list parser is used to communicate input to InstallAPI.
bool isComputedNoexcept(ExceptionSpecificationType ESpecType)
const FunctionProtoType * T
@ EST_Uninstantiated
not instantiated yet
@ EST_Unevaluated
not evaluated yet, for special member function
@ EST_Dynamic
throw(T1, T2)
Holds information about the various types of exception specification.
Definition: Type.h:5059
FunctionDecl * SourceDecl
The function whose exception specification this is, for EST_Unevaluated and EST_Uninstantiated.
Definition: Type.h:5071
FunctionDecl * SourceTemplate
The function template whose exception specification this is instantiated from, for EST_Uninstantiated...
Definition: Type.h:5075
ExceptionSpecificationType Type
The kind of exception specification this is.
Definition: Type.h:5061
ArrayRef< QualType > Exceptions
Explicitly-specified list of exception types.
Definition: Type.h:5064
Expr * NoexceptExpr
Noexcept expression, if this is a computed noexcept specification.
Definition: Type.h:5067