1//=== ASTTableGen.h - Common definitions for AST node tablegen --*- C++ -*-===//
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 CLANG_AST_TABLEGEN_H
10#define CLANG_AST_TABLEGEN_H
11
12#include "llvm/TableGen/Record.h"
13#include "llvm/ADT/STLExtras.h"
14#include <optional>
15
16// These are spellings in the tblgen files.
17
18#define HasPropertiesClassName "HasProperties"
19
20// ASTNodes and their common fields. `Base` is actually defined
21// in subclasses, but it's still common across the hierarchies.
22#define ASTNodeClassName "ASTNode"
23#define BaseFieldName "Base"
24#define AbstractFieldName "Abstract"
25
26// Comment node hierarchy.
27#define CommentNodeClassName "CommentNode"
28
29// Decl node hierarchy.
30#define DeclNodeClassName "DeclNode"
31#define DeclContextNodeClassName "DeclContext"
32
33// Stmt node hierarchy.
34#define StmtNodeClassName "StmtNode"
35
36// Type node hierarchy.
37#define TypeNodeClassName "TypeNode"
38#define AlwaysDependentClassName "AlwaysDependent"
39#define NeverCanonicalClassName "NeverCanonical"
40#define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent"
41#define LeafTypeClassName "LeafType"
42
43// Cases of various non-ASTNode structured types like DeclarationName.
44#define TypeKindClassName "PropertyTypeKind"
45#define KindTypeFieldName "KindType"
46#define KindPropertyNameFieldName "KindPropertyName"
47#define TypeCaseClassName "PropertyTypeCase"
48
49// Properties of AST nodes.
50#define PropertyClassName "Property"
51#define ClassFieldName "Class"
52#define NameFieldName "Name"
53#define TypeFieldName "Type"
54#define ReadFieldName "Read"
55
56// Types of properties.
57#define PropertyTypeClassName "PropertyType"
58#define CXXTypeNameFieldName "CXXName"
59#define PassByReferenceFieldName "PassByReference"
60#define ConstWhenWritingFieldName "ConstWhenWriting"
61#define ConditionalCodeFieldName "Conditional"
62#define PackOptionalCodeFieldName "PackOptional"
63#define UnpackOptionalCodeFieldName "UnpackOptional"
64#define BufferElementTypesFieldName "BufferElementTypes"
65#define ArrayTypeClassName "Array"
66#define ArrayElementTypeFieldName "Element"
67#define OptionalTypeClassName "Optional"
68#define OptionalElementTypeFieldName "Element"
69#define SubclassPropertyTypeClassName "SubclassPropertyType"
70#define SubclassBaseTypeFieldName "Base"
71#define SubclassClassNameFieldName "SubclassName"
72#define EnumPropertyTypeClassName "EnumPropertyType"
73
74// Write helper rules.
75#define ReadHelperRuleClassName "ReadHelper"
76#define HelperCodeFieldName "Code"
77
78// Creation rules.
79#define CreationRuleClassName "Creator"
80#define CreateFieldName "Create"
81
82// Override rules.
83#define OverrideRuleClassName "Override"
84#define IgnoredPropertiesFieldName "IgnoredProperties"
85
86namespace clang {
87namespace tblgen {
88
89class WrappedRecord {
90 llvm::Record *Record;
91
92protected:
93 WrappedRecord(llvm::Record *record = nullptr) : Record(record) {}
94
95 llvm::Record *get() const {
96 assert(Record && "accessing null record");
97 return Record;
98 }
99
100public:
101 llvm::Record *getRecord() const { return Record; }
102
103 explicit operator bool() const { return Record != nullptr; }
104
105 llvm::ArrayRef<llvm::SMLoc> getLoc() const {
106 return get()->getLoc();
107 }
108
109 /// Does the node inherit from the given TableGen class?
110 bool isSubClassOf(llvm::StringRef className) const {
111 return get()->isSubClassOf(Name: className);
112 }
113
114 template <class NodeClass>
115 NodeClass getAs() const {
116 return (isSubClassOf(className: NodeClass::getTableGenNodeClassName())
117 ? NodeClass(get()) : NodeClass());
118 }
119
120 friend bool operator<(WrappedRecord lhs, WrappedRecord rhs) {
121 assert(lhs && rhs && "sorting null nodes");
122 return lhs.get()->getName() < rhs.get()->getName();
123 }
124 friend bool operator>(WrappedRecord lhs, WrappedRecord rhs) {
125 return rhs < lhs;
126 }
127 friend bool operator<=(WrappedRecord lhs, WrappedRecord rhs) {
128 return !(rhs < lhs);
129 }
130 friend bool operator>=(WrappedRecord lhs, WrappedRecord rhs) {
131 return !(lhs < rhs);
132 }
133 friend bool operator==(WrappedRecord lhs, WrappedRecord rhs) {
134 // This should handle null nodes.
135 return lhs.getRecord() == rhs.getRecord();
136 }
137 friend bool operator!=(WrappedRecord lhs, WrappedRecord rhs) {
138 return !(lhs == rhs);
139 }
140};
141
142/// Anything in the AST that has properties.
143class HasProperties : public WrappedRecord {
144public:
145 static constexpr llvm::StringRef ClassName = HasPropertiesClassName;
146
147 HasProperties(llvm::Record *record = nullptr) : WrappedRecord(record) {}
148
149 llvm::StringRef getName() const;
150
151 static llvm::StringRef getTableGenNodeClassName() {
152 return HasPropertiesClassName;
153 }
154};
155
156/// An (optional) reference to a TableGen node representing a class
157/// in one of Clang's AST hierarchies.
158class ASTNode : public HasProperties {
159public:
160 ASTNode(llvm::Record *record = nullptr) : HasProperties(record) {}
161
162 llvm::StringRef getName() const {
163 return get()->getName();
164 }
165
166 /// Return the node for the base, if there is one.
167 ASTNode getBase() const {
168 return get()->getValueAsOptionalDef(BaseFieldName);
169 }
170
171 /// Is the corresponding class abstract?
172 bool isAbstract() const {
173 return get()->getValueAsBit(AbstractFieldName);
174 }
175
176 static llvm::StringRef getTableGenNodeClassName() {
177 return ASTNodeClassName;
178 }
179};
180
181class DeclNode : public ASTNode {
182public:
183 DeclNode(llvm::Record *record = nullptr) : ASTNode(record) {}
184
185 llvm::StringRef getId() const;
186 std::string getClassName() const;
187 DeclNode getBase() const { return DeclNode(ASTNode::getBase().getRecord()); }
188
189 static llvm::StringRef getASTHierarchyName() {
190 return "Decl";
191 }
192 static llvm::StringRef getASTIdTypeName() {
193 return "Decl::Kind";
194 }
195 static llvm::StringRef getASTIdAccessorName() {
196 return "getKind";
197 }
198 static llvm::StringRef getTableGenNodeClassName() {
199 return DeclNodeClassName;
200 }
201};
202
203class TypeNode : public ASTNode {
204public:
205 TypeNode(llvm::Record *record = nullptr) : ASTNode(record) {}
206
207 llvm::StringRef getId() const;
208 llvm::StringRef getClassName() const;
209 TypeNode getBase() const { return TypeNode(ASTNode::getBase().getRecord()); }
210
211 static llvm::StringRef getASTHierarchyName() {
212 return "Type";
213 }
214 static llvm::StringRef getASTIdTypeName() {
215 return "Type::TypeClass";
216 }
217 static llvm::StringRef getASTIdAccessorName() {
218 return "getTypeClass";
219 }
220 static llvm::StringRef getTableGenNodeClassName() {
221 return TypeNodeClassName;
222 }
223};
224
225class StmtNode : public ASTNode {
226public:
227 StmtNode(llvm::Record *record = nullptr) : ASTNode(record) {}
228
229 std::string getId() const;
230 llvm::StringRef getClassName() const;
231 StmtNode getBase() const { return StmtNode(ASTNode::getBase().getRecord()); }
232
233 static llvm::StringRef getASTHierarchyName() {
234 return "Stmt";
235 }
236 static llvm::StringRef getASTIdTypeName() {
237 return "Stmt::StmtClass";
238 }
239 static llvm::StringRef getASTIdAccessorName() {
240 return "getStmtClass";
241 }
242 static llvm::StringRef getTableGenNodeClassName() {
243 return StmtNodeClassName;
244 }
245};
246
247/// The type of a property.
248class PropertyType : public WrappedRecord {
249public:
250 PropertyType(llvm::Record *record = nullptr) : WrappedRecord(record) {}
251
252 /// Is this a generic specialization (i.e. `Array<T>` or `Optional<T>`)?
253 bool isGenericSpecialization() const {
254 return get()->isAnonymous();
255 }
256
257 /// The abstract type name of the property. Doesn't work for generic
258 /// specializations.
259 llvm::StringRef getAbstractTypeName() const {
260 return get()->getName();
261 }
262
263 /// The C++ type name of the property. Doesn't work for generic
264 /// specializations.
265 llvm::StringRef getCXXTypeName() const {
266 return get()->getValueAsString(CXXTypeNameFieldName);
267 }
268 void emitCXXValueTypeName(bool forRead, llvm::raw_ostream &out) const;
269
270 /// Whether the C++ type should be passed around by reference.
271 bool shouldPassByReference() const {
272 return get()->getValueAsBit(PassByReferenceFieldName);
273 }
274
275 /// Whether the C++ type should have 'const' prepended when working with
276 /// a value of the type being written.
277 bool isConstWhenWriting() const {
278 return get()->getValueAsBit(ConstWhenWritingFieldName);
279 }
280
281 /// If this is `Array<T>`, return `T`; otherwise return null.
282 PropertyType getArrayElementType() const {
283 if (isSubClassOf(ArrayTypeClassName))
284 return get()->getValueAsDef(ArrayElementTypeFieldName);
285 return nullptr;
286 }
287
288 /// If this is `Optional<T>`, return `T`; otherwise return null.
289 PropertyType getOptionalElementType() const {
290 if (isSubClassOf(OptionalTypeClassName))
291 return get()->getValueAsDef(OptionalElementTypeFieldName);
292 return nullptr;
293 }
294
295 /// If this is a subclass type, return its superclass type.
296 PropertyType getSuperclassType() const {
297 if (isSubClassOf(SubclassPropertyTypeClassName))
298 return get()->getValueAsDef(SubclassBaseTypeFieldName);
299 return nullptr;
300 }
301
302 // Given that this is a subclass type, return the C++ name of its
303 // subclass type. This is just the bare class name, suitable for
304 // use in `cast<>`.
305 llvm::StringRef getSubclassClassName() const {
306 return get()->getValueAsString(SubclassClassNameFieldName);
307 }
308
309 /// Does this represent an enum type?
310 bool isEnum() const {
311 return isSubClassOf(EnumPropertyTypeClassName);
312 }
313
314 llvm::StringRef getPackOptionalCode() const {
315 return get()->getValueAsString(PackOptionalCodeFieldName);
316 }
317
318 llvm::StringRef getUnpackOptionalCode() const {
319 return get()->getValueAsString(UnpackOptionalCodeFieldName);
320 }
321
322 std::vector<llvm::Record*> getBufferElementTypes() const {
323 return get()->getValueAsListOfDefs(BufferElementTypesFieldName);
324 }
325
326 static llvm::StringRef getTableGenNodeClassName() {
327 return PropertyTypeClassName;
328 }
329};
330
331/// A rule for returning the kind of a type.
332class TypeKindRule : public WrappedRecord {
333public:
334 TypeKindRule(llvm::Record *record = nullptr) : WrappedRecord(record) {}
335
336 /// Return the type to which this applies.
337 PropertyType getParentType() const {
338 return get()->getValueAsDef(TypeFieldName);
339 }
340
341 /// Return the type of the kind.
342 PropertyType getKindType() const {
343 return get()->getValueAsDef(KindTypeFieldName);
344 }
345
346 /// Return the name to use for the kind property.
347 llvm::StringRef getKindPropertyName() const {
348 return get()->getValueAsString(KindPropertyNameFieldName);
349 }
350
351 /// Return the code for reading the kind value.
352 llvm::StringRef getReadCode() const {
353 return get()->getValueAsString(ReadFieldName);
354 }
355
356 static llvm::StringRef getTableGenNodeClassName() {
357 return TypeKindClassName;
358 }
359};
360
361/// An implementation case of a property type.
362class TypeCase : public HasProperties {
363public:
364 TypeCase(llvm::Record *record = nullptr) : HasProperties(record) {}
365
366 /// Return the name of this case.
367 llvm::StringRef getCaseName() const {
368 return get()->getValueAsString(NameFieldName);
369 }
370
371 /// Return the type of which this is a case.
372 PropertyType getParentType() const {
373 return get()->getValueAsDef(TypeFieldName);
374 }
375
376 static llvm::StringRef getTableGenNodeClassName() {
377 return TypeCaseClassName;
378 }
379};
380
381/// A property of an AST node.
382class Property : public WrappedRecord {
383public:
384 Property(llvm::Record *record = nullptr) : WrappedRecord(record) {}
385
386 /// Return the name of this property.
387 llvm::StringRef getName() const {
388 return get()->getValueAsString(NameFieldName);
389 }
390
391 /// Return the type of this property.
392 PropertyType getType() const {
393 return get()->getValueAsDef(TypeFieldName);
394 }
395
396 /// Return the class of which this is a property.
397 HasProperties getClass() const {
398 return get()->getValueAsDef(ClassFieldName);
399 }
400
401 /// Return the code for reading this property.
402 llvm::StringRef getReadCode() const {
403 return get()->getValueAsString(ReadFieldName);
404 }
405
406 /// Return the code for determining whether to add this property.
407 llvm::StringRef getCondition() const {
408 return get()->getValueAsString(ConditionalCodeFieldName);
409 }
410
411 static llvm::StringRef getTableGenNodeClassName() {
412 return PropertyClassName;
413 }
414};
415
416/// A rule for running some helper code for reading properties from
417/// a value (which is actually done when writing the value out).
418class ReadHelperRule : public WrappedRecord {
419public:
420 ReadHelperRule(llvm::Record *record = nullptr) : WrappedRecord(record) {}
421
422 /// Return the class for which this is a creation rule.
423 /// Should never be abstract.
424 HasProperties getClass() const {
425 return get()->getValueAsDef(ClassFieldName);
426 }
427
428 llvm::StringRef getHelperCode() const {
429 return get()->getValueAsString(HelperCodeFieldName);
430 }
431
432 static llvm::StringRef getTableGenNodeClassName() {
433 return ReadHelperRuleClassName;
434 }
435};
436
437/// A rule for how to create an AST node from its properties.
438class CreationRule : public WrappedRecord {
439public:
440 CreationRule(llvm::Record *record = nullptr) : WrappedRecord(record) {}
441
442 /// Return the class for which this is a creation rule.
443 /// Should never be abstract.
444 HasProperties getClass() const {
445 return get()->getValueAsDef(ClassFieldName);
446 }
447
448 llvm::StringRef getCreationCode() const {
449 return get()->getValueAsString(CreateFieldName);
450 }
451
452 static llvm::StringRef getTableGenNodeClassName() {
453 return CreationRuleClassName;
454 }
455};
456
457/// A rule which overrides the standard rules for serializing an AST node.
458class OverrideRule : public WrappedRecord {
459public:
460 OverrideRule(llvm::Record *record = nullptr) : WrappedRecord(record) {}
461
462 /// Return the class for which this is an override rule.
463 /// Should never be abstract.
464 HasProperties getClass() const {
465 return get()->getValueAsDef(ClassFieldName);
466 }
467
468 /// Return a set of properties that are unnecessary when serializing
469 /// this AST node. Generally this is used for inherited properties
470 /// that are derived for this subclass.
471 std::vector<llvm::StringRef> getIgnoredProperties() const {
472 return get()->getValueAsListOfStrings(IgnoredPropertiesFieldName);
473 }
474
475 static llvm::StringRef getTableGenNodeClassName() {
476 return OverrideRuleClassName;
477 }
478};
479
480/// A visitor for an AST node hierarchy. Note that `base` can be null for
481/// the root class.
482template <class NodeClass>
483using ASTNodeHierarchyVisitor =
484 llvm::function_ref<void(NodeClass node, NodeClass base)>;
485
486void visitASTNodeHierarchyImpl(llvm::RecordKeeper &records,
487 llvm::StringRef nodeClassName,
488 ASTNodeHierarchyVisitor<ASTNode> visit);
489
490template <class NodeClass>
491void visitASTNodeHierarchy(llvm::RecordKeeper &records,
492 ASTNodeHierarchyVisitor<NodeClass> visit) {
493 visitASTNodeHierarchyImpl(records, NodeClass::getTableGenNodeClassName(),
494 [visit](ASTNode node, ASTNode base) {
495 visit(NodeClass(node.getRecord()),
496 NodeClass(base.getRecord()));
497 });
498}
499
500} // end namespace clang::tblgen
501} // end namespace clang
502
503#endif
504