xref: /llvm-project/clang/utils/TableGen/ASTTableGen.cpp (revision 63aa8cf6becbeb4983e3d1a7fa3cd8a7c7147118)
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/Error.h"
17 #include "llvm/TableGen/Record.h"
18 
19 using namespace llvm;
20 using namespace clang;
21 using namespace clang::tblgen;
22 
23 StringRef clang::tblgen::HasProperties::getName() const {
24   if (auto node = getAs<ASTNode>()) {
25     return node.getName();
26   } else if (auto typeCase = getAs<TypeCase>()) {
27     return typeCase.getCaseName();
28   } else {
29     PrintFatalError(getLoc(), "unexpected node declaring properties");
30   }
31 }
32 
33 static StringRef removeExpectedNodeNameSuffix(const Record *node,
34                                               StringRef suffix) {
35   StringRef nodeName = node->getName();
36   if (!nodeName.ends_with(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(const RecordKeeper &records, StringRef nodeClassName,
109                            ASTNodeHierarchyVisitor<ASTNode> visit) {
110   // Check for the node class, just as a basic correctness check.
111   if (!records.getClass(nodeClassName)) {
112     PrintFatalError(Twine("cannot find definition for node class ")
113                       + nodeClassName);
114   }
115 
116   // Derive the child map for all nodes in the hierarchy.
117   ChildMap hierarchy;
118   ASTNode root;
119   for (ASTNode node : records.getAllDerivedDefinitions(nodeClassName)) {
120     if (auto base = node.getBase())
121       hierarchy.insert(std::make_pair(base, node));
122     else if (root)
123       PrintFatalError(node.getLoc(),
124                       "multiple root nodes in " + nodeClassName + " hierarchy");
125     else
126       root = node;
127   }
128   if (!root)
129     PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy");
130 
131   // Now visit the map recursively, starting at the root node.
132   visitASTNodeRecursive(root, ASTNode(), hierarchy, visit);
133 }
134 
135 void clang::tblgen::visitASTNodeHierarchyImpl(
136     const RecordKeeper &records, StringRef nodeClassName,
137     ASTNodeHierarchyVisitor<ASTNode> visit) {
138   visitHierarchy(records, nodeClassName, visit);
139 }
140