ASTTableGen.cpp revision 360784
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
19using namespace llvm;
20using namespace clang;
21using namespace clang::tblgen;
22
23llvm::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
33static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) {
34  StringRef nodeName = node->getName();
35  if (!nodeName.endswith(suffix)) {
36    PrintFatalError(node->getLoc(),
37                    Twine("name of node doesn't end in ") + suffix);
38  }
39  return nodeName.drop_back(suffix.size());
40}
41
42// Decl node names don't end in Decl for historical reasons, and it would
43// be somewhat annoying to fix now.  Conveniently, this means the ID matches
44// is exactly the node name, and the class name is simply that plus Decl.
45std::string clang::tblgen::DeclNode::getClassName() const {
46  return (Twine(getName()) + "Decl").str();
47}
48StringRef clang::tblgen::DeclNode::getId() const {
49  return getName();
50}
51
52// Type nodes are all named ending in Type, just like the corresponding
53// C++ class, and the ID just strips this suffix.
54StringRef clang::tblgen::TypeNode::getClassName() const {
55  return getName();
56}
57StringRef clang::tblgen::TypeNode::getId() const {
58  return removeExpectedNodeNameSuffix(getRecord(), "Type");
59}
60
61// Stmt nodes are named the same as the C++ class, which has no regular
62// naming convention (all the non-expression statements end in Stmt,
63// and *many* expressions end in Expr, but there are also several
64// core expression classes like IntegerLiteral and BinaryOperator with
65// no standard suffix).  The ID adds "Class" for historical reasons.
66StringRef clang::tblgen::StmtNode::getClassName() const {
67  return getName();
68}
69std::string clang::tblgen::StmtNode::getId() const {
70  return (Twine(getName()) + "Class").str();
71}
72
73/// Emit a string spelling out the C++ value type.
74void PropertyType::emitCXXValueTypeName(bool forRead, raw_ostream &out) const {
75  if (!isGenericSpecialization()) {
76    if (!forRead && isConstWhenWriting())
77      out << "const ";
78    out << getCXXTypeName();
79  } else if (auto elementType = getArrayElementType()) {
80    out << "llvm::ArrayRef<";
81    elementType.emitCXXValueTypeName(forRead, out);
82    out << ">";
83  } else if (auto valueType = getOptionalElementType()) {
84    out << "llvm::Optional<";
85    valueType.emitCXXValueTypeName(forRead, out);
86    out << ">";
87  } else {
88    //PrintFatalError(getLoc(), "unexpected generic property type");
89    abort();
90  }
91}
92
93// A map from a node to each of its child nodes.
94using ChildMap = std::multimap<ASTNode, ASTNode>;
95
96static void visitASTNodeRecursive(ASTNode node, ASTNode base,
97                                  const ChildMap &map,
98                                  ASTNodeHierarchyVisitor<ASTNode> visit) {
99  visit(node, base);
100
101  auto i = map.lower_bound(node), e = map.upper_bound(node);
102  for (; i != e; ++i) {
103    visitASTNodeRecursive(i->second, node, map, visit);
104  }
105}
106
107static void visitHierarchy(RecordKeeper &records,
108                           StringRef nodeClassName,
109                           ASTNodeHierarchyVisitor<ASTNode> visit) {
110  // Check for the node class, just as a sanity check.
111  if (!records.getClass(nodeClassName)) {
112    PrintFatalError(Twine("cannot find definition for node class ")
113                      + nodeClassName);
114  }
115
116  // Find all the nodes in the hierarchy.
117  auto nodes = records.getAllDerivedDefinitions(nodeClassName);
118
119  // Derive the child map.
120  ChildMap hierarchy;
121  ASTNode root;
122  for (ASTNode node : nodes) {
123    if (auto base = node.getBase())
124      hierarchy.insert(std::make_pair(base, node));
125    else if (root)
126      PrintFatalError(node.getLoc(),
127                      "multiple root nodes in " + nodeClassName + " hierarchy");
128    else
129      root = node;
130  }
131  if (!root)
132    PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy");
133
134  // Now visit the map recursively, starting at the root node.
135  visitASTNodeRecursive(root, ASTNode(), hierarchy, visit);
136}
137
138void clang::tblgen::visitASTNodeHierarchyImpl(RecordKeeper &records,
139                                              StringRef nodeClassName,
140                                      ASTNodeHierarchyVisitor<ASTNode> visit) {
141  visitHierarchy(records, nodeClassName, visit);
142}
143