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:
RenameMemberTest()18   RenameMemberTest() {
19     AppendToHeader(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 
TEST_P(RenameMemberTest,RenameMembers)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(Param.Before, Param.OldName, Param.NewName);
165   CompareSnippets(Param.After, Actual);
166 }
167 
TEST_F(RenameMemberTest,RenameMemberInsideClassMethods)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(Before, "X::Moo", "Y::Meh");
180   CompareSnippets(Expected, After);
181 }
182 
TEST_F(RenameMemberTest,RenameMethodInsideClassMethods)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(Before, "X::Foo", "X::Bar");
195   CompareSnippets(Expected, After);
196 }
197 
TEST_F(RenameMemberTest,RenameCtorInitializer)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(Before, "X::a", "X::bar");
222   CompareSnippets(Expected, After);
223 }
224 
225 } // anonymous namespace
226 } // namespace test
227 } // namespace clang_rename
228 } // namesdpace clang
229