Adds the possibility to run ASTMatchFinder over arbitrary AST nodes.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166567 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index 5060e80..689c91f 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -3171,5 +3171,42 @@
           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