r316571 - [rename] support renaming class member.

Haojian Wu via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 25 04:54:45 PDT 2017


Author: hokein
Date: Wed Oct 25 04:54:45 2017
New Revision: 316571

URL: http://llvm.org/viewvc/llvm-project?rev=316571&view=rev
Log:
[rename] support renaming class member.

Reviewers: ioeric

Reviewed By: ioeric

Subscribers: klimek, cfe-commits, mgorny

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

Added:
    cfe/trunk/unittests/Rename/RenameMemberTest.cpp
Modified:
    cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
    cfe/trunk/unittests/Rename/CMakeLists.txt

Modified: cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp?rev=316571&r1=316570&r2=316571&view=diff
==============================================================================
--- cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp (original)
+++ cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp Wed Oct 25 04:54:45 2017
@@ -212,6 +212,41 @@ public:
     return true;
   }
 
+  bool VisitMemberExpr(const MemberExpr *Expr) {
+    const NamedDecl *Decl = Expr->getFoundDecl();
+    auto StartLoc = Expr->getMemberLoc();
+    auto EndLoc = Expr->getMemberLoc();
+    if (isInUSRSet(Decl)) {
+      RenameInfos.push_back({StartLoc, EndLoc,
+                            /*FromDecl=*/nullptr,
+                            /*Context=*/nullptr,
+                            /*Specifier=*/nullptr,
+                            /*IgnorePrefixQualifiers=*/true});
+    }
+    return true;
+  }
+
+  bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) {
+    // Fix the constructor initializer when renaming class members.
+    for (const auto *Initializer : CD->inits()) {
+      // Ignore implicit initializers.
+      if (!Initializer->isWritten())
+        continue;
+
+      if (const FieldDecl *FD = Initializer->getMember()) {
+        if (isInUSRSet(FD)) {
+          auto Loc = Initializer->getSourceLocation();
+          RenameInfos.push_back({Loc, Loc,
+                                 /*FromDecl=*/nullptr,
+                                 /*Context=*/nullptr,
+                                 /*Specifier=*/nullptr,
+                                 /*IgnorePrefixQualifiers=*/true});
+        }
+      }
+    }
+    return true;
+  }
+
   bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
     const NamedDecl *Decl = Expr->getFoundDecl();
     // Get the underlying declaration of the shadow declaration introduced by a
@@ -227,6 +262,20 @@ public:
                                 ? Expr->getLAngleLoc().getLocWithOffset(-1)
                                 : Expr->getLocEnd();
 
+    if (const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) {
+      if (isInUSRSet(MD)) {
+        // Handle renaming static template class methods, we only rename the
+        // name without prefix qualifiers and restrict the source range to the
+        // name.
+        RenameInfos.push_back({EndLoc, EndLoc,
+                               /*FromDecl=*/nullptr,
+                               /*Context=*/nullptr,
+                               /*Specifier=*/nullptr,
+                               /*IgnorePrefixQualifiers=*/true});
+        return true;
+      }
+    }
+
     // In case of renaming an enum declaration, we have to explicitly handle
     // unscoped enum constants referenced in expressions (e.g.
     // "auto r = ns1::ns2::Green" where Green is an enum constant of an unscoped

Modified: cfe/trunk/unittests/Rename/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Rename/CMakeLists.txt?rev=316571&r1=316570&r2=316571&view=diff
==============================================================================
--- cfe/trunk/unittests/Rename/CMakeLists.txt (original)
+++ cfe/trunk/unittests/Rename/CMakeLists.txt Wed Oct 25 04:54:45 2017
@@ -9,6 +9,7 @@ add_clang_unittest(ClangRenameTests
   RenameClassTest.cpp
   RenameEnumTest.cpp
   RenameAliasTest.cpp
+  RenameMemberTest.cpp
   RenameFunctionTest.cpp
   )
 

Added: cfe/trunk/unittests/Rename/RenameMemberTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Rename/RenameMemberTest.cpp?rev=316571&view=auto
==============================================================================
--- cfe/trunk/unittests/Rename/RenameMemberTest.cpp (added)
+++ cfe/trunk/unittests/Rename/RenameMemberTest.cpp Wed Oct 25 04:54:45 2017
@@ -0,0 +1,229 @@
+//===-- ClangMemberTests.cpp - unit tests for renaming class members ------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangRenameTest.h"
+
+namespace clang {
+namespace clang_rename {
+namespace test {
+namespace {
+
+class RenameMemberTest : public ClangRenameTest {
+public:
+  RenameMemberTest() {
+    AppendToHeader(R"(
+        struct NA {
+          void Foo();
+          void NotFoo();
+          static void SFoo();
+          static void SNotFoo();
+          int Moo;
+        };
+        struct A {
+          virtual void Foo();
+          void NotFoo();
+          static void SFoo();
+          static void SNotFoo();
+          int Moo;
+          int NotMoo;
+          static int SMoo;
+        };
+        struct B : public A {
+          void Foo() override;
+        };
+        template <typename T> struct TA {
+          T* Foo();
+          T* NotFoo();
+          static T* SFoo();
+          static T* NotSFoo();
+        };
+        template <typename T> struct TB : public TA<T> {};
+        namespace ns {
+          template <typename T> struct TA {
+            T* Foo();
+            T* NotFoo();
+            static T* SFoo();
+            static T* NotSFoo();
+            static int SMoo;
+          };
+          template <typename T> struct TB : public TA<T> {};
+          struct A {
+            void Foo();
+            void NotFoo();
+            static void SFoo();
+            static void SNotFoo();
+          };
+          struct B : public A {};
+          struct C {
+            template <class T>
+            void SFoo(const T& t) {}
+            template <class T>
+            void Foo() {}
+          };
+        })");
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(
+    DISABLED_RenameTemplatedClassStaticVariableTest, RenameMemberTest,
+    testing::ValuesIn(std::vector<Case>({
+        // FIXME: support renaming static variables for template classes.
+        {"void f() { ns::TA<int>::SMoo; }",
+         "void f() { ns::TA<int>::SMeh; }", "ns::TA::SMoo", "ns::TA::SMeh"},
+    })), );
+
+INSTANTIATE_TEST_CASE_P(
+    RenameMemberTest, RenameMemberTest,
+    testing::ValuesIn(std::vector<Case>({
+        // Normal methods and fields.
+        {"void f() { A a; a.Foo(); }", "void f() { A a; a.Bar(); }", "A::Foo",
+         "A::Bar"},
+        {"void f() { ns::A a; a.Foo(); }", "void f() { ns::A a; a.Bar(); }",
+         "ns::A::Foo", "ns::A::Bar"},
+        {"void f() { A a; int x = a.Moo; }", "void f() { A a; int x = a.Meh; }",
+         "A::Moo", "A::Meh"},
+        {"void f() { B b; b.Foo(); }", "void f() { B b; b.Bar(); }", "B::Foo",
+         "B::Bar"},
+        {"void f() { ns::B b; b.Foo(); }", "void f() { ns::B b; b.Bar(); }",
+         "ns::A::Foo", "ns::A::Bar"},
+        {"void f() { B b; int x = b.Moo; }", "void f() { B b; int x = b.Meh; }",
+         "A::Moo", "A::Meh"},
+
+        // Static methods.
+        {"void f() { A::SFoo(); }", "void f() { A::SBar(); }", "A::SFoo",
+         "A::SBar"},
+        {"void f() { ns::A::SFoo(); }", "void f() { ns::A::SBar(); }",
+         "ns::A::SFoo", "ns::A::SBar"},
+        {"void f() { TA<int>::SFoo(); }", "void f() { TA<int>::SBar(); }",
+         "TA::SFoo", "TA::SBar"},
+        {"void f() { ns::TA<int>::SFoo(); }",
+         "void f() { ns::TA<int>::SBar(); }", "ns::TA::SFoo", "ns::TA::SBar"},
+
+        // Static variables.
+        {"void f() { A::SMoo; }",
+         "void f() { A::SMeh; }", "A::SMoo", "A::SMeh"},
+
+        // Templated methods.
+        {"void f() { TA<int> a; a.Foo(); }", "void f() { TA<int> a; a.Bar(); }",
+         "TA::Foo", "TA::Bar"},
+        {"void f() { ns::TA<int> a; a.Foo(); }",
+         "void f() { ns::TA<int> a; a.Bar(); }", "ns::TA::Foo", "ns::TA::Bar"},
+        {"void f() { TB<int> b; b.Foo(); }", "void f() { TB<int> b; b.Bar(); }",
+         "TA::Foo", "TA::Bar"},
+        {"void f() { ns::TB<int> b; b.Foo(); }",
+         "void f() { ns::TB<int> b; b.Bar(); }", "ns::TA::Foo", "ns::TA::Bar"},
+        {"void f() { ns::C c; int x; c.SFoo(x); }",
+         "void f() { ns::C c; int x; c.SBar(x); }", "ns::C::SFoo",
+         "ns::C::SBar"},
+        {"void f() { ns::C c; c.Foo<int>(); }",
+         "void f() { ns::C c; c.Bar<int>(); }", "ns::C::Foo", "ns::C::Bar"},
+
+        // Pointers to methods.
+        {"void f() { auto p = &A::Foo; }", "void f() { auto p = &A::Bar; }",
+         "A::Foo", "A::Bar"},
+        {"void f() { auto p = &A::SFoo; }", "void f() { auto p = &A::SBar; }",
+         "A::SFoo", "A::SBar"},
+        {"void f() { auto p = &B::Foo; }", "void f() { auto p = &B::Bar; }",
+         "B::Foo", "B::Bar"},
+        {"void f() { auto p = &ns::A::Foo; }",
+         "void f() { auto p = &ns::A::Bar; }", "ns::A::Foo", "ns::A::Bar"},
+        {"void f() { auto p = &ns::A::SFoo; }",
+         "void f() { auto p = &ns::A::SBar; }", "ns::A::SFoo", "ns::A::SBar"},
+        {"void f() { auto p = &ns::C::SFoo<int>; }",
+         "void f() { auto p = &ns::C::SBar<int>; }", "ns::C::SFoo",
+         "ns::C::SBar"},
+
+        // These methods are not declared or overrided in the subclass B, we
+        // have to use the qualified name with parent class A to identify them.
+        {"void f() { auto p = &ns::B::Foo; }",
+         "void f() { auto p = &ns::B::Bar; }", "ns::A::Foo", "ns::B::Bar"},
+        {"void f() { B::SFoo(); }", "void f() { B::SBar(); }", "A::SFoo",
+         "B::SBar"},
+        {"void f() { ns::B::SFoo(); }", "void f() { ns::B::SBar(); }",
+         "ns::A::SFoo", "ns::B::SBar"},
+        {"void f() { auto p = &B::SFoo; }", "void f() { auto p = &B::SBar; }",
+         "A::SFoo", "B::SBar"},
+        {"void f() { auto p = &ns::B::SFoo; }",
+         "void f() { auto p = &ns::B::SBar; }", "ns::A::SFoo", "ns::B::SBar"},
+        {"void f() { TB<int>::SFoo(); }", "void f() { TB<int>::SBar(); }",
+         "TA::SFoo", "TB::SBar"},
+        {"void f() { ns::TB<int>::SFoo(); }",
+         "void f() { ns::TB<int>::SBar(); }", "ns::TA::SFoo", "ns::TB::SBar"},
+    })), );
+
+TEST_P(RenameMemberTest, RenameMembers) {
+  auto Param = GetParam();
+  assert(!Param.OldName.empty());
+  assert(!Param.NewName.empty());
+  std::string Actual =
+      runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
+  CompareSnippets(Param.After, Actual);
+}
+
+TEST_F(RenameMemberTest, RenameMemberInsideClassMethods) {
+  std::string Before = R"(
+      struct X {
+        int Moo;
+        void Baz() { Moo = 1; }
+      };)";
+  std::string Expected = R"(
+      struct X {
+        int Meh;
+        void Baz() { Meh = 1; }
+      };)";
+  std::string After = runClangRenameOnCode(Before, "X::Moo", "Y::Meh");
+  CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameMemberTest, RenameMethodInsideClassMethods) {
+  std::string Before = R"(
+      struct X {
+        void Foo() {}
+        void Baz() { Foo(); }
+      };)";
+  std::string Expected = R"(
+      struct X {
+        void Bar() {}
+        void Baz() { Bar(); }
+      };)";
+  std::string After = runClangRenameOnCode(Before, "X::Foo", "X::Bar");
+  CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameMemberTest, RenameCtorInitializer) {
+  std::string Before = R"(
+      class X {
+      public:
+       X();
+       A a;
+       A a2;
+       B b;
+      };
+
+      X::X():a(), b() {}
+      )";
+  std::string Expected = R"(
+      class X {
+      public:
+       X();
+       A bar;
+       A a2;
+       B b;
+      };
+
+      X::X():bar(), b() {}
+      )";
+  std::string After = runClangRenameOnCode(Before, "X::a", "X::bar");
+  CompareSnippets(Expected, After);
+}
+
+} // anonymous namespace
+} // namespace test
+} // namespace clang_rename
+} // namesdpace clang




More information about the cfe-commits mailing list