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