//===-- ClangMemberTests.cpp - unit tests for renaming class members ------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #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 struct TA { T* Foo(); T* NotFoo(); static T* SFoo(); static T* NotSFoo(); }; template struct TB : public TA {}; namespace ns { template struct TA { T* Foo(); T* NotFoo(); static T* SFoo(); static T* NotSFoo(); static int SMoo; }; template struct TB : public TA {}; struct A { void Foo(); void NotFoo(); static void SFoo(); static void SNotFoo(); }; struct B : public A {}; struct C { template void SFoo(const T& t) {} template void Foo() {} }; })"); } }; INSTANTIATE_TEST_CASE_P( DISABLED_RenameTemplatedClassStaticVariableTest, RenameMemberTest, testing::ValuesIn(std::vector({ // FIXME: support renaming static variables for template classes. {"void f() { ns::TA::SMoo; }", "void f() { ns::TA::SMeh; }", "ns::TA::SMoo", "ns::TA::SMeh"}, })), ); INSTANTIATE_TEST_CASE_P( RenameMemberTest, RenameMemberTest, testing::ValuesIn(std::vector({ // 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::SFoo(); }", "void f() { TA::SBar(); }", "TA::SFoo", "TA::SBar"}, {"void f() { ns::TA::SFoo(); }", "void f() { ns::TA::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 a; a.Foo(); }", "void f() { TA a; a.Bar(); }", "TA::Foo", "TA::Bar"}, {"void f() { ns::TA a; a.Foo(); }", "void f() { ns::TA a; a.Bar(); }", "ns::TA::Foo", "ns::TA::Bar"}, {"void f() { TB b; b.Foo(); }", "void f() { TB b; b.Bar(); }", "TA::Foo", "TA::Bar"}, {"void f() { ns::TB b; b.Foo(); }", "void f() { ns::TB 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(); }", "void f() { ns::C c; c.Bar(); }", "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; }", "void f() { auto p = &ns::C::SBar; }", "ns::C::SFoo", "ns::C::SBar"}, // These methods are not declared or overridden 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::SFoo(); }", "void f() { TB::SBar(); }", "TA::SFoo", "TB::SBar"}, {"void f() { ns::TB::SFoo(); }", "void f() { ns::TB::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