aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/clang16/utils/TableGen/ASTTableGen.cpp
blob: 60f563d9a1ffc8b8eed2ff1d81251805a1604e19 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//=== ASTTableGen.cpp - Helper functions for working with AST records -----===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines some helper functions for working with tblegen reocrds
// for the Clang AST: that is, the contents of files such as DeclNodes.td,
// StmtNodes.td, and TypeNodes.td.
//
//===----------------------------------------------------------------------===//

#include "ASTTableGen.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/Error.h"
#include <optional>

using namespace llvm;
using namespace clang;
using namespace clang::tblgen;

llvm::StringRef clang::tblgen::HasProperties::getName() const {
  if (auto node = getAs<ASTNode>()) {
    return node.getName();
  } else if (auto typeCase = getAs<TypeCase>()) {
    return typeCase.getCaseName();
  } else {
    PrintFatalError(getLoc(), "unexpected node declaring properties");
  }
}

static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) {
  StringRef nodeName = node->getName();
  if (!nodeName.endswith(suffix)) {
    PrintFatalError(node->getLoc(),
                    Twine("name of node doesn't end in ") + suffix);
  }
  return nodeName.drop_back(suffix.size());
}

// Decl node names don't end in Decl for historical reasons, and it would
// be somewhat annoying to fix now.  Conveniently, this means the ID matches
// is exactly the node name, and the class name is simply that plus Decl.
std::string clang::tblgen::DeclNode::getClassName() const {
  return (Twine(getName()) + "Decl").str();
}
StringRef clang::tblgen::DeclNode::getId() const {
  return getName();
}

// Type nodes are all named ending in Type, just like the corresponding
// C++ class, and the ID just strips this suffix.
StringRef clang::tblgen::TypeNode::getClassName() const {
  return getName();
}
StringRef clang::tblgen::TypeNode::getId() const {
  return removeExpectedNodeNameSuffix(getRecord(), "Type");
}

// Stmt nodes are named the same as the C++ class, which has no regular
// naming convention (all the non-expression statements end in Stmt,
// and *many* expressions end in Expr, but there are also several
// core expression classes like IntegerLiteral and BinaryOperator with
// no standard suffix).  The ID adds "Class" for historical reasons.
StringRef clang::tblgen::StmtNode::getClassName() const {
  return getName();
}
std::string clang::tblgen::StmtNode::getId() const {
  return (Twine(getName()) + "Class").str();
}

/// Emit a string spelling out the C++ value type.
void PropertyType::emitCXXValueTypeName(bool forRead, raw_ostream &out) const {
  if (!isGenericSpecialization()) {
    if (!forRead && isConstWhenWriting())
      out << "const ";
    out << getCXXTypeName();
  } else if (auto elementType = getArrayElementType()) {
    out << "llvm::ArrayRef<";
    elementType.emitCXXValueTypeName(forRead, out);
    out << ">";
  } else if (auto valueType = getOptionalElementType()) {
    out << "std::optional<";
    valueType.emitCXXValueTypeName(forRead, out);
    out << ">";
  } else {
    //PrintFatalError(getLoc(), "unexpected generic property type");
    abort();
  }
}

// A map from a node to each of its child nodes.
using ChildMap = std::multimap<ASTNode, ASTNode>;

static void visitASTNodeRecursive(ASTNode node, ASTNode base,
                                  const ChildMap &map,
                                  ASTNodeHierarchyVisitor<ASTNode> visit) {
  visit(node, base);

  auto i = map.lower_bound(node), e = map.upper_bound(node);
  for (; i != e; ++i) {
    visitASTNodeRecursive(i->second, node, map, visit);
  }
}

static void visitHierarchy(RecordKeeper &records,
                           StringRef nodeClassName,
                           ASTNodeHierarchyVisitor<ASTNode> visit) {
  // Check for the node class, just as a basic correctness check.
  if (!records.getClass(nodeClassName)) {
    PrintFatalError(Twine("cannot find definition for node class ")
                      + nodeClassName);
  }

  // Find all the nodes in the hierarchy.
  auto nodes = records.getAllDerivedDefinitions(nodeClassName);

  // Derive the child map.
  ChildMap hierarchy;
  ASTNode root;
  for (ASTNode node : nodes) {
    if (auto base = node.getBase())
      hierarchy.insert(std::make_pair(base, node));
    else if (root)
      PrintFatalError(node.getLoc(),
                      "multiple root nodes in " + nodeClassName + " hierarchy");
    else
      root = node;
  }
  if (!root)
    PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy");

  // Now visit the map recursively, starting at the root node.
  visitASTNodeRecursive(root, ASTNode(), hierarchy, visit);
}

void clang::tblgen::visitASTNodeHierarchyImpl(RecordKeeper &records,
                                              StringRef nodeClassName,
                                      ASTNodeHierarchyVisitor<ASTNode> visit) {
  visitHierarchy(records, nodeClassName, visit);
}