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 cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits