191dd67efSJohn McCall //=== ASTTableGen.cpp - Helper functions for working with AST records -----===//
291dd67efSJohn McCall //
391dd67efSJohn McCall // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
491dd67efSJohn McCall // See https://llvm.org/LICENSE.txt for license information.
591dd67efSJohn McCall // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
691dd67efSJohn McCall //
791dd67efSJohn McCall //===----------------------------------------------------------------------===//
891dd67efSJohn McCall //
991dd67efSJohn McCall // This file defines some helper functions for working with tblegen reocrds
1091dd67efSJohn McCall // for the Clang AST: that is, the contents of files such as DeclNodes.td,
1191dd67efSJohn McCall // StmtNodes.td, and TypeNodes.td.
1291dd67efSJohn McCall //
1391dd67efSJohn McCall //===----------------------------------------------------------------------===//
1491dd67efSJohn McCall
1591dd67efSJohn McCall #include "ASTTableGen.h"
1691dd67efSJohn McCall #include "llvm/TableGen/Record.h"
1791dd67efSJohn McCall #include "llvm/TableGen/Error.h"
1891dd67efSJohn McCall
1991dd67efSJohn McCall using namespace llvm;
2091dd67efSJohn McCall using namespace clang;
2191dd67efSJohn McCall using namespace clang::tblgen;
2291dd67efSJohn McCall
getName() const23efd0dfbdSJohn McCall llvm::StringRef clang::tblgen::HasProperties::getName() const {
24efd0dfbdSJohn McCall if (auto node = getAs<ASTNode>()) {
25efd0dfbdSJohn McCall return node.getName();
26efd0dfbdSJohn McCall } else if (auto typeCase = getAs<TypeCase>()) {
27efd0dfbdSJohn McCall return typeCase.getCaseName();
28efd0dfbdSJohn McCall } else {
29efd0dfbdSJohn McCall PrintFatalError(getLoc(), "unexpected node declaring properties");
30efd0dfbdSJohn McCall }
31efd0dfbdSJohn McCall }
32efd0dfbdSJohn McCall
removeExpectedNodeNameSuffix(Record * node,StringRef suffix)3391dd67efSJohn McCall static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) {
3491dd67efSJohn McCall StringRef nodeName = node->getName();
3591dd67efSJohn McCall if (!nodeName.endswith(suffix)) {
3691dd67efSJohn McCall PrintFatalError(node->getLoc(),
3791dd67efSJohn McCall Twine("name of node doesn't end in ") + suffix);
3891dd67efSJohn McCall }
3991dd67efSJohn McCall return nodeName.drop_back(suffix.size());
4091dd67efSJohn McCall }
4191dd67efSJohn McCall
4291dd67efSJohn McCall // Decl node names don't end in Decl for historical reasons, and it would
4391dd67efSJohn McCall // be somewhat annoying to fix now. Conveniently, this means the ID matches
4491dd67efSJohn McCall // is exactly the node name, and the class name is simply that plus Decl.
getClassName() const4591dd67efSJohn McCall std::string clang::tblgen::DeclNode::getClassName() const {
4691dd67efSJohn McCall return (Twine(getName()) + "Decl").str();
4791dd67efSJohn McCall }
getId() const4891dd67efSJohn McCall StringRef clang::tblgen::DeclNode::getId() const {
4991dd67efSJohn McCall return getName();
5091dd67efSJohn McCall }
5191dd67efSJohn McCall
5291dd67efSJohn McCall // Type nodes are all named ending in Type, just like the corresponding
5391dd67efSJohn McCall // C++ class, and the ID just strips this suffix.
getClassName() const5491dd67efSJohn McCall StringRef clang::tblgen::TypeNode::getClassName() const {
5591dd67efSJohn McCall return getName();
5691dd67efSJohn McCall }
getId() const5791dd67efSJohn McCall StringRef clang::tblgen::TypeNode::getId() const {
5891dd67efSJohn McCall return removeExpectedNodeNameSuffix(getRecord(), "Type");
5991dd67efSJohn McCall }
6091dd67efSJohn McCall
6191dd67efSJohn McCall // Stmt nodes are named the same as the C++ class, which has no regular
6291dd67efSJohn McCall // naming convention (all the non-expression statements end in Stmt,
6391dd67efSJohn McCall // and *many* expressions end in Expr, but there are also several
6491dd67efSJohn McCall // core expression classes like IntegerLiteral and BinaryOperator with
6591dd67efSJohn McCall // no standard suffix). The ID adds "Class" for historical reasons.
getClassName() const6691dd67efSJohn McCall StringRef clang::tblgen::StmtNode::getClassName() const {
6791dd67efSJohn McCall return getName();
6891dd67efSJohn McCall }
getId() const6991dd67efSJohn McCall std::string clang::tblgen::StmtNode::getId() const {
7091dd67efSJohn McCall return (Twine(getName()) + "Class").str();
7191dd67efSJohn McCall }
7291dd67efSJohn McCall
736404bd23SJohn McCall /// Emit a string spelling out the C++ value type.
emitCXXValueTypeName(bool forRead,raw_ostream & out) const746404bd23SJohn McCall void PropertyType::emitCXXValueTypeName(bool forRead, raw_ostream &out) const {
756404bd23SJohn McCall if (!isGenericSpecialization()) {
766404bd23SJohn McCall if (!forRead && isConstWhenWriting())
776404bd23SJohn McCall out << "const ";
786404bd23SJohn McCall out << getCXXTypeName();
796404bd23SJohn McCall } else if (auto elementType = getArrayElementType()) {
806404bd23SJohn McCall out << "llvm::ArrayRef<";
816404bd23SJohn McCall elementType.emitCXXValueTypeName(forRead, out);
826404bd23SJohn McCall out << ">";
836404bd23SJohn McCall } else if (auto valueType = getOptionalElementType()) {
846404bd23SJohn McCall out << "llvm::Optional<";
856404bd23SJohn McCall valueType.emitCXXValueTypeName(forRead, out);
866404bd23SJohn McCall out << ">";
876404bd23SJohn McCall } else {
886404bd23SJohn McCall //PrintFatalError(getLoc(), "unexpected generic property type");
896404bd23SJohn McCall abort();
906404bd23SJohn McCall }
916404bd23SJohn McCall }
926404bd23SJohn McCall
9391dd67efSJohn McCall // A map from a node to each of its child nodes.
94f6da0cf3SJohn McCall using ChildMap = std::multimap<ASTNode, ASTNode>;
9591dd67efSJohn McCall
visitASTNodeRecursive(ASTNode node,ASTNode base,const ChildMap & map,ASTNodeHierarchyVisitor<ASTNode> visit)96f6da0cf3SJohn McCall static void visitASTNodeRecursive(ASTNode node, ASTNode base,
97f6da0cf3SJohn McCall const ChildMap &map,
98f6da0cf3SJohn McCall ASTNodeHierarchyVisitor<ASTNode> visit) {
9991dd67efSJohn McCall visit(node, base);
10091dd67efSJohn McCall
10191dd67efSJohn McCall auto i = map.lower_bound(node), e = map.upper_bound(node);
10291dd67efSJohn McCall for (; i != e; ++i) {
10391dd67efSJohn McCall visitASTNodeRecursive(i->second, node, map, visit);
10491dd67efSJohn McCall }
10591dd67efSJohn McCall }
10691dd67efSJohn McCall
visitHierarchy(RecordKeeper & records,StringRef nodeClassName,ASTNodeHierarchyVisitor<ASTNode> visit)10791dd67efSJohn McCall static void visitHierarchy(RecordKeeper &records,
10891dd67efSJohn McCall StringRef nodeClassName,
109f6da0cf3SJohn McCall ASTNodeHierarchyVisitor<ASTNode> visit) {
110*d42a6432SZarko Todorovski // Check for the node class, just as a basic correctness check.
11191dd67efSJohn McCall if (!records.getClass(nodeClassName)) {
11291dd67efSJohn McCall PrintFatalError(Twine("cannot find definition for node class ")
11391dd67efSJohn McCall + nodeClassName);
11491dd67efSJohn McCall }
11591dd67efSJohn McCall
11691dd67efSJohn McCall // Find all the nodes in the hierarchy.
11791dd67efSJohn McCall auto nodes = records.getAllDerivedDefinitions(nodeClassName);
11891dd67efSJohn McCall
11991dd67efSJohn McCall // Derive the child map.
120f6da0cf3SJohn McCall ChildMap hierarchy;
121f6da0cf3SJohn McCall ASTNode root;
122f6da0cf3SJohn McCall for (ASTNode node : nodes) {
12391dd67efSJohn McCall if (auto base = node.getBase())
12491dd67efSJohn McCall hierarchy.insert(std::make_pair(base, node));
12591dd67efSJohn McCall else if (root)
12691dd67efSJohn McCall PrintFatalError(node.getLoc(),
12791dd67efSJohn McCall "multiple root nodes in " + nodeClassName + " hierarchy");
12891dd67efSJohn McCall else
12991dd67efSJohn McCall root = node;
13091dd67efSJohn McCall }
13191dd67efSJohn McCall if (!root)
13291dd67efSJohn McCall PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy");
13391dd67efSJohn McCall
13491dd67efSJohn McCall // Now visit the map recursively, starting at the root node.
135f6da0cf3SJohn McCall visitASTNodeRecursive(root, ASTNode(), hierarchy, visit);
13691dd67efSJohn McCall }
13791dd67efSJohn McCall
visitASTNodeHierarchyImpl(RecordKeeper & records,StringRef nodeClassName,ASTNodeHierarchyVisitor<ASTNode> visit)138f6da0cf3SJohn McCall void clang::tblgen::visitASTNodeHierarchyImpl(RecordKeeper &records,
13991dd67efSJohn McCall StringRef nodeClassName,
14091dd67efSJohn McCall ASTNodeHierarchyVisitor<ASTNode> visit) {
14191dd67efSJohn McCall visitHierarchy(records, nodeClassName, visit);
14291dd67efSJohn McCall }
143