diff options
Diffstat (limited to 'unittests/Rename')
-rw-r--r-- | unittests/Rename/CMakeLists.txt | 5 | ||||
-rw-r--r-- | unittests/Rename/RenameAliasTest.cpp | 304 | ||||
-rw-r--r-- | unittests/Rename/RenameClassTest.cpp | 143 | ||||
-rw-r--r-- | unittests/Rename/RenameEnumTest.cpp | 189 | ||||
-rw-r--r-- | unittests/Rename/RenameFunctionTest.cpp | 574 | ||||
-rw-r--r-- | unittests/Rename/RenameMemberTest.cpp | 229 |
6 files changed, 1430 insertions, 14 deletions
diff --git a/unittests/Rename/CMakeLists.txt b/unittests/Rename/CMakeLists.txt index aa7609260cc0c..b625a7a691fbb 100644 --- a/unittests/Rename/CMakeLists.txt +++ b/unittests/Rename/CMakeLists.txt @@ -7,9 +7,14 @@ include_directories(${CLANG_SOURCE_DIR}) add_clang_unittest(ClangRenameTests RenameClassTest.cpp + RenameEnumTest.cpp + RenameAliasTest.cpp + RenameMemberTest.cpp + RenameFunctionTest.cpp ) target_link_libraries(ClangRenameTests + PRIVATE clangAST clangASTMatchers clangBasic diff --git a/unittests/Rename/RenameAliasTest.cpp b/unittests/Rename/RenameAliasTest.cpp new file mode 100644 index 0000000000000..59becaef68a10 --- /dev/null +++ b/unittests/Rename/RenameAliasTest.cpp @@ -0,0 +1,304 @@ +//===-- RenameAliasTest.cpp - unit tests for renaming alias ---------------===// +// +// 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 RenameAliasTest : public ClangRenameTest { +public: + RenameAliasTest() { + AppendToHeader(R"( + #define MACRO(x) x + namespace some_ns { + class A { + public: + void foo() {} + struct Nested { + enum NestedEnum { + E1, E2, + }; + }; + }; + } // namespace some_ns + namespace a { + typedef some_ns::A TA; + using UA = some_ns::A; + } // namespace a + namespace b { + typedef some_ns::A TA; + using UA = some_ns::A; + } + template <typename T> class ptr {}; + template <typename T> + + using TPtr = ptr<int>; + )"); + } +}; + +INSTANTIATE_TEST_CASE_P( + RenameAliasTests, RenameAliasTest, + testing::ValuesIn(std::vector<Case>({ + // basic functions + {"void f(a::TA a1) {}", "void f(b::TB a1) {}", "a::TA", "b::TB"}, + {"void f(a::UA a1) {}", "void f(b::UB a1) {}", "a::UA", "b::UB"}, + {"void f(a::TA* a1) {}", "void f(b::TB* a1) {}", "a::TA", "b::TB"}, + {"void f(a::TA** a1) {}", "void f(b::TB** a1) {}", "a::TA", "b::TB"}, + {"a::TA f() { return a::TA(); }", "b::TB f() { return b::TB(); }", + "a::TA", "b::TB"}, + {"a::TA f() { return a::UA(); }", "b::TB f() { return a::UA(); }", + "a::TA", "b::TB"}, + {"a::TA f() { return a::UA(); }", "a::TA f() { return b::UB(); }", + "a::UA", "b::UB"}, + {"void f() { a::TA a; }", "void f() { b::TB a; }", "a::TA", "b::TB"}, + {"void f(const a::TA& a1) {}", "void f(const b::TB& a1) {}", "a::TA", + "b::TB"}, + {"void f(const a::UA& a1) {}", "void f(const b::UB& a1) {}", "a::UA", + "b::UB"}, + {"void f(const a::TA* a1) {}", "void f(const b::TB* a1) {}", "a::TA", + "b::TB"}, + {"namespace a { void f(TA a1) {} }", + "namespace a { void f(b::TB a1) {} }", "a::TA", "b::TB"}, + {"void f(MACRO(a::TA) a1) {}", "void f(MACRO(b::TB) a1) {}", "a::TA", + "b::TB"}, + {"void f(MACRO(a::TA a1)) {}", "void f(MACRO(b::TB a1)) {}", "a::TA", + "b::TB"}, + + // shorten/add namespace. + {"namespace b { void f(a::UA a1) {} }", + "namespace b {void f(UB a1) {} }", "a::UA", "b::UB"}, + {"namespace a { void f(UA a1) {} }", + "namespace a {void f(b::UB a1) {} }", "a::UA", "b::UB"}, + + // use namespace and typedefs + {"struct S { using T = a::TA; T a_; };", + "struct S { using T = b::TB; T a_; };", "a::TA", "b::TB"}, + {"using T = a::TA; T gA;", "using T = b::TB; T gA;", "a::TA", "b::TB"}, + {"using T = a::UA; T gA;", "using T = b::UB; T gA;", "a::UA", "b::UB"}, + {"typedef a::TA T; T gA;", "typedef b::TB T; T gA;", "a::TA", "b::TB"}, + {"typedef a::UA T; T gA;", "typedef b::UB T; T gA;", "a::UA", "b::UB"}, + {"typedef MACRO(a::TA) T; T gA;", "typedef MACRO(b::TB) T; T gA;", + "a::TA", "b::TB"}, + + // types in using shadows. + {"using a::TA; TA gA;", "using b::TB; b::TB gA;", "a::TA", "b::TB"}, + {"using a::UA; UA gA;", "using b::UB; b::UB gA;", "a::UA", "b::UB"}, + + // struct members and other oddities + {"struct S : public a::TA {};", "struct S : public b::TB {};", "a::TA", + "b::TB"}, + {"struct S : public a::UA {};", "struct S : public b::UB {};", "a::UA", + "b::UB"}, + {"struct F { void f(a::TA a1) {} };", + "struct F { void f(b::TB a1) {} };", "a::TA", "b::TB"}, + {"struct F { a::TA a_; };", "struct F { b::TB a_; };", "a::TA", + "b::TB"}, + {"struct F { ptr<a::TA> a_; };", "struct F { ptr<b::TB> a_; };", + "a::TA", "b::TB"}, + {"struct F { ptr<a::UA> a_; };", "struct F { ptr<b::UB> a_; };", + "a::UA", "b::UB"}, + + // types in nested name specifiers + {"void f() { a::TA::Nested ne; }", "void f() { b::TB::Nested ne; }", + "a::TA", "b::TB"}, + {"void f() { a::UA::Nested ne; }", "void f() { b::UB::Nested ne; }", + "a::UA", "b::UB"}, + {"void f() { a::TA::Nested::NestedEnum e; }", + "void f() { b::TB::Nested::NestedEnum e; }", "a::TA", "b::TB"}, + {"void f() { auto e = a::TA::Nested::NestedEnum::E1; }", + "void f() { auto e = b::TB::Nested::NestedEnum::E1; }", "a::TA", + "b::TB"}, + {"void f() { auto e = a::TA::Nested::E1; }", + "void f() { auto e = b::TB::Nested::E1; }", "a::TA", "b::TB"}, + + // templates + {"template <typename T> struct Foo { T t; }; void f() { Foo<a::TA> " + "foo; }", + "template <typename T> struct Foo { T t; }; void f() { Foo<b::TB> " + "foo; }", + "a::TA", "b::TB"}, + {"template <typename T> struct Foo { a::TA a; };", + "template <typename T> struct Foo { b::TB a; };", "a::TA", "b::TB"}, + {"template <typename T> void f(T t) {} void g() { f<a::TA>(a::TA()); }", + "template <typename T> void f(T t) {} void g() { f<b::TB>(b::TB()); }", + "a::TA", "b::TB"}, + {"template <typename T> void f(T t) {} void g() { f<a::UA>(a::UA()); }", + "template <typename T> void f(T t) {} void g() { f<b::UB>(b::UB()); }", + "a::UA", "b::UB"}, + {"template <typename T> int f() { return 1; } template <> int " + "f<a::TA>() { return 2; } int g() { return f<a::TA>(); }", + "template <typename T> int f() { return 1; } template <> int " + "f<b::TB>() { return 2; } int g() { return f<b::TB>(); }", + "a::TA", "b::TB"}, + {"struct Foo { template <typename T> T foo(); }; void g() { Foo f; " + "auto a = f.template foo<a::TA>(); }", + "struct Foo { template <typename T> T foo(); }; void g() { Foo f; " + "auto a = f.template foo<b::TB>(); }", + "a::TA", "b::TB"}, + {"struct Foo { template <typename T> T foo(); }; void g() { Foo f; " + "auto a = f.template foo<a::UA>(); }", + "struct Foo { template <typename T> T foo(); }; void g() { Foo f; " + "auto a = f.template foo<b::UB>(); }", + "a::UA", "b::UB"}, + + // The following two templates are distilled from regressions found in + // unique_ptr<> and type_traits.h + {"template <typename T> struct outer { typedef T type; type Baz(); }; " + "outer<a::TA> g_A;", + "template <typename T> struct outer { typedef T type; type Baz(); }; " + "outer<b::TB> g_A;", + "a::TA", "b::TB"}, + {"template <typename T> struct nested { typedef T type; }; template " + "<typename T> struct outer { typename nested<T>::type Foo(); }; " + "outer<a::TA> g_A;", + "template <typename T> struct nested { typedef T type; }; template " + "<typename T> struct outer { typename nested<T>::type Foo(); }; " + "outer<b::TB> g_A;", + "a::TA", "b::TB"}, + + // macros + {"#define FOO(T, t) T t\nvoid f() { FOO(a::TA, a1); FOO(a::TA, a2); }", + "#define FOO(T, t) T t\nvoid f() { FOO(b::TB, a1); FOO(b::TB, a2); }", + "a::TA", "b::TB"}, + {"#define FOO(n) a::TA n\nvoid f() { FOO(a1); FOO(a2); }", + "#define FOO(n) b::TB n\nvoid f() { FOO(a1); FOO(a2); }", "a::TA", + "b::TB"}, + {"#define FOO(n) a::UA n\nvoid f() { FOO(a1); FOO(a2); }", + "#define FOO(n) b::UB n\nvoid f() { FOO(a1); FOO(a2); }", "a::UA", + "b::UB"}, + + // Pointer to member functions + {"auto gA = &a::TA::foo;", "auto gA = &b::TB::foo;", "a::TA", "b::TB"}, + {"using a::TA; auto gA = &TA::foo;", + "using b::TB; auto gA = &b::TB::foo;", "a::TA", "b::TB"}, + {"typedef a::TA T; auto gA = &T::foo;", + "typedef b::TB T; auto gA = &T::foo;", "a::TA", "b::TB"}, + {"auto gA = &MACRO(a::TA)::foo;", "auto gA = &MACRO(b::TB)::foo;", + "a::TA", "b::TB"}, + + // templated using alias. + {"void f(TPtr<int> p) {}", "void f(NewTPtr<int> p) {}", "TPtr", + "NewTPtr"}, + {"void f(::TPtr<int> p) {}", "void f(::NewTPtr<int> p) {}", "TPtr", + "NewTPtr"}, + })), ); + +TEST_P(RenameAliasTest, RenameAlias) { + 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(RenameAliasTest, RenameTypedefDefinitions) { + std::string Before = R"( + class X {}; + typedef X TOld; + )"; + std::string Expected = R"( + class X {}; + typedef X TNew; + )"; + std::string After = runClangRenameOnCode(Before, "TOld", "TNew"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameAliasTest, RenameUsingAliasDefinitions) { + std::string Before = R"( + class X {}; + using UOld = X; + )"; + std::string Expected = R"( + class X {}; + using UNew = X; + )"; + std::string After = runClangRenameOnCode(Before, "UOld", "UNew"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameAliasTest, RenameTemplatedAliasDefinitions) { + std::string Before = R"( + template <typename T> + class X { T t; }; + + template <typename T> + using Old = X<T>; + )"; + std::string Expected = R"( + template <typename T> + class X { T t; }; + + template <typename T> + using New = X<T>; + )"; + std::string After = runClangRenameOnCode(Before, "Old", "New"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameAliasTest, RenameAliasesInNamespaces) { + std::string Before = R"( + namespace x { class X {}; } + namespace ns { + using UOld = x::X; + } + )"; + std::string Expected = R"( + namespace x { class X {}; } + namespace ns { + using UNew = x::X; + } + )"; + std::string After = runClangRenameOnCode(Before, "ns::UOld", "ns::UNew"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameAliasTest, AliasesInMacros) { + std::string Before = R"( + namespace x { class Old {}; } + namespace ns { + #define REF(alias) alias alias_var; + + #define ALIAS(old) \ + using old##Alias = x::old; \ + REF(old##Alias); + + ALIAS(Old); + + OldAlias old_alias; + } + )"; + std::string Expected = R"( + namespace x { class Old {}; } + namespace ns { + #define REF(alias) alias alias_var; + + #define ALIAS(old) \ + using old##Alias = x::old; \ + REF(old##Alias); + + ALIAS(Old); + + NewAlias old_alias; + } + )"; + std::string After = + runClangRenameOnCode(Before, "ns::OldAlias", "ns::NewAlias"); + CompareSnippets(Expected, After); +} + +} // anonymous namespace +} // namespace test +} // namespace clang_rename +} // namesdpace clang diff --git a/unittests/Rename/RenameClassTest.cpp b/unittests/Rename/RenameClassTest.cpp index 29b4594fb0a4a..5845d63412b6b 100644 --- a/unittests/Rename/RenameClassTest.cpp +++ b/unittests/Rename/RenameClassTest.cpp @@ -51,6 +51,7 @@ INSTANTIATE_TEST_CASE_P( testing::ValuesIn(std::vector<Case>({ // basic classes {"a::Foo f;", "b::Bar f;", "", ""}, + {"::a::Foo f;", "::b::Bar f;", "", ""}, {"void f(a::Foo f) {}", "void f(b::Bar f) {}", "", ""}, {"void f(a::Foo *f) {}", "void f(b::Bar *f) {}", "", ""}, {"a::Foo f() { return a::Foo(); }", "b::Bar f() { return b::Bar(); }", @@ -469,8 +470,6 @@ TEST_F(ClangRenameTest, RenameClassWithInlineMembers) { CompareSnippets(Expected, After); } -// FIXME: no prefix qualifiers being added to the class definition and -// constructor. TEST_F(ClangRenameTest, RenameClassWithNamespaceWithInlineMembers) { std::string Before = R"( namespace ns { @@ -488,9 +487,9 @@ TEST_F(ClangRenameTest, RenameClassWithNamespaceWithInlineMembers) { )"; std::string Expected = R"( namespace ns { - class ns::New { + class New { public: - ns::New() {} + New() {} ~New() {} New* next() { return next_; } @@ -504,8 +503,6 @@ TEST_F(ClangRenameTest, RenameClassWithNamespaceWithInlineMembers) { CompareSnippets(Expected, After); } -// FIXME: no prefix qualifiers being added to the class definition and -// constructor. TEST_F(ClangRenameTest, RenameClassWithNamespaceWithOutOfInlineMembers) { std::string Before = R"( namespace ns { @@ -527,9 +524,9 @@ TEST_F(ClangRenameTest, RenameClassWithNamespaceWithOutOfInlineMembers) { )"; std::string Expected = R"( namespace ns { - class ns::New { + class New { public: - ns::New(); + New(); ~New(); New* next(); @@ -538,7 +535,7 @@ TEST_F(ClangRenameTest, RenameClassWithNamespaceWithOutOfInlineMembers) { New* next_; }; - New::ns::New() {} + New::New() {} New::~New() {} New* New::next() { return next_; } } // namespace ns @@ -547,12 +544,12 @@ TEST_F(ClangRenameTest, RenameClassWithNamespaceWithOutOfInlineMembers) { CompareSnippets(Expected, After); } -// FIXME: no prefix qualifiers being added to the definition. TEST_F(ClangRenameTest, RenameClassInInheritedConstructor) { // `using Base::Base;` will generate an implicit constructor containing usage // of `::ns::Old` which should not be matched. std::string Before = R"( namespace ns { + class Old; class Old { int x; }; @@ -574,7 +571,8 @@ TEST_F(ClangRenameTest, RenameClassInInheritedConstructor) { })"; std::string Expected = R"( namespace ns { - class ns::New { + class New; + class New { int x; }; class Base { @@ -615,7 +613,7 @@ TEST_F(ClangRenameTest, DontRenameReferencesInImplicitFunction) { )"; std::string Expected = R"( namespace ns { - class ::new_ns::New { + class New { }; } // namespace ns struct S { @@ -632,7 +630,6 @@ TEST_F(ClangRenameTest, DontRenameReferencesInImplicitFunction) { CompareSnippets(Expected, After); } -// FIXME: no prefix qualifiers being adding to the definition. TEST_F(ClangRenameTest, ReferencesInLambdaFunctionParameters) { std::string Before = R"( template <class T> @@ -669,7 +666,7 @@ TEST_F(ClangRenameTest, ReferencesInLambdaFunctionParameters) { }; namespace ns { - class ::new_ns::New {}; + class New {}; void f() { function<void(::new_ns::New)> func; } @@ -678,6 +675,124 @@ TEST_F(ClangRenameTest, ReferencesInLambdaFunctionParameters) { CompareSnippets(Expected, After); } +TEST_F(ClangRenameTest, DontChangeIfSameName) { + std::string Before = R"( + namespace foo { + class Old { + public: + static void foo() {} + }; + } + + void f(foo::Old * x) { + foo::Old::foo() ; + } + using foo::Old;)"; + std::string Expected = R"( + namespace foo { + class Old { + public: + static void foo() {} + }; + } + + void f(foo::Old * x) { + foo::Old::foo() ; + } + using foo::Old;)"; + std::string After = runClangRenameOnCode(Before, "foo::Old", "foo::Old"); + CompareSnippets(Expected, After); +} + +TEST_F(ClangRenameTest, ChangeIfNewNameWithLeadingDotDot) { + std::string Before = R"( + namespace foo { + class Old { + public: + static void foo() {} + }; + } + + void f(foo::Old * x) { + foo::Old::foo() ; + } + using foo::Old;)"; + std::string Expected = R"( + namespace foo { + class Old { + public: + static void foo() {} + }; + } + + void f(::foo::Old * x) { + ::foo::Old::foo() ; + } + using ::foo::Old;)"; + std::string After = runClangRenameOnCode(Before, "foo::Old", "::foo::Old"); + CompareSnippets(Expected, After); +} + +TEST_F(ClangRenameTest, ChangeIfSameNameWithLeadingDotDot) { + std::string Before = R"( + namespace foo { + class Old { + public: + static void foo() {} + }; + } + + void f(foo::Old * x) { + foo::Old::foo() ; + } + using foo::Old;)"; + std::string Expected = R"( + namespace foo { + class Old { + public: + static void foo() {} + }; + } + + void f(::foo::Old * x) { + ::foo::Old::foo() ; + } + using ::foo::Old;)"; + std::string After = runClangRenameOnCode(Before, "::foo::Old", "::foo::Old"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameClassTest, UsingAlias) { + std::string Before = R"( + namespace a { struct A {}; } + + namespace foo { + using Alias = a::A; + Alias a; + })"; + std::string Expected = R"( + namespace a { struct B {}; } + + namespace foo { + using Alias = b::B; + Alias a; + })"; + std::string After = runClangRenameOnCode(Before, "a::A", "b::B"); + CompareSnippets(Expected, After); +} + +TEST_F(ClangRenameTest, NestedTemplates) { + std::string Before = R"( + namespace a { template <typename T> struct A {}; } + a::A<a::A<int>> foo;)"; + std::string Expected = R"( + namespace a { template <typename T> struct B {}; } + b::B<b::B<int>> foo;)"; + std::string After = runClangRenameOnCode(Before, "a::A", "b::B"); + CompareSnippets(Expected, After); +} + + } // anonymous namespace } // namespace test } // namespace clang_rename diff --git a/unittests/Rename/RenameEnumTest.cpp b/unittests/Rename/RenameEnumTest.cpp new file mode 100644 index 0000000000000..55dcd11ac4128 --- /dev/null +++ b/unittests/Rename/RenameEnumTest.cpp @@ -0,0 +1,189 @@ +#include "ClangRenameTest.h" + +namespace clang { +namespace clang_rename { +namespace test { +namespace { + +class RenameEnumTest : public ClangRenameTest { +public: + RenameEnumTest() { + AppendToHeader(R"( + #define MACRO(x) x + namespace a { + enum A1 { Red }; + enum class A2 { Blue }; + struct C { + enum NestedEnum { White }; + enum class NestedScopedEnum { Black }; + }; + namespace d { + enum A3 { Orange }; + } // namespace d + enum A4 { Pink }; + } // namespace a + enum A5 { Green };)"); + } +}; + +INSTANTIATE_TEST_CASE_P( + RenameEnumTests, RenameEnumTest, + testing::ValuesIn(std::vector<Case>({ + {"void f(a::A2 arg) { a::A2 t = a::A2::Blue; }", + "void f(b::B2 arg) { b::B2 t = b::B2::Blue; }", "a::A2", "b::B2"}, + {"void f() { a::A1* t1; }", "void f() { b::B1* t1; }", "a::A1", + "b::B1"}, + {"void f() { a::A2* t1; }", "void f() { b::B2* t1; }", "a::A2", + "b::B2"}, + {"void f() { enum a::A2 t = a::A2::Blue; }", + "void f() { enum b::B2 t = b::B2::Blue; }", "a::A2", "b::B2"}, + {"void f() { enum a::A2 t = a::A2::Blue; }", + "void f() { enum b::B2 t = b::B2::Blue; }", "a::A2", "b::B2"}, + + {"void f() { a::A1 t = a::Red; }", "void f() { b::B1 t = b::B1::Red; }", + "a::A1", "b::B1"}, + {"void f() { a::A1 t = a::A1::Red; }", + "void f() { b::B1 t = b::B1::Red; }", "a::A1", "b::B1"}, + {"void f() { auto t = a::Red; }", "void f() { auto t = b::B1::Red; }", + "a::A1", "b::B1"}, + {"namespace b { void f() { a::A1 t = a::Red; } }", + "namespace b { void f() { B1 t = B1::Red; } }", "a::A1", "b::B1"}, + {"void f() { a::d::A3 t = a::d::Orange; }", + "void f() { a::b::B3 t = a::b::B3::Orange; }", "a::d::A3", "a::b::B3"}, + {"namespace a { void f() { a::d::A3 t = a::d::Orange; } }", + "namespace a { void f() { b::B3 t = b::B3::Orange; } }", "a::d::A3", + "a::b::B3"}, + {"void f() { A5 t = Green; }", "void f() { B5 t = Green; }", "A5", + "B5"}, + // FIXME: the new namespace qualifier should be added to the unscoped + // enum constant. + {"namespace a { void f() { auto t = Green; } }", + "namespace a { void f() { auto t = Green; } }", "a::A1", "b::B1"}, + + // namespace qualifiers + {"namespace a { void f(A1 a1) {} }", + "namespace a { void f(b::B1 a1) {} }", "a::A1", "b::B1"}, + {"namespace a { void f(A2 a2) {} }", + "namespace a { void f(b::B2 a2) {} }", "a::A2", "b::B2"}, + {"namespace b { void f(a::A1 a1) {} }", + "namespace b { void f(B1 a1) {} }", "a::A1", "b::B1"}, + {"namespace b { void f(a::A2 a2) {} }", + "namespace b { void f(B2 a2) {} }", "a::A2", "b::B2"}, + + // nested enums + {"void f() { a::C::NestedEnum t = a::C::White; }", + "void f() { a::C::NewNestedEnum t = a::C::NewNestedEnum::White; }", + "a::C::NestedEnum", "a::C::NewNestedEnum"}, + {"void f() { a::C::NestedScopedEnum t = a::C::NestedScopedEnum::Black; " + "}", + "void f() { a::C::NewNestedScopedEnum t = " + "a::C::NewNestedScopedEnum::Black; }", + "a::C::NestedScopedEnum", "a::C::NewNestedScopedEnum"}, + + // macros + {"void f(MACRO(a::A1) a1) {}", "void f(MACRO(b::B1) a1) {}", "a::A1", + "b::B1"}, + {"void f(MACRO(a::A2) a2) {}", "void f(MACRO(b::B2) a2) {}", "a::A2", + "b::B2"}, + {"#define FOO(T, t) T t\nvoid f() { FOO(a::A1, a1); }", + "#define FOO(T, t) T t\nvoid f() { FOO(b::B1, a1); }", "a::A1", + "b::B1"}, + {"#define FOO(T, t) T t\nvoid f() { FOO(a::A2, a2); }", + "#define FOO(T, t) T t\nvoid f() { FOO(b::B2, a2); }", "a::A2", + "b::B2"}, + {"#define FOO(n) a::A1 n\nvoid f() { FOO(a1); FOO(a2); }", + "#define FOO(n) b::B1 n\nvoid f() { FOO(a1); FOO(a2); }", "a::A1", + "b::B1"}, + + // using and type alias + {"using a::A1; A1 gA;", "using b::B1; b::B1 gA;", "a::A1", "b::B1"}, + {"using a::A2; A2 gA;", "using b::B2; b::B2 gA;", "a::A2", "b::B2"}, + {"struct S { using T = a::A1; T a_; };", + "struct S { using T = b::B1; T a_; };", "a::A1", "b::B1"}, + {"using T = a::A1; T gA;", "using T = b::B1; T gA;", "a::A1", "b::B1"}, + {"using T = a::A2; T gA;", "using T = b::B2; T gA;", "a::A2", "b::B2"}, + {"typedef a::A1 T; T gA;", "typedef b::B1 T; T gA;", "a::A1", "b::B1"}, + {"typedef a::A2 T; T gA;", "typedef b::B2 T; T gA;", "a::A2", "b::B2"}, + {"typedef MACRO(a::A1) T; T gA;", "typedef MACRO(b::B1) T; T gA;", + "a::A1", "b::B1"}, + + // templates + {"template<typename T> struct Foo { T t; }; void f() { Foo<a::A1> " + "foo1; }", + "template<typename T> struct Foo { T t; }; void f() { Foo<b::B1> " + "foo1; }", + "a::A1", "b::B1"}, + {"template<typename T> struct Foo { T t; }; void f() { Foo<a::A2> " + "foo2; }", + "template<typename T> struct Foo { T t; }; void f() { Foo<b::B2> " + "foo2; }", + "a::A2", "b::B2"}, + {"template<typename T> struct Foo { a::A1 a1; };", + "template<typename T> struct Foo { b::B1 a1; };", "a::A1", "b::B1"}, + {"template<typename T> struct Foo { a::A2 a2; };", + "template<typename T> struct Foo { b::B2 a2; };", "a::A2", "b::B2"}, + {"template<typename T> int f() { return 1; } template<> int f<a::A1>() " + "{ return 2; } int g() { return f<a::A1>(); }", + "template<typename T> int f() { return 1; } template<> int f<b::B1>() " + "{ return 2; } int g() { return f<b::B1>(); }", + "a::A1", "b::B1"}, + {"template<typename T> int f() { return 1; } template<> int f<a::A2>() " + "{ return 2; } int g() { return f<a::A2>(); }", + "template<typename T> int f() { return 1; } template<> int f<b::B2>() " + "{ return 2; } int g() { return f<b::B2>(); }", + "a::A2", "b::B2"}, + {"struct Foo { template <typename T> T foo(); }; void g() { Foo f; " + "f.foo<a::A1>(); }", + "struct Foo { template <typename T> T foo(); }; void g() { Foo f; " + "f.foo<b::B1>(); }", + "a::A1", "b::B1"}, + {"struct Foo { template <typename T> T foo(); }; void g() { Foo f; " + "f.foo<a::A2>(); }", + "struct Foo { template <typename T> T foo(); }; void g() { Foo f; " + "f.foo<b::B2>(); }", + "a::A2", "b::B2"}, + })), ); + +TEST_P(RenameEnumTest, RenameEnums) { + 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(RenameEnumTest, RenameEnumDecl) { + std::string Before = R"( + namespace ns { + enum Old1 { Blue }; + } + )"; + std::string Expected = R"( + namespace ns { + enum New1 { Blue }; + } + )"; + std::string After = runClangRenameOnCode(Before, "ns::Old1", "ns::New1"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameEnumTest, RenameScopedEnumDecl) { + std::string Before = R"( + namespace ns { + enum class Old1 { Blue }; + } + )"; + std::string Expected = R"( + namespace ns { + enum class New1 { Blue }; + } + )"; + std::string After = runClangRenameOnCode(Before, "ns::Old1", "ns::New1"); + CompareSnippets(Expected, After); +} + +} // anonymous namespace +} // namespace test +} // namespace clang_rename +} // namesdpace clang diff --git a/unittests/Rename/RenameFunctionTest.cpp b/unittests/Rename/RenameFunctionTest.cpp new file mode 100644 index 0000000000000..b27bbe273af8f --- /dev/null +++ b/unittests/Rename/RenameFunctionTest.cpp @@ -0,0 +1,574 @@ +//===-- RenameFunctionTest.cpp - unit tests for renaming functions --------===// +// +// 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 RenameFunctionTest : public ClangRenameTest { +public: + RenameFunctionTest() { + AppendToHeader(R"( + struct A { + static bool Foo(); + static bool Spam(); + }; + struct B { + static void Same(); + static bool Foo(); + static int Eric(int x); + }; + void Same(int x); + int Eric(int x); + namespace base { + void Same(); + void ToNanoSeconds(); + void ToInt64NanoSeconds(); + })"); + } +}; + +TEST_F(RenameFunctionTest, RefactorsAFoo) { + std::string Before = R"( + void f() { + A::Foo(); + ::A::Foo(); + })"; + std::string Expected = R"( + void f() { + A::Bar(); + ::A::Bar(); + })"; + + std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, RefactorsNonCallingAFoo) { + std::string Before = R"( + bool g(bool (*func)()) { + return func(); + } + void f() { + auto *ref1 = A::Foo; + auto *ref2 = ::A::Foo; + g(A::Foo); + })"; + std::string Expected = R"( + bool g(bool (*func)()) { + return func(); + } + void f() { + auto *ref1 = A::Bar; + auto *ref2 = ::A::Bar; + g(A::Bar); + })"; + std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, RefactorsEric) { + std::string Before = R"( + void f() { + if (Eric(3)==4) ::Eric(2); + })"; + std::string Expected = R"( + void f() { + if (Larry(3)==4) ::Larry(2); + })"; + std::string After = runClangRenameOnCode(Before, "Eric", "Larry"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, RefactorsNonCallingEric) { + std::string Before = R"( + int g(int (*func)(int)) { + return func(1); + } + void f() { + auto *ref = ::Eric; + g(Eric); + })"; + std::string Expected = R"( + int g(int (*func)(int)) { + return func(1); + } + void f() { + auto *ref = ::Larry; + g(Larry); + })"; + std::string After = runClangRenameOnCode(Before, "Eric", "Larry"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, DoesNotRefactorBFoo) { + std::string Before = R"( + void f() { + B::Foo(); + })"; + std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar"); + CompareSnippets(Before, After); +} + +TEST_F(RenameFunctionTest, DoesNotRefactorBEric) { + std::string Before = R"( + void f() { + B::Eric(2); + })"; + std::string After = runClangRenameOnCode(Before, "Eric", "Larry"); + CompareSnippets(Before, After); +} + +TEST_F(RenameFunctionTest, DoesNotRefactorCEric) { + std::string Before = R"( + namespace C { int Eric(int x); } + void f() { + if (C::Eric(3)==4) ::C::Eric(2); + })"; + std::string Expected = R"( + namespace C { int Eric(int x); } + void f() { + if (C::Eric(3)==4) ::C::Eric(2); + })"; + std::string After = runClangRenameOnCode(Before, "Eric", "Larry"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, DoesNotRefactorEricInNamespaceC) { + std::string Before = R"( + namespace C { + int Eric(int x); + void f() { + if (Eric(3)==4) Eric(2); + } + } // namespace C)"; + std::string After = runClangRenameOnCode(Before, "Eric", "Larry"); + CompareSnippets(Before, After); +} + +TEST_F(RenameFunctionTest, NamespaceQualified) { + std::string Before = R"( + void f() { + base::ToNanoSeconds(); + ::base::ToNanoSeconds(); + } + void g() { + using base::ToNanoSeconds; + base::ToNanoSeconds(); + ::base::ToNanoSeconds(); + ToNanoSeconds(); + } + namespace foo { + namespace base { + void ToNanoSeconds(); + void f() { + base::ToNanoSeconds(); + } + } + void f() { + ::base::ToNanoSeconds(); + } + })"; + std::string Expected = R"( + void f() { + base::ToInt64NanoSeconds(); + ::base::ToInt64NanoSeconds(); + } + void g() { + using base::ToInt64NanoSeconds; + base::ToInt64NanoSeconds(); + ::base::ToInt64NanoSeconds(); + base::ToInt64NanoSeconds(); + } + namespace foo { + namespace base { + void ToNanoSeconds(); + void f() { + base::ToNanoSeconds(); + } + } + void f() { + ::base::ToInt64NanoSeconds(); + } + })"; + std::string After = runClangRenameOnCode(Before, "base::ToNanoSeconds", + "base::ToInt64NanoSeconds"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, RenameFunctionDecls) { + std::string Before = R"( + namespace na { + void X(); + void X() {} + })"; + std::string Expected = R"( + namespace na { + void Y(); + void Y() {} + })"; + std::string After = runClangRenameOnCode(Before, "na::X", "na::Y"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, RenameTemplateFunctions) { + std::string Before = R"( + namespace na { + template<typename T> T X(); + } + namespace na { void f() { X<int>(); } } + namespace nb { void g() { na::X <int>(); } } + )"; + std::string Expected = R"( + namespace na { + template<typename T> T Y(); + } + namespace na { void f() { nb::Y<int>(); } } + namespace nb { void g() { Y<int>(); } } + )"; + std::string After = runClangRenameOnCode(Before, "na::X", "nb::Y"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, RenameOutOfLineFunctionDecls) { + std::string Before = R"( + namespace na { + void X(); + } + void na::X() {} + )"; + std::string Expected = R"( + namespace na { + void Y(); + } + void na::Y() {} + )"; + std::string After = runClangRenameOnCode(Before, "na::X", "na::Y"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, NewNamespaceWithoutLeadingDotDot) { + std::string Before = R"( + namespace old_ns { + void X(); + void X() {} + } + // Assume that the reference is in another file. + void f() { old_ns::X(); } + namespace old_ns { void g() { X(); } } + namespace new_ns { void h() { ::old_ns::X(); } } + )"; + std::string Expected = R"( + namespace old_ns { + void Y(); + void Y() {} + } + // Assume that the reference is in another file. + void f() { new_ns::Y(); } + namespace old_ns { void g() { new_ns::Y(); } } + namespace new_ns { void h() { Y(); } } + )"; + std::string After = runClangRenameOnCode(Before, "::old_ns::X", "new_ns::Y"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, NewNamespaceWithLeadingDotDot) { + std::string Before = R"( + namespace old_ns { + void X(); + void X() {} + } + // Assume that the reference is in another file. + void f() { old_ns::X(); } + namespace old_ns { void g() { X(); } } + namespace new_ns { void h() { ::old_ns::X(); } } + )"; + std::string Expected = R"( + namespace old_ns { + void Y(); + void Y() {} + } + // Assume that the reference is in another file. + void f() { ::new_ns::Y(); } + namespace old_ns { void g() { ::new_ns::Y(); } } + namespace new_ns { void h() { Y(); } } + )"; + std::string After = + runClangRenameOnCode(Before, "::old_ns::X", "::new_ns::Y"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, DontRenameSymbolsDefinedInAnonymousNamespace) { + std::string Before = R"( + namespace old_ns { + class X {}; + namespace { + void X(); + void X() {} + void f() { X(); } + } + } + )"; + std::string Expected = R"( + namespace old_ns { + class Y {}; + namespace { + void X(); + void X() {} + void f() { X(); } + } + } + )"; + std::string After = + runClangRenameOnCode(Before, "::old_ns::X", "::old_ns::Y"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, NewNestedNamespace) { + std::string Before = R"( + namespace old_ns { + void X(); + void X() {} + } + // Assume that the reference is in another file. + namespace old_ns { + void f() { X(); } + } + )"; + std::string Expected = R"( + namespace old_ns { + void X(); + void X() {} + } + // Assume that the reference is in another file. + namespace old_ns { + void f() { older_ns::X(); } + } + )"; + std::string After = + runClangRenameOnCode(Before, "::old_ns::X", "::old_ns::older_ns::X"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, MoveFromGlobalToNamespaceWithoutLeadingDotDot) { + std::string Before = R"( + void X(); + void X() {} + + // Assume that the reference is in another file. + namespace some_ns { + void f() { X(); } + } + )"; + std::string Expected = R"( + void X(); + void X() {} + + // Assume that the reference is in another file. + namespace some_ns { + void f() { ns::X(); } + } + )"; + std::string After = + runClangRenameOnCode(Before, "::X", "ns::X"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, MoveFromGlobalToNamespaceWithLeadingDotDot) { + std::string Before = R"( + void Y() {} + + // Assume that the reference is in another file. + namespace some_ns { + void f() { Y(); } + } + )"; + std::string Expected = R"( + void Y() {} + + // Assume that the reference is in another file. + namespace some_ns { + void f() { ::ns::Y(); } + } + )"; + std::string After = + runClangRenameOnCode(Before, "::Y", "::ns::Y"); + CompareSnippets(Expected, After); +} + +// FIXME: the rename of overloaded operator is not fully supported yet. +TEST_F(RenameFunctionTest, DISABLED_DoNotRenameOverloadedOperatorCalls) { + std::string Before = R"( + namespace old_ns { + class T { public: int x; }; + bool operator==(const T& lhs, const T& rhs) { + return lhs.x == rhs.x; + } + } // namespace old_ns + + // Assume that the reference is in another file. + bool f() { + auto eq = old_ns::operator==; + old_ns::T t1, t2; + old_ns::operator==(t1, t2); + return t1 == t2; + } + )"; + std::string Expected = R"( + namespace old_ns { + class T { public: int x; }; + bool operator==(const T& lhs, const T& rhs) { + return lhs.x == rhs.x; + } + } // namespace old_ns + + // Assume that the reference is in another file. + bool f() { + auto eq = new_ns::operator==; + old_ns::T t1, t2; + new_ns::operator==(t1, t2); + return t1 == t2; + } + )"; + std::string After = + runClangRenameOnCode(Before, "old_ns::operator==", "new_ns::operator=="); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, FunctionRefAsTemplate) { + std::string Before = R"( + void X(); + + // Assume that the reference is in another file. + namespace some_ns { + template <void (*Func)(void)> + class TIterator {}; + + template <void (*Func)(void)> + class T { + public: + typedef TIterator<Func> IterType; + using TI = TIterator<Func>; + void g() { + Func(); + auto func = Func; + TIterator<Func> iter; + } + }; + + + void f() { T<X> tx; tx.g(); } + } // namespace some_ns + )"; + std::string Expected = R"( + void X(); + + // Assume that the reference is in another file. + namespace some_ns { + template <void (*Func)(void)> + class TIterator {}; + + template <void (*Func)(void)> + class T { + public: + typedef TIterator<Func> IterType; + using TI = TIterator<Func>; + void g() { + Func(); + auto func = Func; + TIterator<Func> iter; + } + }; + + + void f() { T<ns::X> tx; tx.g(); } + } // namespace some_ns + )"; + std::string After = runClangRenameOnCode(Before, "::X", "ns::X"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameFunctionTest, RenameFunctionInUsingDecl) { + std::string Before = R"( + using base::ToNanoSeconds; + namespace old_ns { + using base::ToNanoSeconds; + void f() { + using base::ToNanoSeconds; + } + } + )"; + std::string Expected = R"( + using base::ToInt64NanoSeconds; + namespace old_ns { + using base::ToInt64NanoSeconds; + void f() { + using base::ToInt64NanoSeconds; + } + } + )"; + std::string After = runClangRenameOnCode(Before, "base::ToNanoSeconds", + "base::ToInt64NanoSeconds"); + CompareSnippets(Expected, After); +} + +// FIXME: Fix the complex the case where the symbol being renamed is located in +// `std::function<decltype<renamed_symbol>>`. +TEST_F(ClangRenameTest, DISABLED_ReferencesInLambdaFunctionParameters) { + std::string Before = R"( + template <class T> + class function; + template <class R, class... ArgTypes> + class function<R(ArgTypes...)> { + public: + template <typename Functor> + function(Functor f) {} + + function() {} + + R operator()(ArgTypes...) const {} + }; + + namespace ns { + void Old() {} + void f() { + function<decltype(Old)> func; + } + } // namespace ns)"; + std::string Expected = R"( + template <class T> + class function; + template <class R, class... ArgTypes> + class function<R(ArgTypes...)> { + public: + template <typename Functor> + function(Functor f) {} + + function() {} + + R operator()(ArgTypes...) const {} + }; + + namespace ns { + void New() {} + void f() { + function<decltype(::new_ns::New)> func; + } + } // namespace ns)"; + std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New"); + CompareSnippets(Expected, After); +} + +} // anonymous namespace +} // namespace test +} // namespace clang_rename +} // namesdpace clang diff --git a/unittests/Rename/RenameMemberTest.cpp b/unittests/Rename/RenameMemberTest.cpp new file mode 100644 index 0000000000000..463f7c70def72 --- /dev/null +++ b/unittests/Rename/RenameMemberTest.cpp @@ -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 |