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 
23 static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) {
24   StringRef nodeName = node->getName();
25   if (!nodeName.endswith(suffix)) {
26     PrintFatalError(node->getLoc(),
27                     Twine("name of node doesn't end in ") + suffix);
28   }
29   return nodeName.drop_back(suffix.size());
30 }
31 
32 // Decl node names don't end in Decl for historical reasons, and it would
33 // be somewhat annoying to fix now.  Conveniently, this means the ID matches
34 // is exactly the node name, and the class name is simply that plus Decl.
35 std::string clang::tblgen::DeclNode::getClassName() const {
36   return (Twine(getName()) + "Decl").str();
37 }
38 StringRef clang::tblgen::DeclNode::getId() const {
39   return getName();
40 }
41 
42 // Type nodes are all named ending in Type, just like the corresponding
43 // C++ class, and the ID just strips this suffix.
44 StringRef clang::tblgen::TypeNode::getClassName() const {
45   return getName();
46 }
47 StringRef clang::tblgen::TypeNode::getId() const {
48   return removeExpectedNodeNameSuffix(getRecord(), "Type");
49 }
50 
51 // Stmt nodes are named the same as the C++ class, which has no regular
52 // naming convention (all the non-expression statements end in Stmt,
53 // and *many* expressions end in Expr, but there are also several
54 // core expression classes like IntegerLiteral and BinaryOperator with
55 // no standard suffix).  The ID adds "Class" for historical reasons.
56 StringRef clang::tblgen::StmtNode::getClassName() const {
57   return getName();
58 }
59 std::string clang::tblgen::StmtNode::getId() const {
60   return (Twine(getName()) + "Class").str();
61 }
62 
63 // A map from a node to each of its child nodes.
64 template <class NodeClass>
65 using ChildMap = std::multimap<NodeClass, NodeClass>;
66 
67 template <class NodeClass>
68 static void visitASTNodeRecursive(NodeClass node, NodeClass base,
69                                   const ChildMap<NodeClass> &map,
70                                   ASTNodeHierarchyVisitor<NodeClass> visit) {
71   visit(node, base);
72 
73   auto i = map.lower_bound(node), e = map.upper_bound(node);
74   for (; i != e; ++i) {
75     visitASTNodeRecursive(i->second, node, map, visit);
76   }
77 }
78 
79 template <class NodeClass>
80 static void visitHierarchy(RecordKeeper &records,
81                            StringRef nodeClassName,
82                            ASTNodeHierarchyVisitor<NodeClass> visit) {
83   // Check for the node class, just as a sanity check.
84   if (!records.getClass(nodeClassName)) {
85     PrintFatalError(Twine("cannot find definition for node class ")
86                       + nodeClassName);
87   }
88 
89   // Find all the nodes in the hierarchy.
90   auto nodes = records.getAllDerivedDefinitions(nodeClassName);
91 
92   // Derive the child map.
93   ChildMap<NodeClass> hierarchy;
94   NodeClass root;
95   for (NodeClass node : nodes) {
96     if (auto base = node.getBase())
97       hierarchy.insert(std::make_pair(base, node));
98     else if (root)
99       PrintFatalError(node.getLoc(),
100                       "multiple root nodes in " + nodeClassName + " hierarchy");
101     else
102       root = node;
103   }
104   if (!root)
105     PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy");
106 
107   // Now visit the map recursively, starting at the root node.
108   visitASTNodeRecursive(root, NodeClass(), hierarchy, visit);
109 }
110 
111 void clang::tblgen::visitASTNodeHierarchy(RecordKeeper &records,
112                                           StringRef nodeClassName,
113                                       ASTNodeHierarchyVisitor<ASTNode> visit) {
114   visitHierarchy(records, nodeClassName, visit);
115 }
116 
117 void clang::tblgen::visitDeclNodeHierarchy(RecordKeeper &records,
118                                       ASTNodeHierarchyVisitor<DeclNode> visit) {
119   visitHierarchy(records, DeclNodeClassName, visit);
120 }
121 
122 void clang::tblgen::visitTypeNodeHierarchy(RecordKeeper &records,
123                                       ASTNodeHierarchyVisitor<TypeNode> visit) {
124   visitHierarchy(records, TypeNodeClassName, visit);
125 }
126 
127 void clang::tblgen::visitStmtNodeHierarchy(RecordKeeper &records,
128                                       ASTNodeHierarchyVisitor<StmtNode> visit) {
129   visitHierarchy(records, StmtNodeClassName, visit);
130 }
131