[clang-tools-extra] r289799 - [change-namespace] handling templated type aliases correctly.

Eric Liu via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 15 02:42:35 PST 2016


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




More information about the cfe-commits mailing list