1//===-- ClangMemberTests.cpp - unit tests for renaming class members ------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ClangRenameTest.h"
10
11namespace clang {
12namespace clang_rename {
13namespace test {
14namespace {
15
16class RenameMemberTest : public ClangRenameTest {
17public:
18 RenameMemberTest() {
19 AppendToHeader(Code: R"(
20 struct NA {
21 void Foo();
22 void NotFoo();
23 static void SFoo();
24 static void SNotFoo();
25 int Moo;
26 };
27 struct A {
28 virtual void Foo();
29 void NotFoo();
30 static void SFoo();
31 static void SNotFoo();
32 int Moo;
33 int NotMoo;
34 static int SMoo;
35 };
36 struct B : public A {
37 void Foo() override;
38 };
39 template <typename T> struct TA {
40 T* Foo();
41 T* NotFoo();
42 static T* SFoo();
43 static T* NotSFoo();
44 };
45 template <typename T> struct TB : public TA<T> {};
46 namespace ns {
47 template <typename T> struct TA {
48 T* Foo();
49 T* NotFoo();
50 static T* SFoo();
51 static T* NotSFoo();
52 static int SMoo;
53 };
54 template <typename T> struct TB : public TA<T> {};
55 struct A {
56 void Foo();
57 void NotFoo();
58 static void SFoo();
59 static void SNotFoo();
60 };
61 struct B : public A {};
62 struct C {
63 template <class T>
64 void SFoo(const T& t) {}
65 template <class T>
66 void Foo() {}
67 };
68 })");
69 }
70};
71
72INSTANTIATE_TEST_SUITE_P(
73 DISABLED_RenameTemplatedClassStaticVariableTest, RenameMemberTest,
74 testing::ValuesIn(std::vector<Case>({
75 // FIXME: support renaming static variables for template classes.
76 {"void f() { ns::TA<int>::SMoo; }",
77 "void f() { ns::TA<int>::SMeh; }", "ns::TA::SMoo", "ns::TA::SMeh"},
78 })) );
79
80INSTANTIATE_TEST_SUITE_P(
81 RenameMemberTest, RenameMemberTest,
82 testing::ValuesIn(std::vector<Case>({
83 // Normal methods and fields.
84 {"void f() { A a; a.Foo(); }", "void f() { A a; a.Bar(); }", "A::Foo",
85 "A::Bar"},
86 {"void f() { ns::A a; a.Foo(); }", "void f() { ns::A a; a.Bar(); }",
87 "ns::A::Foo", "ns::A::Bar"},
88 {"void f() { A a; int x = a.Moo; }", "void f() { A a; int x = a.Meh; }",
89 "A::Moo", "A::Meh"},
90 {"void f() { B b; b.Foo(); }", "void f() { B b; b.Bar(); }", "B::Foo",
91 "B::Bar"},
92 {"void f() { ns::B b; b.Foo(); }", "void f() { ns::B b; b.Bar(); }",
93 "ns::A::Foo", "ns::A::Bar"},
94 {"void f() { B b; int x = b.Moo; }", "void f() { B b; int x = b.Meh; }",
95 "A::Moo", "A::Meh"},
96
97 // Static methods.
98 {"void f() { A::SFoo(); }", "void f() { A::SBar(); }", "A::SFoo",
99 "A::SBar"},
100 {"void f() { ns::A::SFoo(); }", "void f() { ns::A::SBar(); }",
101 "ns::A::SFoo", "ns::A::SBar"},
102 {"void f() { TA<int>::SFoo(); }", "void f() { TA<int>::SBar(); }",
103 "TA::SFoo", "TA::SBar"},
104 {"void f() { ns::TA<int>::SFoo(); }",
105 "void f() { ns::TA<int>::SBar(); }", "ns::TA::SFoo", "ns::TA::SBar"},
106
107 // Static variables.
108 {"void f() { A::SMoo; }",
109 "void f() { A::SMeh; }", "A::SMoo", "A::SMeh"},
110
111 // Templated methods.
112 {"void f() { TA<int> a; a.Foo(); }", "void f() { TA<int> a; a.Bar(); }",
113 "TA::Foo", "TA::Bar"},
114 {"void f() { ns::TA<int> a; a.Foo(); }",
115 "void f() { ns::TA<int> a; a.Bar(); }", "ns::TA::Foo", "ns::TA::Bar"},
116 {"void f() { TB<int> b; b.Foo(); }", "void f() { TB<int> b; b.Bar(); }",
117 "TA::Foo", "TA::Bar"},
118 {"void f() { ns::TB<int> b; b.Foo(); }",
119 "void f() { ns::TB<int> b; b.Bar(); }", "ns::TA::Foo", "ns::TA::Bar"},
120 {"void f() { ns::C c; int x; c.SFoo(x); }",
121 "void f() { ns::C c; int x; c.SBar(x); }", "ns::C::SFoo",
122 "ns::C::SBar"},
123 {"void f() { ns::C c; c.Foo<int>(); }",
124 "void f() { ns::C c; c.Bar<int>(); }", "ns::C::Foo", "ns::C::Bar"},
125
126 // Pointers to methods.
127 {"void f() { auto p = &A::Foo; }", "void f() { auto p = &A::Bar; }",
128 "A::Foo", "A::Bar"},
129 {"void f() { auto p = &A::SFoo; }", "void f() { auto p = &A::SBar; }",
130 "A::SFoo", "A::SBar"},
131 {"void f() { auto p = &B::Foo; }", "void f() { auto p = &B::Bar; }",
132 "B::Foo", "B::Bar"},
133 {"void f() { auto p = &ns::A::Foo; }",
134 "void f() { auto p = &ns::A::Bar; }", "ns::A::Foo", "ns::A::Bar"},
135 {"void f() { auto p = &ns::A::SFoo; }",
136 "void f() { auto p = &ns::A::SBar; }", "ns::A::SFoo", "ns::A::SBar"},
137 {"void f() { auto p = &ns::C::SFoo<int>; }",
138 "void f() { auto p = &ns::C::SBar<int>; }", "ns::C::SFoo",
139 "ns::C::SBar"},
140
141 // These methods are not declared or overridden in the subclass B, we
142 // have to use the qualified name with parent class A to identify them.
143 {"void f() { auto p = &ns::B::Foo; }",
144 "void f() { auto p = &ns::B::Bar; }", "ns::A::Foo", "ns::B::Bar"},
145 {"void f() { B::SFoo(); }", "void f() { B::SBar(); }", "A::SFoo",
146 "B::SBar"},
147 {"void f() { ns::B::SFoo(); }", "void f() { ns::B::SBar(); }",
148 "ns::A::SFoo", "ns::B::SBar"},
149 {"void f() { auto p = &B::SFoo; }", "void f() { auto p = &B::SBar; }",
150 "A::SFoo", "B::SBar"},
151 {"void f() { auto p = &ns::B::SFoo; }",
152 "void f() { auto p = &ns::B::SBar; }", "ns::A::SFoo", "ns::B::SBar"},
153 {"void f() { TB<int>::SFoo(); }", "void f() { TB<int>::SBar(); }",
154 "TA::SFoo", "TB::SBar"},
155 {"void f() { ns::TB<int>::SFoo(); }",
156 "void f() { ns::TB<int>::SBar(); }", "ns::TA::SFoo", "ns::TB::SBar"},
157 })) );
158
159TEST_P(RenameMemberTest, RenameMembers) {
160 auto Param = GetParam();
161 assert(!Param.OldName.empty());
162 assert(!Param.NewName.empty());
163 std::string Actual =
164 runClangRenameOnCode(Code: Param.Before, OldName: Param.OldName, NewName: Param.NewName);
165 CompareSnippets(Expected: Param.After, Actual);
166}
167
168TEST_F(RenameMemberTest, RenameMemberInsideClassMethods) {
169 std::string Before = R"(
170 struct X {
171 int Moo;
172 void Baz() { Moo = 1; }
173 };)";
174 std::string Expected = R"(
175 struct X {
176 int Meh;
177 void Baz() { Meh = 1; }
178 };)";
179 std::string After = runClangRenameOnCode(Code: Before, OldName: "X::Moo", NewName: "Y::Meh");
180 CompareSnippets(Expected, Actual: After);
181}
182
183TEST_F(RenameMemberTest, RenameMethodInsideClassMethods) {
184 std::string Before = R"(
185 struct X {
186 void Foo() {}
187 void Baz() { Foo(); }
188 };)";
189 std::string Expected = R"(
190 struct X {
191 void Bar() {}
192 void Baz() { Bar(); }
193 };)";
194 std::string After = runClangRenameOnCode(Code: Before, OldName: "X::Foo", NewName: "X::Bar");
195 CompareSnippets(Expected, Actual: After);
196}
197
198TEST_F(RenameMemberTest, RenameCtorInitializer) {
199 std::string Before = R"(
200 class X {
201 public:
202 X();
203 A a;
204 A a2;
205 B b;
206 };
207
208 X::X():a(), b() {}
209 )";
210 std::string Expected = R"(
211 class X {
212 public:
213 X();
214 A bar;
215 A a2;
216 B b;
217 };
218
219 X::X():bar(), b() {}
220 )";
221 std::string After = runClangRenameOnCode(Code: Before, OldName: "X::a", NewName: "X::bar");
222 CompareSnippets(Expected, Actual: After);
223}
224
225} // anonymous namespace
226} // namespace test
227} // namespace clang_rename
228} // namesdpace clang
229

source code of clang/unittests/Rename/RenameMemberTest.cpp