| //===-- ASTTableGen.cpp - Helper functions for working with AST records ---===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file defines some helper functions for working with tblegen reocrds | |
| // for the Clang AST: that is, the contents of files such as DeclNodes.td, | |
| // StmtNodes.td, and TypeNodes.td. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "ASTTableGen.h" | |
| #include "llvm/TableGen/Error.h" | |
| #include "llvm/TableGen/Record.h" | |
| using namespace llvm; | |
| using namespace clang; | |
| using namespace clang::tblgen; | |
| StringRef clang::tblgen::HasProperties::getName() const { | |
| if (auto node = getAs<ASTNode>()) { | |
| return node.getName(); | |
| } else if (auto typeCase = getAs<TypeCase>()) { | |
| return typeCase.getCaseName(); | |
| } else { | |
| PrintFatalError(getLoc(), "unexpected node declaring properties"); | |
| } | |
| } | |
| static StringRef removeExpectedNodeNameSuffix(const Record *node, | |
| StringRef suffix) { | |
| StringRef nodeName = node->getName(); | |
| if (!nodeName.ends_with(suffix)) { | |
| PrintFatalError(node->getLoc(), | |
| Twine("name of node doesn't end in ") + suffix); | |
| } | |
| return nodeName.drop_back(suffix.size()); | |
| } | |
| // Decl node names don't end in Decl for historical reasons, and it would | |
| // be somewhat annoying to fix now. Conveniently, this means the ID matches | |
| // is exactly the node name, and the class name is simply that plus Decl. | |
| std::string clang::tblgen::DeclNode::getClassName() const { | |
| return (Twine(getName()) + "Decl").str(); | |
| } | |
| StringRef clang::tblgen::DeclNode::getId() const { | |
| return getName(); | |
| } | |
| // Type nodes are all named ending in Type, just like the corresponding | |
| // C++ class, and the ID just strips this suffix. | |
| StringRef clang::tblgen::TypeNode::getClassName() const { | |
| return getName(); | |
| } | |
| StringRef clang::tblgen::TypeNode::getId() const { | |
| return removeExpectedNodeNameSuffix(getRecord(), "Type"); | |
| } | |
| // Stmt nodes are named the same as the C++ class, which has no regular | |
| // naming convention (all the non-expression statements end in Stmt, | |
| // and *many* expressions end in Expr, but there are also several | |
| // core expression classes like IntegerLiteral and BinaryOperator with | |
| // no standard suffix). The ID adds "Class" for historical reasons. | |
| StringRef clang::tblgen::StmtNode::getClassName() const { | |
| return getName(); | |
| } | |
| std::string clang::tblgen::StmtNode::getId() const { | |
| return (Twine(getName()) + "Class").str(); | |
| } | |
| /// Emit a string spelling out the C++ value type. | |
| void PropertyType::emitCXXValueTypeName(bool forRead, raw_ostream &out) const { | |
| if (!isGenericSpecialization()) { | |
| if (!forRead && isConstWhenWriting()) | |
| out << "const "; | |
| out << getCXXTypeName(); | |
| } else if (auto elementType = getArrayElementType()) { | |
| out << "llvm::ArrayRef<"; | |
| elementType.emitCXXValueTypeName(forRead, out); | |
| out << ">"; | |
| } else if (auto valueType = getOptionalElementType()) { | |
| out << "std::optional<"; | |
| valueType.emitCXXValueTypeName(forRead, out); | |
| out << ">"; | |
| } else { | |
| //PrintFatalError(getLoc(), "unexpected generic property type"); | |
| abort(); | |
| } | |
| } | |
| // A map from a node to each of its child nodes. | |
| using ChildMap = std::multimap<ASTNode, ASTNode>; | |
| static void visitASTNodeRecursive(ASTNode node, ASTNode base, | |
| const ChildMap &map, | |
| ASTNodeHierarchyVisitor<ASTNode> visit) { | |
| visit(node, base); | |
| auto i = map.lower_bound(node), e = map.upper_bound(node); | |
| for (; i != e; ++i) { | |
| visitASTNodeRecursive(i->second, node, map, visit); | |
| } | |
| } | |
| static void visitHierarchy(const RecordKeeper &records, StringRef nodeClassName, | |
| ASTNodeHierarchyVisitor<ASTNode> visit) { | |
| // Check for the node class, just as a basic correctness check. | |
| if (!records.getClass(nodeClassName)) { | |
| PrintFatalError(Twine("cannot find definition for node class ") | |
| + nodeClassName); | |
| } | |
| // Derive the child map for all nodes in the hierarchy. | |
| ChildMap hierarchy; | |
| ASTNode root; | |
| for (ASTNode node : records.getAllDerivedDefinitions(nodeClassName)) { | |
| if (auto base = node.getBase()) | |
| hierarchy.insert(std::make_pair(base, node)); | |
| else if (root) | |
| PrintFatalError(node.getLoc(), | |
| "multiple root nodes in " + nodeClassName + " hierarchy"); | |
| else | |
| root = node; | |
| } | |
| if (!root) | |
| PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy"); | |
| // Now visit the map recursively, starting at the root node. | |
| visitASTNodeRecursive(root, ASTNode(), hierarchy, visit); | |
| } | |
| void clang::tblgen::visitASTNodeHierarchyImpl( | |
| const RecordKeeper &records, StringRef nodeClassName, | |
| ASTNodeHierarchyVisitor<ASTNode> visit) { | |
| visitHierarchy(records, nodeClassName, visit); | |
| } |