ASTTableGen.cpp 5.0 KB

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