RecursiveASTVisitor should visit the nested name qualifiers in
a template specialisation

rdar://33123354

Differential Revision: https://reviews.llvm.org/D34981

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@307638 91177308-0d34-0410-b5e6-96231b3b80d8
(cherry picked from commit b6e778e0bfa2fc32f8821c6b33762f5cb6724659)
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 2e41bc2..8c2cb30 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1767,6 +1767,7 @@
     if (TypeSourceInfo *TSI = D->getTypeAsWritten())                           \
       TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));                              \
                                                                                \
+    TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));              \
     if (!getDerived().shouldVisitTemplateInstantiations() &&                   \
         D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)      \
       /* Returning from here skips traversing the                              \
diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp
index 269bdbb..887330c 100644
--- a/unittests/Tooling/RecursiveASTVisitorTest.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp
@@ -158,4 +158,62 @@
                               "static int k = f();\n"));
 }
 
+// Check to ensure that nested name specifiers are visited.
+class NestedNameSpecifiersVisitor
+    : public ExpectedLocationVisitor<NestedNameSpecifiersVisitor> {
+public:
+  bool VisitRecordTypeLoc(RecordTypeLoc RTL) {
+    if (!RTL)
+      return true;
+    Match(RTL.getDecl()->getName(), RTL.getNameLoc());
+    return true;
+  }
+
+  bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+    if (!NNS)
+      return true;
+    if (const NamespaceDecl *ND =
+            NNS.getNestedNameSpecifier()->getAsNamespace())
+      Match(ND->getName(), NNS.getLocalBeginLoc());
+    return ExpectedLocationVisitor::TraverseNestedNameSpecifierLoc(NNS);
+  }
+};
+
+TEST(RecursiveASTVisitor,
+     NestedNameSpecifiersForTemplateSpecializationsAreVisited) {
+  StringRef Source = R"(
+namespace ns {
+struct Outer {
+    template<typename T, typename U>
+    struct Nested { };
+
+    template<typename T>
+    static T x;
+};
+}
+
+template<>
+struct ns::Outer::Nested<int, int>;
+
+template<>
+struct ns::Outer::Nested<int, int> { };
+
+template<typename T>
+struct ns::Outer::Nested<int, T> { };
+
+template<>
+int ns::Outer::x<int> = 0;
+)";
+  NestedNameSpecifiersVisitor Visitor;
+  Visitor.ExpectMatch("ns", 13, 8);
+  Visitor.ExpectMatch("ns", 16, 8);
+  Visitor.ExpectMatch("ns", 19, 8);
+  Visitor.ExpectMatch("ns", 22, 5);
+  Visitor.ExpectMatch("Outer", 13, 12);
+  Visitor.ExpectMatch("Outer", 16, 12);
+  Visitor.ExpectMatch("Outer", 19, 12);
+  Visitor.ExpectMatch("Outer", 22, 9);
+  EXPECT_TRUE(Visitor.runOver(Source, NestedNameSpecifiersVisitor::Lang_CXX14));
+}
+
 } // end anonymous namespace