ASTTableGen.cpp 5.0 KB

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