Implement descendant matchers for NestedNamespecifiers

This implements has(), hasDescendant(), forEach() and
forEachDescendant() for NestedNameSpecifier and NestedNameSpecifierLoc
matchers.

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167017 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index ec4312e..8861881 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -3236,6 +3236,94 @@
           specifiesTypeLoc(loc(qualType(asString("struct A"))))))));
 }
 
+TEST(NNS, DescendantsOfNestedNameSpecifiers) {
+  std::string Fragment =
+      "namespace a { struct A { struct B { struct C {}; }; }; };"
+      "void f() { a::A::B::C c; }";
+  EXPECT_TRUE(matches(
+      Fragment,
+      nestedNameSpecifier(specifiesType(asString("struct a::A::B")),
+                          hasDescendant(nestedNameSpecifier(
+                              specifiesNamespace(hasName("a")))))));
+  EXPECT_TRUE(notMatches(
+      Fragment,
+      nestedNameSpecifier(specifiesType(asString("struct a::A::B")),
+                          has(nestedNameSpecifier(
+                              specifiesNamespace(hasName("a")))))));
+  EXPECT_TRUE(matches(
+      Fragment,
+      nestedNameSpecifier(specifiesType(asString("struct a::A")),
+                          has(nestedNameSpecifier(
+                              specifiesNamespace(hasName("a")))))));
+
+  // Not really useful because a NestedNameSpecifier can af at most one child,
+  // but to complete the interface.
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Fragment,
+      nestedNameSpecifier(specifiesType(asString("struct a::A::B")),
+                          forEach(nestedNameSpecifier().bind("x"))),
+      new VerifyIdIsBoundTo<NestedNameSpecifier>("x", 1)));
+}
+
+TEST(NNS, NestedNameSpecifiersAsDescendants) {
+  std::string Fragment =
+      "namespace a { struct A { struct B { struct C {}; }; }; };"
+      "void f() { a::A::B::C c; }";
+  EXPECT_TRUE(matches(
+      Fragment,
+      decl(hasDescendant(nestedNameSpecifier(specifiesType(
+          asString("struct a::A")))))));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Fragment,
+      functionDecl(hasName("f"),
+                   forEachDescendant(nestedNameSpecifier().bind("x"))),
+      // Nested names: a, a::A and a::A::B.
+      new VerifyIdIsBoundTo<NestedNameSpecifier>("x", 3)));
+}
+
+TEST(NNSLoc, DescendantsOfNestedNameSpecifierLocs) {
+  std::string Fragment =
+      "namespace a { struct A { struct B { struct C {}; }; }; };"
+      "void f() { a::A::B::C c; }";
+  EXPECT_TRUE(matches(
+      Fragment,
+      nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))),
+                             hasDescendant(loc(nestedNameSpecifier(
+                                 specifiesNamespace(hasName("a"))))))));
+  EXPECT_TRUE(notMatches(
+      Fragment,
+      nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))),
+                             has(loc(nestedNameSpecifier(
+                                 specifiesNamespace(hasName("a"))))))));
+  EXPECT_TRUE(matches(
+      Fragment,
+      nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A"))),
+                             has(loc(nestedNameSpecifier(
+                                 specifiesNamespace(hasName("a"))))))));
+
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Fragment,
+      nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))),
+                             forEach(nestedNameSpecifierLoc().bind("x"))),
+      new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("x", 1)));
+}
+
+TEST(NNSLoc, NestedNameSpecifierLocsAsDescendants) {
+  std::string Fragment =
+      "namespace a { struct A { struct B { struct C {}; }; }; };"
+      "void f() { a::A::B::C c; }";
+  EXPECT_TRUE(matches(
+      Fragment,
+      decl(hasDescendant(loc(nestedNameSpecifier(specifiesType(
+          asString("struct a::A"))))))));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Fragment,
+      functionDecl(hasName("f"),
+                   forEachDescendant(nestedNameSpecifierLoc().bind("x"))),
+      // Nested names: a, a::A and a::A::B.
+      new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("x", 3)));
+}
+
 template <typename T>
 class VerifyRecursiveMatch : public BoundNodesCallback {
 public: