[clang-tools-extra] r282073 - [change-namespace] fix name qualifiers in UsingShadowDecl and NestedNameSpecifier.

Eric Liu via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 21 08:06:12 PDT 2016


Author: ioeric
Date: Wed Sep 21 10:06:12 2016
New Revision: 282073

URL: http://llvm.org/viewvc/llvm-project?rev=282073&view=rev
Log:
[change-namespace] fix name qualifiers in UsingShadowDecl and NestedNameSpecifier.

Reviewers: hokein

Subscribers: cfe-commits

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

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=282073&r1=282072&r2=282073&view=diff
==============================================================================
--- clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp (original)
+++ clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp Wed Sep 21 10:06:12 2016
@@ -231,9 +231,6 @@ ChangeNamespaceTool::ChangeNamespaceTool
 }
 
 // FIXME: handle the following symbols:
-//   - Types in `UsingShadowDecl` (e.g. `using a::b::c;`) which are not matched
-//   by `typeLoc`.
-//   - Types in nested name specifier, e.g. "na::X" in "na::X::Nested".
 //   - Function references.
 //   - Variable references.
 void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
@@ -266,7 +263,6 @@ void ChangeNamespaceTool::registerMatche
   // Match TypeLocs on the declaration. Carefully match only the outermost
   // TypeLoc that's directly linked to the old class and don't handle nested
   // name specifier locs.
-  // FIXME: match and handle nested name specifier locs.
   Finder->addMatcher(
       typeLoc(IsInMovedNs,
               loc(qualType(hasDeclaration(DeclMatcher.bind("from_decl")))),
@@ -276,6 +272,17 @@ void ChangeNamespaceTool::registerMatche
               hasAncestor(decl().bind("dc")))
           .bind("type"),
       this);
+  // Types in `UsingShadowDecl` is not matched by `typeLoc` above, so we need to
+  // special case it.
+  Finder->addMatcher(
+      usingDecl(hasAnyUsingShadowDecl(IsInMovedNs)).bind("using_decl"), this);
+  // Handle types in nested name specifier.
+  Finder->addMatcher(nestedNameSpecifierLoc(
+                         hasAncestor(decl(IsInMovedNs).bind("dc")),
+                         loc(nestedNameSpecifier(specifiesType(
+                             hasDeclaration(DeclMatcher.bind("from_decl"))))))
+                         .bind("nested_specifier_loc"),
+                     this);
 }
 
 void ChangeNamespaceTool::run(
@@ -285,6 +292,15 @@ void ChangeNamespaceTool::run(
   } 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 *Specifier =
+                 Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
+                     "nested_specifier_loc")) {
+    SourceLocation Start = Specifier->getBeginLoc();
+    SourceLocation End = EndLocationForType(Specifier->getTypeLoc());
+    fixTypeLoc(Result, Start, End, Specifier->getTypeLoc());
   } else {
     const auto *TLoc = Result.Nodes.getNodeAs<TypeLoc>("type");
     assert(TLoc != nullptr && "Expecting callback for TypeLoc");
@@ -439,6 +455,26 @@ void ChangeNamespaceTool::fixTypeLoc(
                                       FromDecl->getQualifiedNameAsString());
 }
 
+void ChangeNamespaceTool::fixUsingShadowDecl(
+    const ast_matchers::MatchFinder::MatchResult &Result,
+    const UsingDecl *UsingDeclaration) {
+  SourceLocation Start = UsingDeclaration->getLocStart();
+  SourceLocation End = UsingDeclaration->getLocEnd();
+  if (Start.isInvalid() || End.isInvalid()) return;
+
+  assert(UsingDeclaration->shadow_size() > 0);
+  // FIXME: it might not be always accurate to use the first using-decl.
+  const NamedDecl *TargetDecl =
+      UsingDeclaration->shadow_begin()->getTargetDecl();
+  std::string TargetDeclName = TargetDecl->getQualifiedNameAsString();
+  // FIXME: check if target_decl_name is in moved ns, which doesn't make much
+  // sense. If this happens, we need to use name with the new namespace.
+  // Use fully qualified name in UsingDecl for now.
+  auto R = createReplacement(Start, End, "using ::" + TargetDeclName,
+                             *Result.SourceManager);
+  addOrMergeReplacement(R, &FileToReplacements[R.getFilePath()]);
+}
+
 void ChangeNamespaceTool::onEndOfTranslationUnit() {
   // Move namespace blocks and insert forward declaration to old namespace.
   for (const auto &FileAndNsMoves : MoveNamespaces) {

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=282073&r1=282072&r2=282073&view=diff
==============================================================================
--- clang-tools-extra/trunk/change-namespace/ChangeNamespace.h (original)
+++ clang-tools-extra/trunk/change-namespace/ChangeNamespace.h Wed Sep 21 10:06:12 2016
@@ -73,6 +73,9 @@ private:
   void fixTypeLoc(const ast_matchers::MatchFinder::MatchResult &Result,
                   SourceLocation Start, SourceLocation End, TypeLoc Type);
 
+  void fixUsingShadowDecl(const ast_matchers::MatchFinder::MatchResult &Result,
+                          const UsingDecl *UsingDeclaration);
+
   // Information about moving an old namespace.
   struct MoveNamespace {
     // The start offset of the namespace block being moved in the original

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=282073&r1=282072&r2=282073&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp (original)
+++ clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp Wed Sep 21 10:06:12 2016
@@ -229,6 +229,91 @@ TEST_F(ChangeNamespaceTest, MoveFunction
   EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
 }
 
+TEST_F(ChangeNamespaceTest, FixUsingShadowDecl) {
+  std::string Code = "namespace na {\n"
+                     "namespace nc {\n"
+                     "class SAME {};\n"
+                     "}\n"
+                     "namespace nd {\n"
+                     "class SAME {};\n"
+                     "}\n"
+                     "namespace nb {\n"
+                     "using nc::SAME;\n"
+                     "using YO = nc::SAME;\n"
+                     "typedef nc::SAME IDENTICAL;\n"
+                     "void f(nd::SAME Same) {}\n"
+                     "} // namespace nb\n"
+                     "} // namespace na\n";
+
+  std::string Expected = "namespace na {\n"
+                         "namespace nc {\n"
+                         "class SAME {};\n"
+                         "}\n"
+                         "namespace nd {\n"
+                         "class SAME {};\n"
+                         "}\n"
+                         "\n"
+                         "} // namespace na\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "using ::na::nc::SAME;\n"
+                         "using YO = na::nc::SAME;\n"
+                         "typedef na::nc::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, TypeInNestedNameSpecifier) {
+  std::string Code =
+      "namespace na {\n"
+      "class C_A {\n"
+      "public:\n"
+      "  class Nested {\n"
+      "    public:\n"
+      "      static int NestedX;\n"
+      "      static void nestedFunc() {}\n"
+      "  };\n"
+      "};\n"
+      "namespace nb {\n"
+      "class C_X {\n"
+      "  C_A na;\n"
+      "  C_A::Nested nested;\n"
+      "  void f() {\n"
+      "    C_A::Nested::nestedFunc();\n"
+      "    int X = C_A::Nested::NestedX;\n"
+      "  }\n"
+      "};\n"
+      "}  // namespace nb\n"
+      "}  // namespace na\n";
+  std::string Expected =
+      "namespace na {\n"
+      "class C_A {\n"
+      "public:\n"
+      "  class Nested {\n"
+      "    public:\n"
+      "      static int NestedX;\n"
+      "      static void nestedFunc() {}\n"
+      "  };\n"
+      "};\n"
+      "\n"
+      "}  // namespace na\n"
+      "namespace x {\n"
+      "namespace y {\n"
+      "class C_X {\n"
+      "  na::C_A na;\n"
+      "  na::C_A::Nested nested;\n"
+      "  void f() {\n"
+      "    na::C_A::Nested::nestedFunc();\n"
+      "    int X = na::C_A::Nested::NestedX;\n"
+      "  }\n"
+      "};\n"
+      "}  // namespace y\n"
+      "}  // namespace x\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
 } // anonymous namespace
 } // namespace change_namespace
 } // namespace clang




More information about the cfe-commits mailing list