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 | |
11 | namespace clang { |
12 | namespace clang_rename { |
13 | namespace test { |
14 | namespace { |
15 | |
16 | class RenameMemberTest : public ClangRenameTest { |
17 | public: |
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 | |
72 | INSTANTIATE_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 | |
80 | INSTANTIATE_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 | |
159 | TEST_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 | |
168 | TEST_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 | |
183 | TEST_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 | |
198 | TEST_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 | |