[clang-tools-extra] r286307 - [change-namespace] shorten namespace qualifier based on UsingDecl and UsingDirectiveDecl.

Eric Liu via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 8 14:44:18 PST 2016


Author: ioeric
Date: Tue Nov  8 16:44:17 2016
New Revision: 286307

URL: http://llvm.org/viewvc/llvm-project?rev=286307&view=rev
Log:
[change-namespace] shorten namespace qualifier based on UsingDecl and UsingDirectiveDecl.

Summary:
when replacing symbol references in moved namespaces, trying to make the replace
name as short as possible by considering UsingDecl (i.e. UsingShadow) and
UsingDirectiveDecl (i.e. using namespace decl).

Reviewers: hokein

Subscribers: cfe-commits

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

Modified:
    clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp
    clang-tools-extra/trunk/change-namespace/ChangeNamespace.h
    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=286307&r1=286306&r2=286307&view=diff
==============================================================================
--- clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp (original)
+++ clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp Tue Nov  8 16:44:17 2016
@@ -189,10 +189,8 @@ std::string getShortestQualifiedNameInNa
                                                 llvm::StringRef NsName) {
   DeclName = DeclName.ltrim(':');
   NsName = NsName.ltrim(':');
-  // If `DeclName` is a global variable, we prepend "::" to it if it is not in
-  // the global namespace.
   if (DeclName.find(':') == llvm::StringRef::npos)
-    return NsName.empty() ? DeclName.str() : ("::" + DeclName).str();
+    return DeclName;
 
   while (!DeclName.consume_front((NsName + "::").str())) {
     const auto Pos = NsName.find_last_of(':');
@@ -219,6 +217,26 @@ std::string wrapCodeInNamespace(StringRe
   return Code;
 }
 
+// Returns true if \p D is a nested DeclContext in \p Context
+bool isNestedDeclContext(const DeclContext *D, const DeclContext *Context) {
+  while (D) {
+    if (D == Context)
+      return true;
+    D = D->getParent();
+  }
+  return false;
+}
+
+// Returns true if \p D is visible at \p Loc with DeclContext \p DeclCtx.
+bool isDeclVisibleAtLocation(const SourceManager &SM, const Decl *D,
+                             const DeclContext *DeclCtx, SourceLocation Loc) {
+  SourceLocation DeclLoc = SM.getSpellingLoc(D->getLocation());
+  Loc = SM.getSpellingLoc(Loc);
+  return SM.isBeforeInTranslationUnit(DeclLoc, Loc) &&
+         (SM.getFileID(DeclLoc) == SM.getFileID(Loc) &&
+          isNestedDeclContext(DeclCtx, D->getDeclContext()));
+}
+
 } // anonymous namespace
 
 ChangeNamespaceTool::ChangeNamespaceTool(
@@ -244,17 +262,40 @@ ChangeNamespaceTool::ChangeNamespaceTool
 }
 
 void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
-  // Match old namespace blocks.
   std::string FullOldNs = "::" + OldNamespace;
+  // Prefix is the outer-most namespace in DiffOldNamespace. For example, if the
+  // OldNamespace is "a::b::c" and DiffOldNamespace is "b::c", then Prefix will
+  // be "a::b". Declarations in this namespace will not be visible in the new
+  // namespace. If DiffOldNamespace is empty, Prefix will be a invalid name "-".
+  llvm::SmallVector<llvm::StringRef, 4> DiffOldNsSplitted;
+  llvm::StringRef(DiffOldNamespace).split(DiffOldNsSplitted, "::");
+  std::string Prefix = "-";
+  if (!DiffOldNsSplitted.empty())
+    Prefix = (StringRef(FullOldNs).drop_back(DiffOldNamespace.size()) +
+              DiffOldNsSplitted.front())
+                 .str();
+  auto IsInMovedNs =
+      allOf(hasAncestor(namespaceDecl(hasName(FullOldNs)).bind("ns_decl")),
+            isExpansionInFileMatching(FilePattern));
+  auto IsVisibleInNewNs = anyOf(
+      IsInMovedNs, unless(hasAncestor(namespaceDecl(hasName(Prefix)))));
+  // Match using declarations.
+  Finder->addMatcher(
+      usingDecl(isExpansionInFileMatching(FilePattern), IsVisibleInNewNs)
+          .bind("using"),
+      this);
+  // Match using namespace declarations.
+  Finder->addMatcher(usingDirectiveDecl(isExpansionInFileMatching(FilePattern),
+                                        IsVisibleInNewNs)
+                         .bind("using_namespace"),
+                     this);
+
+  // Match old namespace blocks.
   Finder->addMatcher(
       namespaceDecl(hasName(FullOldNs), isExpansionInFileMatching(FilePattern))
           .bind("old_ns"),
       this);
 
-  auto IsInMovedNs =
-      allOf(hasAncestor(namespaceDecl(hasName(FullOldNs)).bind("ns_decl")),
-            isExpansionInFileMatching(FilePattern));
-
   // Match forward-declarations in the old namespace.
   Finder->addMatcher(
       cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())), IsInMovedNs)
@@ -288,9 +329,9 @@ void ChangeNamespaceTool::registerMatche
 
   // Types in `UsingShadowDecl` is not matched by `typeLoc` above, so we need to
   // special case it.
-  Finder->addMatcher(
-      usingDecl(IsInMovedNs, hasAnyUsingShadowDecl(decl())).bind("using_decl"),
-      this);
+  Finder->addMatcher(usingDecl(IsInMovedNs, hasAnyUsingShadowDecl(decl()))
+                         .bind("using_with_shadow"),
+                     this);
 
   // Handle types in nested name specifier.
   Finder->addMatcher(nestedNameSpecifierLoc(
@@ -328,14 +369,21 @@ void ChangeNamespaceTool::registerMatche
 
 void ChangeNamespaceTool::run(
     const ast_matchers::MatchFinder::MatchResult &Result) {
-  if (const auto *NsDecl = Result.Nodes.getNodeAs<NamespaceDecl>("old_ns")) {
+  if (const auto *Using = Result.Nodes.getNodeAs<UsingDecl>("using")) {
+    UsingDecls.insert(Using);
+  } else if (const auto *UsingNamespace =
+                 Result.Nodes.getNodeAs<UsingDirectiveDecl>(
+                     "using_namespace")) {
+    UsingNamespaceDecls.insert(UsingNamespace);
+  } else if (const auto *NsDecl =
+                 Result.Nodes.getNodeAs<NamespaceDecl>("old_ns")) {
     moveOldNamespace(Result, NsDecl);
   } else if (const auto *FwdDecl =
                  Result.Nodes.getNodeAs<CXXRecordDecl>("fwd_decl")) {
     moveClassForwardDeclaration(Result, FwdDecl);
-  } else if (const auto *UsingDeclaration =
-                 Result.Nodes.getNodeAs<UsingDecl>("using_decl")) {
-    fixUsingShadowDecl(Result, UsingDeclaration);
+  } else if (const auto *UsingWithShadow =
+                 Result.Nodes.getNodeAs<UsingDecl>("using_with_shadow")) {
+    fixUsingShadowDecl(Result, UsingWithShadow);
   } else if (const auto *Specifier =
                  Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
                      "nested_specifier_loc")) {
@@ -351,12 +399,12 @@ void ChangeNamespaceTool::run(
     assert(Var);
     if (Var->getCanonicalDecl()->isStaticDataMember())
       return;
-    std::string Name = Var->getQualifiedNameAsString();
     const clang::Decl *Context = Result.Nodes.getNodeAs<clang::Decl>("dc");
     assert(Context && "Empty decl context.");
     clang::SourceRange VarRefRange = VarRef->getSourceRange();
-    replaceQualifiedSymbolInDeclContext(Result, Context, VarRefRange.getBegin(),
-                                        VarRefRange.getEnd(), Name);
+    replaceQualifiedSymbolInDeclContext(
+        Result, Context->getDeclContext(), VarRefRange.getBegin(),
+        VarRefRange.getEnd(), llvm::dyn_cast<NamedDecl>(Var));
   } else {
     const auto *Call = Result.Nodes.getNodeAs<clang::CallExpr>("call");
     assert(Call != nullptr && "Expecting callback for CallExpr.");
@@ -368,12 +416,12 @@ void ChangeNamespaceTool::run(
             clang::StorageClass::SC_Static &&
         Func->isOutOfLine())
       return;
-    std::string Name = Func->getQualifiedNameAsString();
     const clang::Decl *Context = Result.Nodes.getNodeAs<clang::Decl>("dc");
     assert(Context && "Empty decl context.");
     clang::SourceRange CalleeRange = Call->getCallee()->getSourceRange();
-    replaceQualifiedSymbolInDeclContext(Result, Context, CalleeRange.getBegin(),
-                                        CalleeRange.getEnd(), Name);
+    replaceQualifiedSymbolInDeclContext(
+        Result, Context->getDeclContext(), CalleeRange.getBegin(),
+        CalleeRange.getEnd(), llvm::dyn_cast<NamedDecl>(Func));
   }
 }
 
@@ -487,15 +535,14 @@ void ChangeNamespaceTool::moveClassForwa
   InsertFwdDecls[Insertion.getFilePath()].push_back(InsertFwd);
 }
 
-// Replaces a qualified symbol that refers to a declaration `DeclName` with the
-// shortest qualified name possible when the reference is in `NewNamespace`.
-// FIXME: don't need to add redundant namespace qualifier when there is
-// UsingShadowDecl or using namespace decl.
+// Replaces a qualified symbol (in \p DeclCtx) that refers to a declaration \p
+// FromDecl with the shortest qualified name possible when the reference is in
+// `NewNamespace`.
 void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext(
-    const ast_matchers::MatchFinder::MatchResult &Result, const Decl *DeclCtx,
-    SourceLocation Start, SourceLocation End, llvm::StringRef DeclName) {
-  const auto *NsDeclContext =
-      DeclCtx->getDeclContext()->getEnclosingNamespaceContext();
+    const ast_matchers::MatchFinder::MatchResult &Result,
+    const DeclContext *DeclCtx, SourceLocation Start, SourceLocation End,
+    const NamedDecl *FromDecl) {
+  const auto *NsDeclContext = DeclCtx->getEnclosingNamespaceContext();
   const auto *NsDecl = llvm::dyn_cast<NamespaceDecl>(NsDeclContext);
   // Calculate the name of the `NsDecl` after it is moved to new namespace.
   std::string OldNs = NsDecl->getQualifiedNameAsString();
@@ -513,8 +560,40 @@ void ChangeNamespaceTool::replaceQualifi
   // If the symbol is already fully qualified, no change needs to be make.
   if (NestedName.startswith("::"))
     return;
+  std::string FromDeclName = FromDecl->getQualifiedNameAsString();
   std::string ReplaceName =
-      getShortestQualifiedNameInNamespace(DeclName, NewNs);
+      getShortestQualifiedNameInNamespace(FromDeclName, NewNs);
+  // Checks if there is any using namespace declarations that can shorten the
+  // qualified name.
+  for (const auto *UsingNamespace : UsingNamespaceDecls) {
+    if (!isDeclVisibleAtLocation(*Result.SourceManager, UsingNamespace, DeclCtx,
+                                 Start))
+      continue;
+    StringRef FromDeclNameRef = FromDeclName;
+    if (FromDeclNameRef.consume_front(UsingNamespace->getNominatedNamespace()
+                                          ->getQualifiedNameAsString())) {
+      FromDeclNameRef = FromDeclNameRef.drop_front(2);
+      if (FromDeclNameRef.size() < ReplaceName.size())
+        ReplaceName = FromDeclNameRef;
+    }
+  }
+  // Checks if there is any using shadow declarations that can shorten the
+  // qualified name.
+  bool Matched = false;
+  for (const UsingDecl *Using : UsingDecls) {
+    if (Matched)
+      break;
+    if (isDeclVisibleAtLocation(*Result.SourceManager, Using, DeclCtx, Start)) {
+      for (const auto *UsingShadow : Using->shadows()) {
+        const auto *TargetDecl = UsingShadow->getTargetDecl();
+        if (TargetDecl == FromDecl) {
+          ReplaceName = FromDecl->getNameAsString();
+          Matched = true;
+          break;
+        }
+      }
+    }
+  }
   // If the new nested name in the new namespace is the same as it was in the
   // old namespace, we don't create replacement.
   if (NestedName == ReplaceName)
@@ -540,8 +619,8 @@ void ChangeNamespaceTool::fixTypeLoc(
 
   const Decl *DeclCtx = Result.Nodes.getNodeAs<Decl>("dc");
   assert(DeclCtx && "Empty decl context.");
-  replaceQualifiedSymbolInDeclContext(Result, DeclCtx, Start, End,
-                                      FromDecl->getQualifiedNameAsString());
+  replaceQualifiedSymbolInDeclContext(Result, DeclCtx->getDeclContext(), Start,
+                                      End, FromDecl);
 }
 
 void ChangeNamespaceTool::fixUsingShadowDecl(

Modified: clang-tools-extra/trunk/change-namespace/ChangeNamespace.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/change-namespace/ChangeNamespace.h?rev=286307&r1=286306&r2=286307&view=diff
==============================================================================
--- clang-tools-extra/trunk/change-namespace/ChangeNamespace.h (original)
+++ clang-tools-extra/trunk/change-namespace/ChangeNamespace.h Tue Nov  8 16:44:17 2016
@@ -67,8 +67,8 @@ private:
 
   void replaceQualifiedSymbolInDeclContext(
       const ast_matchers::MatchFinder::MatchResult &Result,
-      const Decl *DeclContext, SourceLocation Start, SourceLocation End,
-      llvm::StringRef DeclName);
+      const DeclContext *DeclContext, SourceLocation Start, SourceLocation End,
+      const NamedDecl *FromDecl);
 
   void fixTypeLoc(const ast_matchers::MatchFinder::MatchResult &Result,
                   SourceLocation Start, SourceLocation End, TypeLoc Type);
@@ -139,6 +139,12 @@ private:
   // will be done after removing the code from the old namespace and before
   // inserting it to the new namespace.
   std::map<std::string, std::vector<InsertForwardDeclaration>> InsertFwdDecls;
+  // Records all using declarations, which can be used to shorten namespace
+  // specifiers.
+  llvm::SmallPtrSet<const UsingDecl *, 8> UsingDecls;
+  // Records all using namespace declarations, which can be used to shorten
+  // namespace specifiers.
+  llvm::SmallPtrSet<const UsingDirectiveDecl *, 8> UsingNamespaceDecls;
 };
 
 } // namespace change_namespace

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=286307&r1=286306&r2=286307&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp (original)
+++ clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp Tue Nov  8 16:44:17 2016
@@ -313,8 +313,8 @@ TEST_F(ChangeNamespaceTest, FixUsingShad
                      "}\n"
                      "namespace nb {\n"
                      "using nc::SAME;\n"
-                     "using YO = nc::SAME;\n"
-                     "typedef nc::SAME IDENTICAL;\n"
+                     "using YO = nd::SAME;\n"
+                     "typedef nd::SAME IDENTICAL;\n"
                      "void f(nd::SAME Same) {}\n"
                      "} // namespace nb\n"
                      "} // namespace na\n";
@@ -333,93 +333,14 @@ TEST_F(ChangeNamespaceTest, FixUsingShad
                          "namespace x {\n"
                          "namespace y {\n"
                          "using ::na::nc::SAME;\n"
-                         "using YO = na::nc::SAME;\n"
-                         "typedef na::nc::SAME IDENTICAL;\n"
+                         "using YO = na::nd::SAME;\n"
+                         "typedef na::nd::SAME IDENTICAL;\n"
                          "void f(na::nd::SAME Same) {}\n"
                          "} // namespace y\n"
                          "} // namespace x\n";
   EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
 }
 
-TEST_F(ChangeNamespaceTest, UsingShadowDeclInFunction) {
-  std::string Code = "namespace glob {\n"
-                     "class Glob {};\n"
-                     "}\n"
-                     "namespace na {\n"
-                     "namespace nb {\n"
-                     "void f() {\n"
-                     "  using glob::Glob;\n"
-                     "  Glob g;\n"
-                     "}\n"
-                     "} // namespace nb\n"
-                     "} // namespace na\n";
-
-  // FIXME: don't add namespace qualifier when there is UsingShadowDecl.
-  std::string Expected = "namespace glob {\n"
-                         "class Glob {};\n"
-                         "}\n"
-                         "\n"
-                         "namespace x {\n"
-                         "namespace y {\n"
-                         "void f() {\n"
-                         "  using ::glob::Glob;\n"
-                         "  glob::Glob g;\n"
-                         "}\n"
-                         "} // namespace y\n"
-                         "} // namespace x\n";
-  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
-}
-
-TEST_F(ChangeNamespaceTest, UsingShadowDeclInGlobal) {
-  std::string Code = "namespace glob {\n"
-                     "class Glob {};\n"
-                     "}\n"
-                     "using glob::Glob;\n"
-                     "namespace na {\n"
-                     "namespace nb {\n"
-                     "void f() { Glob g; }\n"
-                     "} // namespace nb\n"
-                     "} // namespace na\n";
-
-  // FIXME: don't add namespace qualifier when there is UsingShadowDecl.
-  std::string Expected = "namespace glob {\n"
-                         "class Glob {};\n"
-                         "}\n"
-                         "using glob::Glob;\n"
-                         "\n"
-                         "namespace x {\n"
-                         "namespace y {\n"
-                         "void f() { glob::Glob g; }\n"
-                         "} // namespace y\n"
-                         "} // namespace x\n";
-  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
-}
-
-TEST_F(ChangeNamespaceTest, UsingNamespace) {
-  std::string Code = "namespace glob {\n"
-                     "class Glob {};\n"
-                     "}\n"
-                     "using namespace glob;\n"
-                     "namespace na {\n"
-                     "namespace nb {\n"
-                     "void f() { Glob g; }\n"
-                     "} // namespace nb\n"
-                     "} // namespace na\n";
-
-  // FIXME: don't add namespace qualifier when there is "using namespace" decl.
-  std::string Expected = "namespace glob {\n"
-                         "class Glob {};\n"
-                         "}\n"
-                         "using namespace glob;\n"
-                         "\n"
-                         "namespace x {\n"
-                         "namespace y {\n"
-                         "void f() { glob::Glob g; }\n"
-                         "} // namespace y\n"
-                         "} // namespace x\n";
-  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
-}
-
 TEST_F(ChangeNamespaceTest, TypeInNestedNameSpecifier) {
   std::string Code =
       "namespace na {\n"
@@ -625,6 +546,359 @@ TEST_F(ChangeNamespaceTest, CommentsBefo
   EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
 }
 
+TEST_F(ChangeNamespaceTest, UsingShadowDeclInGlobal) {
+  std::string Code = "namespace glob {\n"
+                     "class Glob {};\n"
+                     "}\n"
+                     "using glob::Glob;\n"
+                     "namespace na {\n"
+                     "namespace nb {\n"
+                     "void f() { Glob g; }\n"
+                     "} // namespace nb\n"
+                     "} // namespace na\n";
+
+  std::string Expected = "namespace glob {\n"
+                         "class Glob {};\n"
+                         "}\n"
+                         "using glob::Glob;\n"
+                         "\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "void f() { Glob g; }\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingNamespaceInGlobal) {
+  std::string Code = "namespace glob {\n"
+                     "class Glob {};\n"
+                     "}\n"
+                     "using namespace glob;\n"
+                     "namespace na {\n"
+                     "namespace nb {\n"
+                     "void f() { Glob g; }\n"
+                     "} // namespace nb\n"
+                     "} // namespace na\n";
+
+  std::string Expected = "namespace glob {\n"
+                         "class Glob {};\n"
+                         "}\n"
+                         "using namespace glob;\n"
+                         "\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "void f() { Glob g; }\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingDeclAfterReference) {
+  std::string Code = "namespace glob {\n"
+                     "class Glob {};\n"
+                     "}\n"
+                     "namespace na {\n"
+                     "namespace nb {\n"
+                     "void f() { glob::Glob g; }\n"
+                     "} // namespace nb\n"
+                     "} // namespace na\n"
+                     "using glob::Glob;\n"
+                     "using namespace glob;\n";
+
+  std::string Expected = "namespace glob {\n"
+                         "class Glob {};\n"
+                         "}\n"
+                         "\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "void f() { glob::Glob g; }\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n"
+                         "using glob::Glob;\n"
+                         "using namespace glob;\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingNamespaceAfterReference) {
+  NewNamespace = "na::nc";
+  std::string Code = "namespace glob {\n"
+                     "class Glob {};\n"
+                     "}\n"
+                     "namespace na {\n"
+                     "namespace nb {\n"
+                     "void f() { glob::Glob g; }\n"
+                     "} // namespace nb\n"
+                     "using namespace glob;\n"
+                     "} // namespace na\n";
+
+  std::string Expected = "namespace glob {\n"
+                         "class Glob {};\n"
+                         "}\n"
+                         "namespace na {\n"
+                         "\n"
+                         "namespace nc {\n"
+                         "void f() { glob::Glob g; }\n"
+                         "} // namespace nc\n"
+                         "using namespace glob;\n"
+                         "} // namespace na\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingNamespaceAndUsingShadowInGlobal) {
+  std::string Code = "namespace glob1 {\n"
+                     "namespace glob2 {\n"
+                     "class Glob {};\n"
+                     "}\n"
+                     "}\n"
+                     "using glob1::glob2::Glob;\n"
+                     "using namespace glob1;\n"
+                     "namespace na {\n"
+                     "namespace nb {\n"
+                     "void f() { Glob g; }\n"
+                     "} // namespace nb\n"
+                     "} // namespace na\n";
+
+  std::string Expected = "namespace glob1 {\n"
+                         "namespace glob2 {\n"
+                         "class Glob {};\n"
+                         "}\n"
+                         "}\n"
+                         "using glob1::glob2::Glob;\n"
+                         "using namespace glob1;\n"
+                         "\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "void f() { Glob g; }\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingAliasInGlobal) {
+  std::string Code = "namespace glob {\n"
+                     "class Glob {};\n"
+                     "}\n"
+                     "using GLB = glob::Glob;\n"
+                     "using BLG = glob::Glob;\n"
+                     "namespace na {\n"
+                     "namespace nb {\n"
+                     "void f() { GLB g; BLG blg; }\n"
+                     "} // namespace nb\n"
+                     "} // namespace na\n";
+
+  std::string Expected = "namespace glob {\n"
+                         "class Glob {};\n"
+                         "}\n"
+                         "using GLB = glob::Glob;\n"
+                         "using BLG = glob::Glob;\n"
+                         "\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "void f() { GLB g; BLG blg; }\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingShadowDeclAndMovedNamespace) {
+  std::string Code = "namespace na { class C_A {};\n }\n"
+                     "using na::C_A;\n"
+                     "namespace na {\n"
+                     "namespace nb {\n"
+                     "class C_X {\n"
+                     "public:\n"
+                     "  C_A a;\n"
+                     "};\n"
+                     "} // namespace nb\n"
+                     "} // namespace na\n";
+  std::string Expected = "namespace na { class C_A {};\n }\n"
+                         "using na::C_A;\n"
+                         "\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "class C_X {\n"
+                         "public:\n"
+                         "  C_A a;\n"
+                         "};\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingNamespaceDeclAndMovedNamespace) {
+  std::string Code = "namespace na { class C_A {};\n }\n"
+                     "using namespace na;\n"
+                     "namespace na {\n"
+                     "namespace nb {\n"
+                     "class C_X {\n"
+                     "public:\n"
+                     "  C_A ca;\n"
+                     "};\n"
+                     "} // namespace nb\n"
+                     "} // namespace na\n";
+  std::string Expected = "namespace na { class C_A {};\n }\n"
+                         "using namespace na;\n"
+                         "\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "class C_X {\n"
+                         "public:\n"
+                         "  C_A ca;\n"
+                         "};\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingShadowDeclInFunction) {
+  std::string Code = "namespace glob {\n"
+                     "class Glob {};\n"
+                     "}\n"
+                     "namespace na {\n"
+                     "namespace nb {\n"
+                     "void f() {\n"
+                     "  using glob::Glob;\n"
+                     "  Glob g;\n"
+                     "}\n"
+                     "} // namespace nb\n"
+                     "} // namespace na\n";
+
+  std::string Expected = "namespace glob {\n"
+                         "class Glob {};\n"
+                         "}\n"
+                         "\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "void f() {\n"
+                         "  using ::glob::Glob;\n"
+                         "  Glob g;\n"
+                         "}\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingShadowDeclInClass) {
+  std::string Code = "namespace na { class C_A {};\n }\n"
+                     "namespace na {\n"
+                     "namespace nb {\n"
+                     "void f() {\n"
+                     "  using na::CA;\n"
+                     "  CA ca;\n"
+                     "}\n"
+                     "} // namespace nb\n"
+                     "} // namespace na\n";
+  std::string Expected = "namespace na { class C_A {};\n }\n"
+                         "\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "void f() {\n"
+                         "  using na::CA;\n"
+                         "  CA ca;\n"
+                         "}\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingDeclInMovedNamespace) {
+  std::string Code = "namespace nx { void f(); }\n"
+                     "namespace na {\n"
+                     "using nx::f;\n"
+                     "namespace nb {\n"
+                     "void d() { f(); }\n"
+                     "} // nb\n"
+                     "} // na\n";
+
+  std::string Expected = "namespace nx { void f(); }\n"
+                         "namespace na {\n"
+                         "using nx::f;\n"
+                         "\n"
+                         "} // na\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "void d() { nx::f(); }\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingDeclInMovedNamespaceNotNested) {
+  OldNamespace = "na";
+  std::string Code = "namespace nx { void f(); }\n"
+                     "namespace na {\n"
+                     "using ::nx::f;\n"
+                     "void d() { f(); }\n"
+                     "} // na\n";
+
+  std::string Expected = "namespace nx { void f(); }\n"
+                         "\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "using ::nx::f;\n"
+                         "void d() { f(); }\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingDeclInMovedNamespaceMultiNested) {
+  OldNamespace = "a::b::c::d";
+  NewNamespace = "a::b::x::y";
+  std::string Code = "namespace nx { void f(); void g(); }\n"
+                     "namespace a {\n"
+                     "namespace b {\n"
+                     "using ::nx::f;\n"
+                     "namespace c {\n"
+                     "using ::nx::g;\n"
+                     "namespace d {\n"
+                     "void d() { f(); g(); }\n"
+                     "} // d\n"
+                     "} // c\n"
+                     "} // b\n"
+                     "} // a\n";
+
+  std::string Expected = "namespace nx { void f(); void g(); }\n"
+                         "namespace a {\n"
+                         "namespace b {\n"
+                         "using ::nx::f;\n"
+                         "namespace c {\n"
+                         "using ::nx::g;\n"
+                         "\n"
+                         "} // c\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "void d() { f(); nx::g(); }\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n"
+                         "} // b\n"
+                         "} // a\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingDeclInTheParentOfOldNamespace) {
+  OldNamespace = "nb::nc";
+  NewNamespace = "nb::nd";
+  std::string Code = "namespace na { class A {}; }\n"
+                     "namespace nb {\n"
+                     "using na::A;\n"
+                     "namespace nc {\n"
+                     "void d() { A a; }\n"
+                     "} // nc\n"
+                     "} // nb\n";
+
+  std::string Expected = "namespace na { class A {}; }\n"
+                         "namespace nb {\n"
+                         "using na::A;\n"
+                         "\n"
+                         "namespace nd {\n"
+                         "void d() { A a; }\n"
+                         "} // namespace nd\n"
+                         "} // nb\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
 } // anonymous namespace
 } // namespace change_namespace
 } // namespace clang




More information about the cfe-commits mailing list