From c268745011bc26e3948c1b63506c5c56ec8892c4 Mon Sep 17 00:00:00 2001 From: Manuel Klimek Date: Wed, 24 Oct 2012 14:47:44 +0000 Subject: [PATCH] Adds the possibility to run ASTMatchFinder over arbitrary AST nodes. llvm-svn: 166567 --- .../clang/ASTMatchers/ASTMatchFinder.h | 7 ++++ clang/lib/ASTMatchers/ASTMatchFinder.cpp | 12 ++++++ .../unittests/ASTMatchers/ASTMatchersTest.cpp | 37 +++++++++++++++++++ clang/unittests/ASTMatchers/ASTMatchersTest.h | 7 +++- 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/ASTMatchers/ASTMatchFinder.h b/clang/include/clang/ASTMatchers/ASTMatchFinder.h index 1cf2036640a4..ba8e0a7eccca 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchFinder.h +++ b/clang/include/clang/ASTMatchers/ASTMatchFinder.h @@ -123,6 +123,13 @@ public: /// \brief Creates a clang ASTConsumer that finds all matches. clang::ASTConsumer *newASTConsumer(); + /// \brief Finds all matches on the given \c Node. + /// + /// @{ + void findAll(const Decl &Node, ASTContext &Context); + void findAll(const Stmt &Node, ASTContext &Context); + /// @} + /// \brief Registers a callback to notify the end of parsing. /// /// The provided closure is called after parsing is done, before the AST is diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp index c0d97df07584..218b78187db6 100644 --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -667,6 +667,18 @@ ASTConsumer *MatchFinder::newASTConsumer() { return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone); } +void MatchFinder::findAll(const Decl &Node, ASTContext &Context) { + internal::MatchASTVisitor Visitor(&MatcherCallbackPairs); + Visitor.set_active_ast_context(&Context); + Visitor.TraverseDecl(const_cast(&Node)); +} + +void MatchFinder::findAll(const Stmt &Node, ASTContext &Context) { + internal::MatchASTVisitor Visitor(&MatcherCallbackPairs); + Visitor.set_active_ast_context(&Context); + Visitor.TraverseStmt(const_cast(&Node)); +} + void MatchFinder::registerTestCallbackAfterParsing( MatchFinder::ParsingDoneTestCallback *NewParsingDone) { ParsingDone = NewParsingDone; diff --git a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp index 5060e807c672..689c91f47672 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -3171,5 +3171,42 @@ TEST(NNS, MatchesNestedNameSpecifierPrefixes) { specifiesTypeLoc(loc(qualType(asString("struct A")))))))); } +template +class VerifyRecursiveMatch : public BoundNodesCallback { +public: + explicit VerifyRecursiveMatch(StringRef Id, + const internal::Matcher &InnerMatcher) + : Id(Id), InnerMatcher(InnerMatcher) {} + virtual bool run(const BoundNodes *Nodes, ASTContext *Context) { + const T *Node = Nodes->getNodeAs(Id); + bool Found = false; + MatchFinder Finder; + Finder.addMatcher(InnerMatcher, new VerifyMatch(0, &Found)); + Finder.findAll(*Node, *Context); + return Found; + } +private: + std::string Id; + internal::Matcher InnerMatcher; +}; + +TEST(MatchFinder, CanMatchDeclarationsRecursively) { + EXPECT_TRUE(matchAndVerifyResultTrue("class X { class Y {}; };", + recordDecl(hasName("::X")).bind("X"), + new VerifyRecursiveMatch("X", recordDecl(hasName("X::Y"))))); + EXPECT_TRUE(matchAndVerifyResultFalse("class X { class Y {}; };", + recordDecl(hasName("::X")).bind("X"), + new VerifyRecursiveMatch("X", recordDecl(hasName("X::Z"))))); +} + +TEST(MatchFinder, CanMatchStatementsRecursively) { + EXPECT_TRUE(matchAndVerifyResultTrue("void f() { if (1) { for (;;) { } } }", + ifStmt().bind("if"), + new VerifyRecursiveMatch("if", forStmt()))); + EXPECT_TRUE(matchAndVerifyResultFalse("void f() { if (1) { for (;;) { } } }", + ifStmt().bind("if"), + new VerifyRecursiveMatch("if", declStmt()))); +} + } // end namespace ast_matchers } // end namespace clang diff --git a/clang/unittests/ASTMatchers/ASTMatchersTest.h b/clang/unittests/ASTMatchers/ASTMatchersTest.h index 01a7c5101626..66cc9bd45074 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTest.h +++ b/clang/unittests/ASTMatchers/ASTMatchersTest.h @@ -24,7 +24,10 @@ using clang::tooling::FrontendActionFactory; class BoundNodesCallback { public: virtual ~BoundNodesCallback() {} - virtual bool run(const BoundNodes *BoundNodes) = 0; + virtual bool run(const BoundNodes *BoundNodes) { return false; } + virtual bool run(const BoundNodes *BoundNodes, ASTContext *Context) { + return run(BoundNodes); + } }; // If 'FindResultVerifier' is not NULL, sets *Verified to the result of @@ -37,7 +40,7 @@ public: virtual void run(const MatchFinder::MatchResult &Result) { if (FindResultReviewer != NULL) { - *Verified = FindResultReviewer->run(&Result.Nodes); + *Verified = FindResultReviewer->run(&Result.Nodes, Result.Context); } else { *Verified = true; }