1 //=== ASTTableGen.cpp - Helper functions for working with AST records -----===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines some helper functions for working with tblegen reocrds
10 // for the Clang AST: that is, the contents of files such as DeclNodes.td,
11 // StmtNodes.td, and TypeNodes.td.
13 //===----------------------------------------------------------------------===//
15 #include "ASTTableGen.h"
16 #include "llvm/TableGen/Record.h"
17 #include "llvm/TableGen/Error.h"
21 using namespace clang
;
22 using namespace clang::tblgen
;
24 llvm::StringRef
clang::tblgen::HasProperties::getName() const {
25 if (auto node
= getAs
<ASTNode
>()) {
26 return node
.getName();
27 } else if (auto typeCase
= getAs
<TypeCase
>()) {
28 return typeCase
.getCaseName();
30 PrintFatalError(getLoc(), "unexpected node declaring properties");
34 static StringRef
removeExpectedNodeNameSuffix(Record
*node
, StringRef suffix
) {
35 StringRef nodeName
= node
->getName();
36 if (!nodeName
.endswith(suffix
)) {
37 PrintFatalError(node
->getLoc(),
38 Twine("name of node doesn't end in ") + suffix
);
40 return nodeName
.drop_back(suffix
.size());
43 // Decl node names don't end in Decl for historical reasons, and it would
44 // be somewhat annoying to fix now. Conveniently, this means the ID matches
45 // is exactly the node name, and the class name is simply that plus Decl.
46 std::string
clang::tblgen::DeclNode::getClassName() const {
47 return (Twine(getName()) + "Decl").str();
49 StringRef
clang::tblgen::DeclNode::getId() const {
53 // Type nodes are all named ending in Type, just like the corresponding
54 // C++ class, and the ID just strips this suffix.
55 StringRef
clang::tblgen::TypeNode::getClassName() const {
58 StringRef
clang::tblgen::TypeNode::getId() const {
59 return removeExpectedNodeNameSuffix(getRecord(), "Type");
62 // Stmt nodes are named the same as the C++ class, which has no regular
63 // naming convention (all the non-expression statements end in Stmt,
64 // and *many* expressions end in Expr, but there are also several
65 // core expression classes like IntegerLiteral and BinaryOperator with
66 // no standard suffix). The ID adds "Class" for historical reasons.
67 StringRef
clang::tblgen::StmtNode::getClassName() const {
70 std::string
clang::tblgen::StmtNode::getId() const {
71 return (Twine(getName()) + "Class").str();
74 /// Emit a string spelling out the C++ value type.
75 void PropertyType::emitCXXValueTypeName(bool forRead
, raw_ostream
&out
) const {
76 if (!isGenericSpecialization()) {
77 if (!forRead
&& isConstWhenWriting())
79 out
<< getCXXTypeName();
80 } else if (auto elementType
= getArrayElementType()) {
81 out
<< "llvm::ArrayRef<";
82 elementType
.emitCXXValueTypeName(forRead
, out
);
84 } else if (auto valueType
= getOptionalElementType()) {
85 out
<< "std::optional<";
86 valueType
.emitCXXValueTypeName(forRead
, out
);
89 //PrintFatalError(getLoc(), "unexpected generic property type");
94 // A map from a node to each of its child nodes.
95 using ChildMap
= std::multimap
<ASTNode
, ASTNode
>;
97 static void visitASTNodeRecursive(ASTNode node
, ASTNode base
,
99 ASTNodeHierarchyVisitor
<ASTNode
> visit
) {
102 auto i
= map
.lower_bound(node
), e
= map
.upper_bound(node
);
103 for (; i
!= e
; ++i
) {
104 visitASTNodeRecursive(i
->second
, node
, map
, visit
);
108 static void visitHierarchy(RecordKeeper
&records
,
109 StringRef nodeClassName
,
110 ASTNodeHierarchyVisitor
<ASTNode
> visit
) {
111 // Check for the node class, just as a basic correctness check.
112 if (!records
.getClass(nodeClassName
)) {
113 PrintFatalError(Twine("cannot find definition for node class ")
117 // Find all the nodes in the hierarchy.
118 auto nodes
= records
.getAllDerivedDefinitions(nodeClassName
);
120 // Derive the child map.
123 for (ASTNode node
: nodes
) {
124 if (auto base
= node
.getBase())
125 hierarchy
.insert(std::make_pair(base
, node
));
127 PrintFatalError(node
.getLoc(),
128 "multiple root nodes in " + nodeClassName
+ " hierarchy");
133 PrintFatalError(Twine("no root node in ") + nodeClassName
+ " hierarchy");
135 // Now visit the map recursively, starting at the root node.
136 visitASTNodeRecursive(root
, ASTNode(), hierarchy
, visit
);
139 void clang::tblgen::visitASTNodeHierarchyImpl(RecordKeeper
&records
,
140 StringRef nodeClassName
,
141 ASTNodeHierarchyVisitor
<ASTNode
> visit
) {
142 visitHierarchy(records
, nodeClassName
, visit
);