]> granicus.if.org Git - clang/commitdiff
RecursiveASTVisitor should visit the nested name qualifiers in
authorAlex Lorenz <arphaman@gmail.com>
Tue, 11 Jul 2017 09:39:23 +0000 (09:39 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Tue, 11 Jul 2017 09:39:23 +0000 (09:39 +0000)
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

include/clang/AST/RecursiveASTVisitor.h
unittests/Tooling/RecursiveASTVisitorTest.cpp

index 152e05bca740a3b6c4f66bc6c1634255675a9b61..917b240428e775bd06306f0ab6010601fdefedcf 100644 (file)
@@ -1799,6 +1799,7 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })
     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                              \
index 74c9c3db34d89f2d7efe39ca88cb39a9491f45c9..63dbd1475454fb70b8d4ffba2e992a31146edca4 100644 (file)
@@ -244,4 +244,62 @@ TEST(RecursiveASTVisitor, InitListExprIsPostOrderNoQueueVisitedTwice) {
                               InitListExprPostOrderNoQueueVisitor::Lang_C));
 }
 
+// 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