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 #include <optional> 19 20 using namespace llvm; 21 using namespace clang; 22 using namespace clang::tblgen; 23 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(); 29 } else { 30 PrintFatalError(getLoc(), "unexpected node declaring properties"); 31 } 32 } 33 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); 39 } 40 return nodeName.drop_back(suffix.size()); 41 } 42 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(); 48 } 49 StringRef clang::tblgen::DeclNode::getId() const { 50 return getName(); 51 } 52 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 { 56 return getName(); 57 } 58 StringRef clang::tblgen::TypeNode::getId() const { 59 return removeExpectedNodeNameSuffix(getRecord(), "Type"); 60 } 61 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 { 68 return getName(); 69 } 70 std::string clang::tblgen::StmtNode::getId() const { 71 return (Twine(getName()) + "Class").str(); 72 } 73 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()) 78 out << "const "; 79 out << getCXXTypeName(); 80 } else if (auto elementType = getArrayElementType()) { 81 out << "llvm::ArrayRef<"; 82 elementType.emitCXXValueTypeName(forRead, out); 83 out << ">"; 84 } else if (auto valueType = getOptionalElementType()) { 85 out << "std::optional<"; 86 valueType.emitCXXValueTypeName(forRead, out); 87 out << ">"; 88 } else { 89 //PrintFatalError(getLoc(), "unexpected generic property type"); 90 abort(); 91 } 92 } 93 94 // A map from a node to each of its child nodes. 95 using ChildMap = std::multimap<ASTNode, ASTNode>; 96 97 static void visitASTNodeRecursive(ASTNode node, ASTNode base, 98 const ChildMap &map, 99 ASTNodeHierarchyVisitor<ASTNode> visit) { 100 visit(node, base); 101 102 auto i = map.lower_bound(node), e = map.upper_bound(node); 103 for (; i != e; ++i) { 104 visitASTNodeRecursive(i->second, node, map, visit); 105 } 106 } 107 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 ") 114 + nodeClassName); 115 } 116 117 // Find all the nodes in the hierarchy. 118 auto nodes = records.getAllDerivedDefinitions(nodeClassName); 119 120 // Derive the child map. 121 ChildMap hierarchy; 122 ASTNode root; 123 for (ASTNode node : nodes) { 124 if (auto base = node.getBase()) 125 hierarchy.insert(std::make_pair(base, node)); 126 else if (root) 127 PrintFatalError(node.getLoc(), 128 "multiple root nodes in " + nodeClassName + " hierarchy"); 129 else 130 root = node; 131 } 132 if (!root) 133 PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy"); 134 135 // Now visit the map recursively, starting at the root node. 136 visitASTNodeRecursive(root, ASTNode(), hierarchy, visit); 137 } 138 139 void clang::tblgen::visitASTNodeHierarchyImpl(RecordKeeper &records, 140 StringRef nodeClassName, 141 ASTNodeHierarchyVisitor<ASTNode> visit) { 142 visitHierarchy(records, nodeClassName, visit); 143 } 144