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