aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/ASTMatchers/ASTMatchFinder.h7
-rw-r--r--lib/ASTMatchers/ASTMatchFinder.cpp12
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.cpp37
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h7
4 files changed, 61 insertions, 2 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchFinder.h b/include/clang/ASTMatchers/ASTMatchFinder.h
index 1cf2036640..ba8e0a7ecc 100644
--- a/include/clang/ASTMatchers/ASTMatchFinder.h
+++ b/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/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index c0d97df075..218b78187d 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/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<Decl*>(&Node));
+}
+
+void MatchFinder::findAll(const Stmt &Node, ASTContext &Context) {
+ internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
+ Visitor.set_active_ast_context(&Context);
+ Visitor.TraverseStmt(const_cast<Stmt*>(&Node));
+}
+
void MatchFinder::registerTestCallbackAfterParsing(
MatchFinder::ParsingDoneTestCallback *NewParsingDone) {
ParsingDone = NewParsingDone;
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index 5060e807c6..689c91f476 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -3171,5 +3171,42 @@ TEST(NNS, MatchesNestedNameSpecifierPrefixes) {
specifiesTypeLoc(loc(qualType(asString("struct A"))))))));
}
+template <typename T>
+class VerifyRecursiveMatch : public BoundNodesCallback {
+public:
+ explicit VerifyRecursiveMatch(StringRef Id,
+ const internal::Matcher<T> &InnerMatcher)
+ : Id(Id), InnerMatcher(InnerMatcher) {}
+ virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
+ const T *Node = Nodes->getNodeAs<T>(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<T> InnerMatcher;
+};
+
+TEST(MatchFinder, CanMatchDeclarationsRecursively) {
+ EXPECT_TRUE(matchAndVerifyResultTrue("class X { class Y {}; };",
+ recordDecl(hasName("::X")).bind("X"),
+ new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Y")))));
+ EXPECT_TRUE(matchAndVerifyResultFalse("class X { class Y {}; };",
+ recordDecl(hasName("::X")).bind("X"),
+ new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Z")))));
+}
+
+TEST(MatchFinder, CanMatchStatementsRecursively) {
+ EXPECT_TRUE(matchAndVerifyResultTrue("void f() { if (1) { for (;;) { } } }",
+ ifStmt().bind("if"),
+ new VerifyRecursiveMatch<clang::Stmt>("if", forStmt())));
+ EXPECT_TRUE(matchAndVerifyResultFalse("void f() { if (1) { for (;;) { } } }",
+ ifStmt().bind("if"),
+ new VerifyRecursiveMatch<clang::Stmt>("if", declStmt())));
+}
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index 01a7c51016..66cc9bd450 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/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;
}