Skip to content

Commit dd68942

Browse files
committed
[AST] Add TypeLoc support to node introspection
Extend the matchers gathering API for types to record template parameters. The TypeLoc type hierarchy has some types which are templates used in CRTP such as PointerLikeTypeLoc. Record the inherited template and template arguments of types inheriting those CRTP types in the ClassInheritance map. Because the name inherited from is now computed, the value type in that map changes from StringRef to std::string. This also causes the toJSON override signature used to serialize that map to change. Remove the logic for skipping over empty ClassData instances. Several classes such as TypeOfExprTypeLoc inherit a CRTP class which provides interesting locations though the derived class does not. Record it as a class to make the locations it inherits available. Record the typeSourceInfo accessors too as they provide access to TypeLocs in many classes. The existing unit tests use UnorderedElementsAre to compare the introspection result with the expected result. Our current implementation of google mock (in gmock-generated-matchers.h) is limited to support for comparing a container of 10 elements. As we are now returning more than 10 results for one of the introspection tests, change it to instead compare against an ordered vector of pairs. Because a macro is used to generate API strings and API calls, disable clang-format in blocks of expected results. Otherwise clang-format would insert whitespaces which would then be compared against the introspected strings and fail the test. Introduce a recursion guard in the generated code. The TypeLoc class has IgnoreParens() API which by default returns itself, so it would otherwise recurse infinitely. Differential Revision: https://reviews.llvm.org/D100516
1 parent 863d5c4 commit dd68942

File tree

7 files changed

+821
-159
lines changed

7 files changed

+821
-159
lines changed

clang/include/clang/Tooling/NodeIntrospection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ NodeLocationAccessors GetLocations(clang::CXXCtorInitializer const *Object);
8686
NodeLocationAccessors GetLocations(clang::NestedNameSpecifierLoc const *);
8787
NodeLocationAccessors GetLocations(clang::TemplateArgumentLoc const *);
8888
NodeLocationAccessors GetLocations(clang::CXXBaseSpecifier const *);
89+
NodeLocationAccessors GetLocations(clang::TypeLoc const &);
8990
NodeLocationAccessors GetLocations(clang::DynTypedNode const &Node);
9091
} // namespace NodeIntrospection
9192
} // namespace tooling

clang/lib/Tooling/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ NodeLocationAccessors NodeIntrospection::GetLocations(
5858
clang::CXXBaseSpecifier const*) {
5959
return {};
6060
}
61+
NodeLocationAccessors NodeIntrospection::GetLocations(
62+
clang::TypeLoc const&) {
63+
return {};
64+
}
6165
NodeLocationAccessors
6266
NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
6367
return {};

clang/lib/Tooling/DumpTool/APIData.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,11 @@ namespace clang {
1616
namespace tooling {
1717

1818
struct ClassData {
19-
20-
bool isEmpty() const {
21-
return ASTClassLocations.empty() && ASTClassRanges.empty();
22-
}
23-
2419
std::vector<std::string> ASTClassLocations;
2520
std::vector<std::string> ASTClassRanges;
21+
std::vector<std::string> TemplateParms;
22+
std::vector<std::string> TypeSourceInfos;
23+
std::vector<std::string> TypeLocs;
2624
// TODO: Extend this with locations available via typelocs etc.
2725
};
2826

clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp

Lines changed: 99 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,24 @@ ASTSrcLocProcessor::ASTSrcLocProcessor(StringRef JsonPath)
2222

2323
Finder = std::make_unique<MatchFinder>(std::move(FinderOptions));
2424
Finder->addMatcher(
25-
cxxRecordDecl(
26-
isDefinition(),
27-
isSameOrDerivedFrom(
28-
// TODO: Extend this with other clades
29-
namedDecl(hasAnyName("clang::Stmt", "clang::Decl",
30-
"clang::CXXCtorInitializer",
31-
"clang::NestedNameSpecifierLoc",
32-
"clang::TemplateArgumentLoc",
33-
"clang::CXXBaseSpecifier"))
34-
.bind("nodeClade")),
35-
optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom"))))
36-
.bind("className"),
25+
cxxRecordDecl(
26+
isDefinition(),
27+
isSameOrDerivedFrom(
28+
// TODO: Extend this with other clades
29+
namedDecl(hasAnyName("clang::Stmt", "clang::Decl",
30+
"clang::CXXCtorInitializer",
31+
"clang::NestedNameSpecifierLoc",
32+
"clang::TemplateArgumentLoc",
33+
"clang::CXXBaseSpecifier",
34+
"clang::TypeLoc"))
35+
.bind("nodeClade")),
36+
optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom"))))
37+
.bind("className"),
38+
this);
39+
Finder->addMatcher(
40+
cxxRecordDecl(isDefinition(), hasAnyName("clang::PointerLikeTypeLoc",
41+
"clang::TypeofLikeTypeLoc"))
42+
.bind("templateName"),
3743
this);
3844
}
3945

@@ -53,7 +59,7 @@ llvm::json::Object toJSON(llvm::StringMap<std::vector<StringRef>> const &Obj) {
5359
return JsonObj;
5460
}
5561

56-
llvm::json::Object toJSON(llvm::StringMap<StringRef> const &Obj) {
62+
llvm::json::Object toJSON(llvm::StringMap<std::string> const &Obj) {
5763
using llvm::json::toJSON;
5864

5965
llvm::json::Object JsonObj;
@@ -70,17 +76,21 @@ llvm::json::Object toJSON(ClassData const &Obj) {
7076
JsonObj["sourceLocations"] = Obj.ASTClassLocations;
7177
if (!Obj.ASTClassRanges.empty())
7278
JsonObj["sourceRanges"] = Obj.ASTClassRanges;
79+
if (!Obj.TemplateParms.empty())
80+
JsonObj["templateParms"] = Obj.TemplateParms;
81+
if (!Obj.TypeSourceInfos.empty())
82+
JsonObj["typeSourceInfos"] = Obj.TypeSourceInfos;
83+
if (!Obj.TypeLocs.empty())
84+
JsonObj["typeLocs"] = Obj.TypeLocs;
7385
return JsonObj;
7486
}
7587

7688
llvm::json::Object toJSON(llvm::StringMap<ClassData> const &Obj) {
7789
using llvm::json::toJSON;
7890

7991
llvm::json::Object JsonObj;
80-
for (const auto &Item : Obj) {
81-
if (!Item.second.isEmpty())
82-
JsonObj[Item.first()] = ::toJSON(Item.second);
83-
}
92+
for (const auto &Item : Obj)
93+
JsonObj[Item.first()] = ::toJSON(Item.second);
8494
return JsonObj;
8595
}
8696

@@ -127,28 +137,40 @@ CaptureMethods(std::string TypeString, const clang::CXXRecordDecl *ASTClass,
127137
equalsNode(ASTClass),
128138
optionally(isDerivedFrom(
129139
cxxRecordDecl(hasAnyName("clang::Stmt", "clang::Decl"))
130-
.bind("stmtOrDeclBase"))))),
140+
.bind("stmtOrDeclBase"))),
141+
optionally(isDerivedFrom(
142+
cxxRecordDecl(hasName("clang::Expr")).bind("exprBase"))),
143+
optionally(
144+
isDerivedFrom(cxxRecordDecl(hasName("clang::TypeLoc"))
145+
.bind("typeLocBase"))))),
131146
returns(asString(TypeString)))
132147
.bind("classMethod")),
133148
*ASTClass, *Result.Context);
134149

135150
std::vector<std::string> Methods;
136151
for (const auto &BN : BoundNodesVec) {
137-
const auto *StmtOrDeclBase =
138-
BN.getNodeAs<clang::CXXRecordDecl>("stmtOrDeclBase");
139152
if (const auto *Node = BN.getNodeAs<clang::NamedDecl>("classMethod")) {
140-
// Only record the getBeginLoc etc on Stmt etc, because it will call
141-
// more-derived implementations pseudo-virtually.
153+
const auto *StmtOrDeclBase =
154+
BN.getNodeAs<clang::CXXRecordDecl>("stmtOrDeclBase");
155+
const auto *TypeLocBase =
156+
BN.getNodeAs<clang::CXXRecordDecl>("typeLocBase");
157+
const auto *ExprBase = BN.getNodeAs<clang::CXXRecordDecl>("exprBase");
158+
// The clang AST has several methods on base classes which are overriden
159+
// pseudo-virtually by derived classes.
160+
// We record only the pseudo-virtual methods on the base classes to
161+
// avoid duplication.
142162
if (StmtOrDeclBase &&
143163
(Node->getName() == "getBeginLoc" || Node->getName() == "getEndLoc" ||
144164
Node->getName() == "getSourceRange"))
145165
continue;
146-
147-
// Only record the getExprLoc on Expr, because it will call
148-
// more-derived implementations pseudo-virtually.
149-
if (ASTClass->getName() != "Expr" && Node->getName() == "getExprLoc") {
166+
if (ExprBase && Node->getName() == "getExprLoc")
167+
continue;
168+
if (TypeLocBase && Node->getName() == "getLocalSourceRange")
169+
continue;
170+
if ((ASTClass->getName() == "PointerLikeTypeLoc" ||
171+
ASTClass->getName() == "TypeofLikeTypeLoc") &&
172+
Node->getName() == "getLocalSourceRange")
150173
continue;
151-
}
152174
Methods.push_back(Node->getName().str());
153175
}
154176
}
@@ -160,25 +182,64 @@ void ASTSrcLocProcessor::run(const MatchFinder::MatchResult &Result) {
160182
const auto *ASTClass =
161183
Result.Nodes.getNodeAs<clang::CXXRecordDecl>("className");
162184

185+
StringRef CladeName;
186+
if (ASTClass) {
187+
if (const auto *NodeClade =
188+
Result.Nodes.getNodeAs<clang::CXXRecordDecl>("nodeClade"))
189+
CladeName = NodeClade->getName();
190+
} else {
191+
ASTClass = Result.Nodes.getNodeAs<clang::CXXRecordDecl>("templateName");
192+
CladeName = "TypeLoc";
193+
}
194+
163195
StringRef ClassName = ASTClass->getName();
164196

165197
ClassData CD;
166198

167-
const auto *NodeClade =
168-
Result.Nodes.getNodeAs<clang::CXXRecordDecl>("nodeClade");
169-
StringRef CladeName = NodeClade->getName();
170-
171-
if (const auto *DerivedFrom =
172-
Result.Nodes.getNodeAs<clang::CXXRecordDecl>("derivedFrom"))
173-
ClassInheritance[ClassName] = DerivedFrom->getName();
174-
175199
CD.ASTClassLocations =
176200
CaptureMethods("class clang::SourceLocation", ASTClass, Result);
177201
CD.ASTClassRanges =
178202
CaptureMethods("class clang::SourceRange", ASTClass, Result);
203+
CD.TypeSourceInfos =
204+
CaptureMethods("class clang::TypeSourceInfo *", ASTClass, Result);
205+
CD.TypeLocs = CaptureMethods("class clang::TypeLoc", ASTClass, Result);
179206

180-
if (!CD.isEmpty()) {
181-
ClassEntries[ClassName] = CD;
182-
ClassesInClade[CladeName].push_back(ClassName);
207+
if (const auto *DerivedFrom =
208+
Result.Nodes.getNodeAs<clang::CXXRecordDecl>("derivedFrom")) {
209+
210+
if (const auto *Templ =
211+
llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
212+
DerivedFrom)) {
213+
214+
const auto &TArgs = Templ->getTemplateArgs();
215+
216+
std::string TArgsString = (DerivedFrom->getName() + "<").str();
217+
218+
for (unsigned I = 0; I < TArgs.size(); ++I) {
219+
if (I > 0) {
220+
TArgsString += ", ";
221+
}
222+
auto Ty = TArgs.get(I).getAsType();
223+
clang::PrintingPolicy PPol(Result.Context->getLangOpts());
224+
PPol.TerseOutput = true;
225+
TArgsString += Ty.getAsString(PPol);
226+
}
227+
TArgsString += ">";
228+
229+
ClassInheritance[ClassName] = std::move(TArgsString);
230+
} else {
231+
ClassInheritance[ClassName] = DerivedFrom->getName().str();
232+
}
233+
}
234+
235+
if (const auto *Templ = ASTClass->getDescribedClassTemplate()) {
236+
if (auto *TParams = Templ->getTemplateParameters()) {
237+
for (const auto &TParam : *TParams) {
238+
CD.TemplateParms.push_back(TParam->getName().str());
239+
}
240+
}
183241
}
242+
243+
ClassEntries[ClassName] = CD;
244+
ClassesInClade[CladeName].push_back(ClassName);
184245
}

clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ class ASTSrcLocProcessor : public ast_matchers::MatchFinder::MatchCallback {
3535
private:
3636
void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
3737

38-
llvm::StringMap<StringRef> ClassInheritance;
38+
llvm::Optional<TraversalKind> getCheckTraversalKind() const override {
39+
return TK_IgnoreUnlessSpelledInSource;
40+
}
41+
42+
llvm::StringMap<std::string> ClassInheritance;
3943
llvm::StringMap<std::vector<StringRef>> ClassesInClade;
4044
llvm::StringMap<ClassData> ClassEntries;
4145

0 commit comments

Comments
 (0)