1 //=== ASTTableGen.cpp - Helper functions for working with AST records -----===//
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 // 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.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "ASTTableGen.h"
16 #include "llvm/TableGen/Record.h"
17 #include "llvm/TableGen/Error.h"
18
19 using namespace llvm;
20 using namespace clang;
21 using namespace clang::tblgen;
22
getName() const23 llvm::StringRef clang::tblgen::HasProperties::getName() const {
24 if (auto node = getAs<ASTNode>()) {
25 return node.getName();
26 } else if (auto typeCase = getAs<TypeCase>()) {
27 return typeCase.getCaseName();
28 } else {
29 PrintFatalError(getLoc(), "unexpected node declaring properties");
30 }
31 }
32
removeExpectedNodeNameSuffix(Record * node,StringRef suffix)33 static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) {
34 StringRef nodeName = node->getName();
35 if (!nodeName.endswith(suffix)) {
36 PrintFatalError(node->getLoc(),
37 Twine("name of node doesn't end in ") + suffix);
38 }
39 return nodeName.drop_back(suffix.size());
40 }
41
42 // Decl node names don't end in Decl for historical reasons, and it would
43 // be somewhat annoying to fix now. Conveniently, this means the ID matches
44 // is exactly the node name, and the class name is simply that plus Decl.
getClassName() const45 std::string clang::tblgen::DeclNode::getClassName() const {
46 return (Twine(getName()) + "Decl").str();
47 }
getId() const48 StringRef clang::tblgen::DeclNode::getId() const {
49 return getName();
50 }
51
52 // Type nodes are all named ending in Type, just like the corresponding
53 // C++ class, and the ID just strips this suffix.
getClassName() const54 StringRef clang::tblgen::TypeNode::getClassName() const {
55 return getName();
56 }
getId() const57 StringRef clang::tblgen::TypeNode::getId() const {
58 return removeExpectedNodeNameSuffix(getRecord(), "Type");
59 }
60
61 // Stmt nodes are named the same as the C++ class, which has no regular
62 // naming convention (all the non-expression statements end in Stmt,
63 // and *many* expressions end in Expr, but there are also several
64 // core expression classes like IntegerLiteral and BinaryOperator with
65 // no standard suffix). The ID adds "Class" for historical reasons.
getClassName() const66 StringRef clang::tblgen::StmtNode::getClassName() const {
67 return getName();
68 }
getId() const69 std::string clang::tblgen::StmtNode::getId() const {
70 return (Twine(getName()) + "Class").str();
71 }
72
73 /// Emit a string spelling out the C++ value type.
emitCXXValueTypeName(bool forRead,raw_ostream & out) const74 void PropertyType::emitCXXValueTypeName(bool forRead, raw_ostream &out) const {
75 if (!isGenericSpecialization()) {
76 if (!forRead && isConstWhenWriting())
77 out << "const ";
78 out << getCXXTypeName();
79 } else if (auto elementType = getArrayElementType()) {
80 out << "llvm::ArrayRef<";
81 elementType.emitCXXValueTypeName(forRead, out);
82 out << ">";
83 } else if (auto valueType = getOptionalElementType()) {
84 out << "llvm::Optional<";
85 valueType.emitCXXValueTypeName(forRead, out);
86 out << ">";
87 } else {
88 //PrintFatalError(getLoc(), "unexpected generic property type");
89 abort();
90 }
91 }
92
93 // A map from a node to each of its child nodes.
94 using ChildMap = std::multimap<ASTNode, ASTNode>;
95
visitASTNodeRecursive(ASTNode node,ASTNode base,const ChildMap & map,ASTNodeHierarchyVisitor<ASTNode> visit)96 static void visitASTNodeRecursive(ASTNode node, ASTNode base,
97 const ChildMap &map,
98 ASTNodeHierarchyVisitor<ASTNode> visit) {
99 visit(node, base);
100
101 auto i = map.lower_bound(node), e = map.upper_bound(node);
102 for (; i != e; ++i) {
103 visitASTNodeRecursive(i->second, node, map, visit);
104 }
105 }
106
visitHierarchy(RecordKeeper & records,StringRef nodeClassName,ASTNodeHierarchyVisitor<ASTNode> visit)107 static void visitHierarchy(RecordKeeper &records,
108 StringRef nodeClassName,
109 ASTNodeHierarchyVisitor<ASTNode> visit) {
110 // Check for the node class, just as a sanity check.
111 if (!records.getClass(nodeClassName)) {
112 PrintFatalError(Twine("cannot find definition for node class ")
113 + nodeClassName);
114 }
115
116 // Find all the nodes in the hierarchy.
117 auto nodes = records.getAllDerivedDefinitions(nodeClassName);
118
119 // Derive the child map.
120 ChildMap hierarchy;
121 ASTNode root;
122 for (ASTNode node : nodes) {
123 if (auto base = node.getBase())
124 hierarchy.insert(std::make_pair(base, node));
125 else if (root)
126 PrintFatalError(node.getLoc(),
127 "multiple root nodes in " + nodeClassName + " hierarchy");
128 else
129 root = node;
130 }
131 if (!root)
132 PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy");
133
134 // Now visit the map recursively, starting at the root node.
135 visitASTNodeRecursive(root, ASTNode(), hierarchy, visit);
136 }
137
visitASTNodeHierarchyImpl(RecordKeeper & records,StringRef nodeClassName,ASTNodeHierarchyVisitor<ASTNode> visit)138 void clang::tblgen::visitASTNodeHierarchyImpl(RecordKeeper &records,
139 StringRef nodeClassName,
140 ASTNodeHierarchyVisitor<ASTNode> visit) {
141 visitHierarchy(records, nodeClassName, visit);
142 }
143