From 9c171406c63c4b60cf0cbae9949ce0b712d057ec Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 11 Jul 2017 09:39:23 +0000 Subject: [PATCH] RecursiveASTVisitor should visit the nested name qualifiers in a template specialisation rdar://33123354 Differential Revision: https://reviews.llvm.org/D34981 llvm-svn: 307638 --- clang/include/clang/AST/RecursiveASTVisitor.h | 1 + .../Tooling/RecursiveASTVisitorTest.cpp | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 152e05bca740..917b240428e7 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -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 \ diff --git a/clang/unittests/Tooling/RecursiveASTVisitorTest.cpp b/clang/unittests/Tooling/RecursiveASTVisitorTest.cpp index 74c9c3db34d8..63dbd1475454 100644 --- a/clang/unittests/Tooling/RecursiveASTVisitorTest.cpp +++ b/clang/unittests/Tooling/RecursiveASTVisitorTest.cpp @@ -244,4 +244,62 @@ TEST(RecursiveASTVisitor, InitListExprIsPostOrderNoQueueVisitedTwice) { InitListExprPostOrderNoQueueVisitor::Lang_C)); } +// Check to ensure that nested name specifiers are visited. +class NestedNameSpecifiersVisitor + : public ExpectedLocationVisitor { +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 + struct Nested { }; + + template + static T x; +}; +} + +template<> +struct ns::Outer::Nested; + +template<> +struct ns::Outer::Nested { }; + +template +struct ns::Outer::Nested { }; + +template<> +int ns::Outer::x = 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