Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 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> |
||
20 | inline std::optional<T> makeOptionalFromNullable(const T &value) { |
||
21 | return (value.isNull() ? std::optional<T>() : std::optional<T>(value)); |
||
22 | } |
||
23 | |||
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; |
||
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. |
||
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> |
||
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 | |||
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 | |||
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 | |||
198 | void writeQualifiers(Qualifiers value) { |
||
199 | static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t), |
||
200 | "update this if the value size changes"); |
||
201 | asImpl().writeUInt32(value.getAsOpaqueValue()); |
||
202 | } |
||
203 | |||
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 | |||
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 | |||
225 | void writeNestedNameSpecifier(NestedNameSpecifier *NNS) { |
||
226 | // Nested name specifiers usually aren't too long. I think that 8 would |
||
227 | // typically accommodate the vast majority. |
||
228 | SmallVector<NestedNameSpecifier *, 8> nestedNames; |
||
229 | |||
230 | // Push each of the NNS's onto a stack for serialization in reverse order. |
||
231 | while (NNS) { |
||
232 | nestedNames.push_back(NNS); |
||
233 | NNS = NNS->getPrefix(); |
||
234 | } |
||
235 | |||
236 | asImpl().writeUInt32(nestedNames.size()); |
||
237 | while (!nestedNames.empty()) { |
||
238 | NNS = nestedNames.pop_back_val(); |
||
239 | NestedNameSpecifier::SpecifierKind kind = NNS->getKind(); |
||
240 | asImpl().writeNestedNameSpecifierKind(kind); |
||
241 | switch (kind) { |
||
242 | case NestedNameSpecifier::Identifier: |
||
243 | asImpl().writeIdentifier(NNS->getAsIdentifier()); |
||
244 | continue; |
||
245 | |||
246 | case NestedNameSpecifier::Namespace: |
||
247 | asImpl().writeNamespaceDeclRef(NNS->getAsNamespace()); |
||
248 | continue; |
||
249 | |||
250 | case NestedNameSpecifier::NamespaceAlias: |
||
251 | asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias()); |
||
252 | continue; |
||
253 | |||
254 | case NestedNameSpecifier::TypeSpec: |
||
255 | case NestedNameSpecifier::TypeSpecWithTemplate: |
||
256 | asImpl().writeQualType(QualType(NNS->getAsType(), 0)); |
||
257 | continue; |
||
258 | |||
259 | case NestedNameSpecifier::Global: |
||
260 | // Don't need to write an associated value. |
||
261 | continue; |
||
262 | |||
263 | case NestedNameSpecifier::Super: |
||
264 | asImpl().writeDeclRef(NNS->getAsRecordDecl()); |
||
265 | continue; |
||
266 | } |
||
267 | llvm_unreachable("bad nested name specifier kind"); |
||
268 | } |
||
269 | } |
||
270 | }; |
||
271 | |||
272 | } // end namespace serialization |
||
273 | } // end namespace clang |
||
274 | |||
275 | #endif |