Author: ioeric Date: Thu Dec 15 04:42:35 2016 New Revision: 289799 URL: http://llvm.org/viewvc/llvm-project?rev=289799&view=rev Log: [change-namespace] handling templated type aliases correctly.
Summary: This fixes templated type aliases and templated type aliases in classes. Reviewers: hokein Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D27801 Modified: clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp Modified: clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp?rev=289799&r1=289798&r2=289799&view=diff ============================================================================== --- clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp (original) +++ clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp Thu Dec 15 04:42:35 2016 @@ -454,6 +454,17 @@ void ChangeNamespaceTool::run( BaseCtorInitializerTypeLocs.push_back( BaseInitializer->getTypeSourceInfo()->getTypeLoc()); } else if (const auto *TLoc = Result.Nodes.getNodeAs<TypeLoc>("type")) { + // This avoids fixing types with record types as qualifier, which is not + // filtered by matchers in some cases, e.g. the type is templated. We should + // handle the record type qualifier instead. + if (TLoc->getTypeLocClass() == TypeLoc::Elaborated) { + NestedNameSpecifierLoc NestedNameSpecifier = + TLoc->castAs<ElaboratedTypeLoc>().getQualifierLoc(); + const Type *SpecifierType = + NestedNameSpecifier.getNestedNameSpecifier()->getAsType(); + if (SpecifierType && SpecifierType->isRecordType()) + return; + } fixTypeLoc(Result, startLocationForType(*TLoc), endLocationForType(*TLoc), *TLoc); } else if (const auto *VarRef = @@ -705,27 +716,32 @@ void ChangeNamespaceTool::fixTypeLoc( const auto *FromDecl = Result.Nodes.getNodeAs<NamedDecl>("from_decl"); // `hasDeclaration` gives underlying declaration, but if the type is // a typedef type, we need to use the typedef type instead. + auto IsInMovedNs = [&](const NamedDecl *D) { + if (!llvm::StringRef(D->getQualifiedNameAsString()) + .startswith(OldNamespace + "::")) + return false; + auto ExpansionLoc = Result.SourceManager->getExpansionLoc(D->getLocStart()); + if (ExpansionLoc.isInvalid()) + return false; + llvm::StringRef Filename = Result.SourceManager->getFilename(ExpansionLoc); + return FilePatternRE.match(Filename); + }; + // Make `FromDecl` the immediate declaration that `Type` refers to, i.e. if + // `Type` is an alias type, we make `FromDecl` the type alias declaration. + // Also, don't fix the \p Type if it refers to a type alias decl in the moved + // namespace since the alias decl will be moved along with the type reference. if (auto *Typedef = Type.getType()->getAs<TypedefType>()) { FromDecl = Typedef->getDecl(); - auto IsInMovedNs = [&](const NamedDecl *D) { - if (!llvm::StringRef(D->getQualifiedNameAsString()) - .startswith(OldNamespace + "::")) - return false; - auto ExpansionLoc = - Result.SourceManager->getExpansionLoc(D->getLocStart()); - if (ExpansionLoc.isInvalid()) - return false; - llvm::StringRef Filename = - Result.SourceManager->getFilename(ExpansionLoc); - return FilePatternRE.match(Filename); - }; - // Don't fix the \p Type if it refers to a type alias decl in the moved - // namespace since the alias decl will be moved along with the type - // reference. if (IsInMovedNs(FromDecl)) return; + } else if (auto *TemplateType = + Type.getType()->getAs<TemplateSpecializationType>()) { + if (TemplateType->isTypeAlias()) { + FromDecl = TemplateType->getTemplateName().getAsTemplateDecl(); + if (IsInMovedNs(FromDecl)) + return; + } } - const auto *DeclCtx = Result.Nodes.getNodeAs<Decl>("dc"); assert(DeclCtx && "Empty decl context."); replaceQualifiedSymbolInDeclContext(Result, DeclCtx->getDeclContext(), Start, Modified: clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp?rev=289799&r1=289798&r2=289799&view=diff ============================================================================== --- clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp (original) +++ clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp Thu Dec 15 04:42:35 2016 @@ -1317,6 +1317,88 @@ TEST_F(ChangeNamespaceTest, KeepGlobalSp EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code)); } +TEST_F(ChangeNamespaceTest, UsingAliasInTemplate) { + NewNamespace = "na::nb::nc"; + std::string Code = "namespace some_ns {\n" + "template <typename T, typename S>\n" + "class G {};\n" + "} // namespace some_ns\n" + "namespace na {\n" + "template<typename P>\n" + "using GG = some_ns::G<int, P>;\n" + "} // namespace na\n" + "namespace na {\n" + "namespace nb {\n" + "void f() {\n" + " GG<float> g;\n" + "}\n" + "} // namespace nb\n" + "} // namespace na\n"; + std::string Expected = "namespace some_ns {\n" + "template <typename T, typename S>\n" + "class G {};\n" + "} // namespace some_ns\n" + "namespace na {\n" + "template<typename P>\n" + "using GG = some_ns::G<int, P>;\n" + "} // namespace na\n" + "namespace na {\n" + "namespace nb {\n" + "namespace nc {\n" + "void f() {\n" + " GG<float> g;\n" + "}\n" + "} // namespace nc\n\n" + "} // namespace nb\n" + "} // namespace na\n"; + EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code)); +} + +TEST_F(ChangeNamespaceTest, TemplateUsingAliasInBaseClass) { + NewNamespace = "na::nb::nc"; + std::string Code = "namespace some_ns {\n" + "template <typename T, typename S>\n" + "class G {};\n" + "} // namespace some_ns\n" + "namespace na {\n" + "class Base {\n" + "public:\n" + " template<typename P>\n" + " using GG = some_ns::G<int, P>;\n" + "};\n" + "class Derived : public Base {};\n" + "} // namespace na\n" + "namespace na {\n" + "namespace nb {\n" + "void f() {\n" + " Derived::GG<float> g;\n" + "}\n" + "} // namespace nb\n" + "} // namespace na\n"; + std::string Expected = "namespace some_ns {\n" + "template <typename T, typename S>\n" + "class G {};\n" + "} // namespace some_ns\n" + "namespace na {\n" + "class Base {\n" + "public:\n" + " template<typename P>\n" + " using GG = some_ns::G<int, P>;\n" + "};\n" + "class Derived : public Base {};\n" + "} // namespace na\n" + "namespace na {\n" + "namespace nb {\n" + "namespace nc {\n" + "void f() {\n" + " Derived::GG<float> g;\n" + "}\n" + "} // namespace nc\n\n" + "} // namespace nb\n" + "} // namespace na\n"; + EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code)); +} + } // anonymous namespace } // namespace change_namespace } // namespace clang _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits