martong created this revision.
martong added reviewers: klimek, aprantl, pcc, sbenza, Prazek, dblaikie,
balazske, xazax.hun.
Herald added subscribers: cfe-commits, dkrupp, rnkovacs.
Add matchSubtree, so we can traverse on a subtree rooted on a specific node.
Currently, we can match **one** node against a matcher, but we will not traverse
into the children (this is MatchFinder::match).
Or we can traverse through the whole tree rooted at the TUDecl (this
is MatchFinder::matchAST).
Note, findAll may provide an alternative, but that will traverse throught the
whole AST, and that has some weaknesses:
https://bugs.llvm.org/show_bug.cgi?id=38318
Repository:
rC Clang
https://reviews.llvm.org/D49840
Files:
include/clang/ASTMatchers/ASTMatchFinder.h
lib/ASTMatchers/ASTMatchFinder.cpp
unittests/ASTMatchers/ASTMatchersInternalTest.cpp
Index: unittests/ASTMatchers/ASTMatchersInternalTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersInternalTest.cpp
+++ unittests/ASTMatchers/ASTMatchersInternalTest.cpp
@@ -236,5 +236,53 @@
#endif // _WIN32
+
+TEST(Matcher, matchSubtree) {
+
+ std::unique_ptr<ASTUnit> AST =
+ clang::tooling::buildASTFromCode(
+ R"(
+ template <typename T>
+ struct X {
+ void f() {}
+ void g() {}
+ };
+ void foo() {
+ X<char> xc;
+ xc.f();
+ X<int> xi;
+ }
+ )");
+ ASSERT_TRUE(AST.get());
+
+ // To get the "f" FunctionDecl inside the instantiation ...
+ auto FullPattern =
+ functionDecl(hasName("f")
+ // ... we must specify the parent.
+ ,hasParent(classTemplateSpecializationDecl()));
+ auto *FunD = selectFirst<FunctionDecl>(
+ "dontcare", match(FullPattern.bind("dontcare"), AST->getASTContext()));
+
+
+ auto *SpecD = selectFirst<ClassTemplateSpecializationDecl>(
+ "dontcare", match(classTemplateSpecializationDecl().bind("dontcare"),
+ AST->getASTContext()));
+ MatchFinder Finder;
+ struct TestCallback : MatchFinder::MatchCallback {
+ FunctionDecl *Node = nullptr;
+ void run(const MatchFinder::MatchResult &Result) override {
+ Node =
+ const_cast<FunctionDecl *>(Result.Nodes.getNodeAs<FunctionDecl>(""));
+ }
+ };
+ TestCallback Cb;
+
+ // With matchSubtree we can traverse through the given instantiation.
+ auto SimplePattern = functionDecl(hasName("f"));
+ Finder.addMatcher(SimplePattern.bind(""), &Cb);
+ Finder.matchSubtree(*SpecD, AST->getASTContext());
+ EXPECT_EQ(FunD, Cb.Node);
+}
+
} // end namespace ast_matchers
} // end namespace clang
Index: lib/ASTMatchers/ASTMatchFinder.cpp
===================================================================
--- lib/ASTMatchers/ASTMatchFinder.cpp
+++ lib/ASTMatchers/ASTMatchFinder.cpp
@@ -1015,6 +1015,32 @@
Visitor.match(Node);
}
+void MatchFinder::matchSubtree(const clang::ast_type_traits::DynTypedNode &Node,
+ ASTContext &Context) {
+ internal::MatchASTVisitor Visitor(&Matchers, Options);
+ Visitor.set_active_ast_context(&Context);
+ // FIXME: Improve this with a switch or a visitor pattern.
+ if (auto *N = Node.get<Decl>()) {
+ if (dyn_cast<TranslationUnitDecl>(N))
+ Visitor.onStartOfTranslationUnit();
+ Visitor.TraverseDecl(const_cast<Decl *>(N));
+ if (dyn_cast<TranslationUnitDecl>(N))
+ Visitor.onEndOfTranslationUnit();
+ } else if (auto *N = Node.get<Stmt>()) {
+ Visitor.TraverseStmt(const_cast<Stmt *>(N));
+ } else if (auto *N = Node.get<QualType>()) {
+ Visitor.TraverseType(*N);
+ } else if (auto *N = Node.get<TypeLoc>()) {
+ Visitor.TraverseTypeLoc(*N);
+ } else if (auto *N = Node.get<NestedNameSpecifier>()) {
+ Visitor.TraverseNestedNameSpecifier(const_cast<NestedNameSpecifier *>(N));
+ } else if (auto *N = Node.get<NestedNameSpecifierLoc>()) {
+ Visitor.TraverseNestedNameSpecifierLoc(*N);
+ } else if (auto *N = Node.get<CXXCtorInitializer>()) {
+ Visitor.TraverseConstructorInitializer(const_cast<CXXCtorInitializer *>(N));
+ }
+}
+
void MatchFinder::matchAST(ASTContext &Context) {
internal::MatchASTVisitor Visitor(&Matchers, Options);
Visitor.set_active_ast_context(&Context);
Index: include/clang/ASTMatchers/ASTMatchFinder.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchFinder.h
+++ include/clang/ASTMatchers/ASTMatchFinder.h
@@ -189,6 +189,15 @@
ASTContext &Context);
/// @}
+ /// \brief Finds all matches in the given subtree rooted at \p Node
+ /// @{
+ template <typename T> void matchSubtree(const T &Node, ASTContext &Context) {
+ matchSubtree(clang::ast_type_traits::DynTypedNode::create(Node), Context);
+ }
+ void matchSubtree(const clang::ast_type_traits::DynTypedNode &Node,
+ ASTContext &Context);
+ /// @}
+
/// Finds all matches in the given AST.
void matchAST(ASTContext &Context);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits