/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/utils/TableGen/ASTTableGen.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
19 | | using namespace llvm; |
20 | | using namespace clang; |
21 | | using namespace clang::tblgen; |
22 | | |
23 | 0 | llvm::StringRef clang::tblgen::HasProperties::getName() const { |
24 | 0 | if (auto node = getAs<ASTNode>()) { |
25 | 0 | return node.getName(); |
26 | 0 | } else if (auto typeCase = getAs<TypeCase>()) { |
27 | 0 | return typeCase.getCaseName(); |
28 | 0 | } else { |
29 | 0 | PrintFatalError(getLoc(), "unexpected node declaring properties"); |
30 | 0 | } |
31 | 0 | } |
32 | | |
33 | 0 | static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) { |
34 | 0 | StringRef nodeName = node->getName(); |
35 | 0 | if (!nodeName.endswith(suffix)) { |
36 | 0 | PrintFatalError(node->getLoc(), |
37 | 0 | Twine("name of node doesn't end in ") + suffix); |
38 | 0 | } |
39 | 0 | return nodeName.drop_back(suffix.size()); |
40 | 0 | } |
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. |
45 | 0 | std::string clang::tblgen::DeclNode::getClassName() const { |
46 | 0 | return (Twine(getName()) + "Decl").str(); |
47 | 0 | } |
48 | 0 | StringRef clang::tblgen::DeclNode::getId() const { |
49 | 0 | return getName(); |
50 | 0 | } |
51 | | |
52 | | // Type nodes are all named ending in Type, just like the corresponding |
53 | | // C++ class, and the ID just strips this suffix. |
54 | 0 | StringRef clang::tblgen::TypeNode::getClassName() const { |
55 | 0 | return getName(); |
56 | 0 | } |
57 | 0 | StringRef clang::tblgen::TypeNode::getId() const { |
58 | 0 | return removeExpectedNodeNameSuffix(getRecord(), "Type"); |
59 | 0 | } |
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. |
66 | 0 | StringRef clang::tblgen::StmtNode::getClassName() const { |
67 | 0 | return getName(); |
68 | 0 | } |
69 | 0 | std::string clang::tblgen::StmtNode::getId() const { |
70 | 0 | return (Twine(getName()) + "Class").str(); |
71 | 0 | } |
72 | | |
73 | | /// Emit a string spelling out the C++ value type. |
74 | 0 | void PropertyType::emitCXXValueTypeName(bool forRead, raw_ostream &out) const { |
75 | 0 | if (!isGenericSpecialization()) { |
76 | 0 | if (!forRead && isConstWhenWriting()) |
77 | 0 | out << "const "; |
78 | 0 | out << getCXXTypeName(); |
79 | 0 | } else if (auto elementType = getArrayElementType()) { |
80 | 0 | out << "llvm::ArrayRef<"; |
81 | 0 | elementType.emitCXXValueTypeName(forRead, out); |
82 | 0 | out << ">"; |
83 | 0 | } else if (auto valueType = getOptionalElementType()) { |
84 | 0 | out << "llvm::Optional<"; |
85 | 0 | valueType.emitCXXValueTypeName(forRead, out); |
86 | 0 | out << ">"; |
87 | 0 | } else { |
88 | | //PrintFatalError(getLoc(), "unexpected generic property type"); |
89 | 0 | abort(); |
90 | 0 | } |
91 | 0 | } |
92 | | |
93 | | // A map from a node to each of its child nodes. |
94 | | using ChildMap = std::multimap<ASTNode, ASTNode>; |
95 | | |
96 | | static void visitASTNodeRecursive(ASTNode node, ASTNode base, |
97 | | const ChildMap &map, |
98 | 0 | ASTNodeHierarchyVisitor<ASTNode> visit) { |
99 | 0 | visit(node, base); |
100 | |
|
101 | 0 | auto i = map.lower_bound(node), e = map.upper_bound(node); |
102 | 0 | for (; i != e; ++i) { |
103 | 0 | visitASTNodeRecursive(i->second, node, map, visit); |
104 | 0 | } |
105 | 0 | } |
106 | | |
107 | | static void visitHierarchy(RecordKeeper &records, |
108 | | StringRef nodeClassName, |
109 | 0 | ASTNodeHierarchyVisitor<ASTNode> visit) { |
110 | | // Check for the node class, just as a sanity check. |
111 | 0 | if (!records.getClass(nodeClassName)) { |
112 | 0 | PrintFatalError(Twine("cannot find definition for node class ") |
113 | 0 | + nodeClassName); |
114 | 0 | } |
115 | | |
116 | | // Find all the nodes in the hierarchy. |
117 | 0 | auto nodes = records.getAllDerivedDefinitions(nodeClassName); |
118 | | |
119 | | // Derive the child map. |
120 | 0 | ChildMap hierarchy; |
121 | 0 | ASTNode root; |
122 | 0 | for (ASTNode node : nodes) { |
123 | 0 | if (auto base = node.getBase()) |
124 | 0 | hierarchy.insert(std::make_pair(base, node)); |
125 | 0 | else if (root) |
126 | 0 | PrintFatalError(node.getLoc(), |
127 | 0 | "multiple root nodes in " + nodeClassName + " hierarchy"); |
128 | 0 | else |
129 | 0 | root = node; |
130 | 0 | } |
131 | 0 | if (!root) |
132 | 0 | PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy"); |
133 | | |
134 | | // Now visit the map recursively, starting at the root node. |
135 | 0 | visitASTNodeRecursive(root, ASTNode(), hierarchy, visit); |
136 | 0 | } |
137 | | |
138 | | void clang::tblgen::visitASTNodeHierarchyImpl(RecordKeeper &records, |
139 | | StringRef nodeClassName, |
140 | 0 | ASTNodeHierarchyVisitor<ASTNode> visit) { |
141 | 0 | visitHierarchy(records, nodeClassName, visit); |
142 | 0 | } |