Implement has(), hasDescendant(), forEach() and forEachDescendant() for
Types, QualTypes and TypeLocs.

Review: http://llvm-reviews.chandlerc.com/D83

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166917 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index 689c91f..2602e87 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -555,6 +555,114 @@
       "};", ZDescendantClassXDescendantClassY));
 }
 
+// Implements a run method that returns whether BoundNodes contains a
+// Decl bound to Id that can be dynamically cast to T.
+// Optionally checks that the check succeeded a specific number of times.
+template <typename T>
+class VerifyIdIsBoundTo : public BoundNodesCallback {
+public:
+  // Create an object that checks that a node of type \c T was bound to \c Id.
+  // Does not check for a certain number of matches.
+  explicit VerifyIdIsBoundTo(llvm::StringRef Id)
+    : Id(Id), ExpectedCount(-1), Count(0) {}
+
+  // Create an object that checks that a node of type \c T was bound to \c Id.
+  // Checks that there were exactly \c ExpectedCount matches.
+  VerifyIdIsBoundTo(llvm::StringRef Id, int ExpectedCount)
+    : Id(Id), ExpectedCount(ExpectedCount), Count(0) {}
+
+  // Create an object that checks that a node of type \c T was bound to \c Id.
+  // Checks that there was exactly one match with the name \c ExpectedName.
+  // Note that \c T must be a NamedDecl for this to work.
+  VerifyIdIsBoundTo(llvm::StringRef Id, llvm::StringRef ExpectedName)
+    : Id(Id), ExpectedCount(1), Count(0), ExpectedName(ExpectedName) {}
+
+  ~VerifyIdIsBoundTo() {
+    if (ExpectedCount != -1)
+      EXPECT_EQ(ExpectedCount, Count);
+    if (!ExpectedName.empty())
+      EXPECT_EQ(ExpectedName, Name);
+  }
+
+  virtual bool run(const BoundNodes *Nodes) {
+    if (Nodes->getNodeAs<T>(Id)) {
+      ++Count;
+      if (const NamedDecl *Named = Nodes->getNodeAs<NamedDecl>(Id)) {
+        Name = Named->getNameAsString();
+      } else if (const NestedNameSpecifier *NNS =
+                 Nodes->getNodeAs<NestedNameSpecifier>(Id)) {
+        llvm::raw_string_ostream OS(Name);
+        NNS->print(OS, PrintingPolicy(LangOptions()));
+      }
+      return true;
+    }
+    return false;
+  }
+
+private:
+  const std::string Id;
+  const int ExpectedCount;
+  int Count;
+  const std::string ExpectedName;
+  std::string Name;
+};
+
+TEST(HasDescendant, MatchesDescendantTypes) {
+  EXPECT_TRUE(matches("void f() { int i = 3; }",
+                      decl(hasDescendant(loc(builtinType())))));
+  EXPECT_TRUE(matches("void f() { int i = 3; }",
+                      stmt(hasDescendant(builtinType()))));
+
+  EXPECT_TRUE(matches("void f() { int i = 3; }",
+                      stmt(hasDescendant(loc(builtinType())))));
+  EXPECT_TRUE(matches("void f() { int i = 3; }",
+                      stmt(hasDescendant(qualType(builtinType())))));
+
+  EXPECT_TRUE(notMatches("void f() { float f = 2.0f; }",
+                         stmt(hasDescendant(isInteger()))));
+
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      "void f() { int a; float c; int d; int e; }",
+      functionDecl(forEachDescendant(
+          varDecl(hasDescendant(isInteger())).bind("x"))),
+      new VerifyIdIsBoundTo<Decl>("x", 3)));
+}
+
+TEST(HasDescendant, MatchesDescendantsOfTypes) {
+  EXPECT_TRUE(matches("void f() { int*** i; }",
+                      qualType(hasDescendant(builtinType()))));
+  EXPECT_TRUE(matches("void f() { int*** i; }",
+                      qualType(hasDescendant(
+                          pointerType(pointee(builtinType()))))));
+  EXPECT_TRUE(matches("void f() { int*** i; }",
+                      typeLoc(hasDescendant(builtinTypeLoc()))));
+
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      "void f() { int*** i; }",
+      qualType(asString("int ***"), forEachDescendant(pointerType().bind("x"))),
+      new VerifyIdIsBoundTo<Type>("x", 2)));
+}
+
+TEST(Has, MatchesChildrenOfTypes) {
+  EXPECT_TRUE(matches("int i;",
+                      varDecl(hasName("i"), has(isInteger()))));
+  EXPECT_TRUE(notMatches("int** i;",
+                         varDecl(hasName("i"), has(isInteger()))));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      "int (*f)(float, int);",
+      qualType(functionType(), forEach(qualType(isInteger()).bind("x"))),
+      new VerifyIdIsBoundTo<QualType>("x", 2)));
+}
+
+TEST(Has, MatchesChildTypes) {
+  EXPECT_TRUE(matches(
+      "int* i;",
+      varDecl(hasName("i"), hasType(qualType(has(builtinType()))))));
+  EXPECT_TRUE(notMatches(
+      "int* i;",
+      varDecl(hasName("i"), hasType(qualType(has(pointerType()))))));
+}
+
 TEST(Enum, DoesNotMatchClasses) {
   EXPECT_TRUE(notMatches("class X {};", enumDecl(hasName("X"))));
 }
@@ -613,58 +721,6 @@
       matches("class A { public: A *a; class B {}; };", TypeAHasClassB));
 }
 
-// Implements a run method that returns whether BoundNodes contains a
-// Decl bound to Id that can be dynamically cast to T.
-// Optionally checks that the check succeeded a specific number of times.
-template <typename T>
-class VerifyIdIsBoundTo : public BoundNodesCallback {
-public:
-  // Create an object that checks that a node of type \c T was bound to \c Id.
-  // Does not check for a certain number of matches.
-  explicit VerifyIdIsBoundTo(llvm::StringRef Id)
-    : Id(Id), ExpectedCount(-1), Count(0) {}
-
-  // Create an object that checks that a node of type \c T was bound to \c Id.
-  // Checks that there were exactly \c ExpectedCount matches.
-  VerifyIdIsBoundTo(llvm::StringRef Id, int ExpectedCount)
-    : Id(Id), ExpectedCount(ExpectedCount), Count(0) {}
-
-  // Create an object that checks that a node of type \c T was bound to \c Id.
-  // Checks that there was exactly one match with the name \c ExpectedName.
-  // Note that \c T must be a NamedDecl for this to work.
-  VerifyIdIsBoundTo(llvm::StringRef Id, llvm::StringRef ExpectedName)
-    : Id(Id), ExpectedCount(1), Count(0), ExpectedName(ExpectedName) {}
-
-  ~VerifyIdIsBoundTo() {
-    if (ExpectedCount != -1)
-      EXPECT_EQ(ExpectedCount, Count);
-    if (!ExpectedName.empty())
-      EXPECT_EQ(ExpectedName, Name);
-  }
-
-  virtual bool run(const BoundNodes *Nodes) {
-    if (Nodes->getNodeAs<T>(Id)) {
-      ++Count;
-      if (const NamedDecl *Named = Nodes->getNodeAs<NamedDecl>(Id)) {
-        Name = Named->getNameAsString();
-      } else if (const NestedNameSpecifier *NNS =
-                 Nodes->getNodeAs<NestedNameSpecifier>(Id)) {
-        llvm::raw_string_ostream OS(Name);
-        NNS->print(OS, PrintingPolicy(LangOptions()));
-      }
-      return true;
-    }
-    return false;
-  }
-
-private:
-  const std::string Id;
-  const int ExpectedCount;
-  int Count;
-  const std::string ExpectedName;
-  std::string Name;
-};
-
 TEST(Matcher, BindMatchedNodes) {
   DeclarationMatcher ClassX = has(recordDecl(hasName("::X")).bind("x"));
 
@@ -3018,6 +3074,11 @@
                          autoType(hasDeducedType(isInteger()))));
 }
 
+TEST(TypeMatching, MatchesFunctionTypes) {
+  EXPECT_TRUE(matches("int (*f)(int);", functionType()));
+  EXPECT_TRUE(matches("void f(int i) {}", functionType()));
+}
+
 TEST(TypeMatching, PointerTypes) {
   // FIXME: Reactive when these tests can be more specific (not matching
   // implicit code on certain platforms), likely when we have hasDescendant for