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
19using namespace llvm;
20using namespace clang;
21using namespace clang::tblgen;
22
23StringRef 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(ErrorLoc: getLoc(), Msg: "unexpected node declaring properties");
30 }
31}
32
33static StringRef removeExpectedNodeNameSuffix(const Record *node,
34 StringRef suffix) {
35 StringRef nodeName = node->getName();
36 if (!nodeName.ends_with(Suffix: suffix)) {
37 PrintFatalError(ErrorLoc: node->getLoc(),
38 Msg: Twine("name of node doesn't end in ") + suffix);
39 }
40 return nodeName.drop_back(N: 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.
46std::string clang::tblgen::DeclNode::getClassName() const {
47 return (Twine(getName()) + "Decl").str();
48}
49StringRef 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.
55StringRef clang::tblgen::TypeNode::getClassName() const {
56 return getName();
57}
58StringRef clang::tblgen::TypeNode::getId() const {
59 return removeExpectedNodeNameSuffix(node: getRecord(), suffix: "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.
67StringRef clang::tblgen::StmtNode::getClassName() const {
68 return getName();
69}
70std::string clang::tblgen::StmtNode::getId() const {
71 return (Twine(getName()) + "Class").str();
72}
73
74/// Emit a string spelling out the C++ value type.
75void 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.
95using ChildMap = std::multimap<ASTNode, ASTNode>;
96
97static 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(x: node), e = map.upper_bound(x: node);
103 for (; i != e; ++i) {
104 visitASTNodeRecursive(node: i->second, base: node, map, visit);
105 }
106}
107
108static 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(Name: nodeClassName)) {
112 PrintFatalError(Msg: 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(ClassName: nodeClassName)) {
120 if (auto base = node.getBase())
121 hierarchy.insert(x: std::make_pair(x&: base, y&: node));
122 else if (root)
123 PrintFatalError(ErrorLoc: node.getLoc(),
124 Msg: "multiple root nodes in " + nodeClassName + " hierarchy");
125 else
126 root = node;
127 }
128 if (!root)
129 PrintFatalError(Msg: Twine("no root node in ") + nodeClassName + " hierarchy");
130
131 // Now visit the map recursively, starting at the root node.
132 visitASTNodeRecursive(node: root, base: ASTNode(), map: hierarchy, visit);
133}
134
135void clang::tblgen::visitASTNodeHierarchyImpl(
136 const RecordKeeper &records, StringRef nodeClassName,
137 ASTNodeHierarchyVisitor<ASTNode> visit) {
138 visitHierarchy(records, nodeClassName, visit);
139}
140

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang/utils/TableGen/ASTTableGen.cpp