blob: 29b4594fb0a4aba6cc9c112a0916a055136dc1af [file] [log] [blame]
Haojian Wu74f823a2017-04-04 09:30:06 +00001//===-- RenameClassTest.cpp - unit tests for renaming classes -------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "ClangRenameTest.h"
11
12namespace clang {
13namespace clang_rename {
14namespace test {
15namespace {
16
17class RenameClassTest : public ClangRenameTest {
18public:
19 RenameClassTest() {
20 AppendToHeader(R"(
21 namespace a {
22 class Foo {
23 public:
24 struct Nested {
25 enum NestedEnum {E1, E2};
26 };
27 void func() {}
28 static int Constant;
29 };
30 class Goo {
31 public:
32 struct Nested {
33 enum NestedEnum {E1, E2};
34 };
35 };
36 int Foo::Constant = 1;
37 } // namespace a
38 namespace b {
39 class Foo {};
40 } // namespace b
41
42 #define MACRO(x) x
43
44 template<typename T> class ptr {};
45 )");
46 }
47};
48
49INSTANTIATE_TEST_CASE_P(
50 RenameClassTests, RenameClassTest,
51 testing::ValuesIn(std::vector<Case>({
52 // basic classes
David Blaikie0c0c8c42017-04-05 16:50:19 +000053 {"a::Foo f;", "b::Bar f;", "", ""},
54 {"void f(a::Foo f) {}", "void f(b::Bar f) {}", "", ""},
55 {"void f(a::Foo *f) {}", "void f(b::Bar *f) {}", "", ""},
56 {"a::Foo f() { return a::Foo(); }", "b::Bar f() { return b::Bar(); }",
57 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000058 {"namespace a {a::Foo f() { return Foo(); }}",
David Blaikie0c0c8c42017-04-05 16:50:19 +000059 "namespace a {b::Bar f() { return b::Bar(); }}", "", ""},
60 {"void f(const a::Foo& a1) {}", "void f(const b::Bar& a1) {}", "", ""},
61 {"void f(const a::Foo* a1) {}", "void f(const b::Bar* a1) {}", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000062 {"namespace a { void f(Foo a1) {} }",
David Blaikie0c0c8c42017-04-05 16:50:19 +000063 "namespace a { void f(b::Bar a1) {} }", "", ""},
64 {"void f(MACRO(a::Foo) a1) {}", "void f(MACRO(b::Bar) a1) {}", "", ""},
65 {"void f(MACRO(a::Foo a1)) {}", "void f(MACRO(b::Bar a1)) {}", "", ""},
66 {"a::Foo::Nested ns;", "b::Bar::Nested ns;", "", ""},
67 {"auto t = a::Foo::Constant;", "auto t = b::Bar::Constant;", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000068 {"a::Foo::Nested ns;", "a::Foo::Nested2 ns;", "a::Foo::Nested",
69 "a::Foo::Nested2"},
70
71 // use namespace and typedefs
David Blaikie0c0c8c42017-04-05 16:50:19 +000072 {"using a::Foo; Foo gA;", "using b::Bar; b::Bar gA;", "", ""},
73 {"using a::Foo; void f(Foo gA) {}", "using b::Bar; void f(Bar gA) {}",
74 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000075 {"using a::Foo; namespace x { Foo gA; }",
David Blaikie0c0c8c42017-04-05 16:50:19 +000076 "using b::Bar; namespace x { Bar gA; }", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000077 {"struct S { using T = a::Foo; T a_; };",
David Blaikie0c0c8c42017-04-05 16:50:19 +000078 "struct S { using T = b::Bar; T a_; };", "", ""},
79 {"using T = a::Foo; T gA;", "using T = b::Bar; T gA;", "", ""},
80 {"typedef a::Foo T; T gA;", "typedef b::Bar T; T gA;", "", ""},
81 {"typedef MACRO(a::Foo) T; T gA;", "typedef MACRO(b::Bar) T; T gA;", "",
82 ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000083
84 // struct members and other oddities
David Blaikie0c0c8c42017-04-05 16:50:19 +000085 {"struct S : public a::Foo {};", "struct S : public b::Bar {};", "",
86 ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000087 {"struct F { void f(a::Foo a1) {} };",
David Blaikie0c0c8c42017-04-05 16:50:19 +000088 "struct F { void f(b::Bar a1) {} };", "", ""},
89 {"struct F { a::Foo a_; };", "struct F { b::Bar a_; };", "", ""},
90 {"struct F { ptr<a::Foo> a_; };", "struct F { ptr<b::Bar> a_; };", "",
91 ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000092
David Blaikie0c0c8c42017-04-05 16:50:19 +000093 {"void f() { a::Foo::Nested ne; }", "void f() { b::Bar::Nested ne; }",
94 "", ""},
95 {"void f() { a::Goo::Nested ne; }", "void f() { a::Goo::Nested ne; }",
96 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000097 {"void f() { a::Foo::Nested::NestedEnum e; }",
David Blaikie0c0c8c42017-04-05 16:50:19 +000098 "void f() { b::Bar::Nested::NestedEnum e; }", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000099 {"void f() { auto e = a::Foo::Nested::NestedEnum::E1; }",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000100 "void f() { auto e = b::Bar::Nested::NestedEnum::E1; }", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000101 {"void f() { auto e = a::Foo::Nested::E1; }",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000102 "void f() { auto e = b::Bar::Nested::E1; }", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000103
104 // templates
105 {"template <typename T> struct Foo { T t; };\n"
106 "void f() { Foo<a::Foo> foo; }",
107 "template <typename T> struct Foo { T t; };\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000108 "void f() { Foo<b::Bar> foo; }",
109 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000110 {"template <typename T> struct Foo { a::Foo a; };",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000111 "template <typename T> struct Foo { b::Bar a; };", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000112 {"template <typename T> void f(T t) {}\n"
113 "void g() { f<a::Foo>(a::Foo()); }",
114 "template <typename T> void f(T t) {}\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000115 "void g() { f<b::Bar>(b::Bar()); }",
116 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000117 {"template <typename T> int f() { return 1; }\n"
118 "template <> int f<a::Foo>() { return 2; }\n"
119 "int g() { return f<a::Foo>(); }",
120 "template <typename T> int f() { return 1; }\n"
121 "template <> int f<b::Bar>() { return 2; }\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000122 "int g() { return f<b::Bar>(); }",
123 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000124 {"struct Foo { template <typename T> T foo(); };\n"
125 "void g() { Foo f; auto a = f.template foo<a::Foo>(); }",
126 "struct Foo { template <typename T> T foo(); };\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000127 "void g() { Foo f; auto a = f.template foo<b::Bar>(); }",
128 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000129
130 // The following two templates are distilled from regressions found in
131 // unique_ptr<> and type_traits.h
132 {"template <typename T> struct outer {\n"
133 " typedef T type;\n"
134 " type Baz();\n"
135 " };\n"
136 " outer<a::Foo> g_A;",
137 "template <typename T> struct outer {\n"
138 " typedef T type;\n"
139 " type Baz();\n"
140 " };\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000141 " outer<b::Bar> g_A;",
142 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000143 {"template <typename T> struct nested { typedef T type; };\n"
144 "template <typename T> struct outer { typename nested<T>::type Foo(); "
145 "};\n"
146 "outer<a::Foo> g_A;",
147 "template <typename T> struct nested { typedef T type; };\n"
148 "template <typename T> struct outer { typename nested<T>::type Foo(); "
149 "};\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000150 "outer<b::Bar> g_A;",
151 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000152
153 // macros
154 {"#define FOO(T, t) T t\n"
155 "void f() { FOO(a::Foo, a1); FOO(a::Foo, a2); }",
156 "#define FOO(T, t) T t\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000157 "void f() { FOO(b::Bar, a1); FOO(b::Bar, a2); }",
158 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000159 {"#define FOO(n) a::Foo n\n"
160 " void f() { FOO(a1); FOO(a2); }",
161 "#define FOO(n) b::Bar n\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000162 " void f() { FOO(a1); FOO(a2); }",
163 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000164
165 // Pointer to member functions
David Blaikie0c0c8c42017-04-05 16:50:19 +0000166 {"auto gA = &a::Foo::func;", "auto gA = &b::Bar::func;", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000167 {"using a::Foo; auto gA = &Foo::func;",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000168 "using b::Bar; auto gA = &b::Bar::func;", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000169 {"using a::Foo; namespace x { auto gA = &Foo::func; }",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000170 "using b::Bar; namespace x { auto gA = &Bar::func; }", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000171 {"typedef a::Foo T; auto gA = &T::func;",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000172 "typedef b::Bar T; auto gA = &T::func;", "", ""},
173 {"auto gA = &MACRO(a::Foo)::func;", "auto gA = &MACRO(b::Bar)::func;",
174 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000175
176 // Short match inside a namespace
177 {"namespace a { void f(Foo a1) {} }",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000178 "namespace a { void f(b::Bar a1) {} }", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000179
180 // Correct match.
181 {"using a::Foo; struct F { ptr<Foo> a_; };",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000182 "using b::Bar; struct F { ptr<Bar> a_; };", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000183
184 // avoid false positives
David Blaikie0c0c8c42017-04-05 16:50:19 +0000185 {"void f(b::Foo a) {}", "void f(b::Foo a) {}", "", ""},
186 {"namespace b { void f(Foo a) {} }", "namespace b { void f(Foo a) {} }",
187 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000188
189 // friends, everyone needs friends.
190 {"class Foo { int i; friend class a::Foo; };",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000191 "class Foo { int i; friend class b::Bar; };", "", ""},
Haojian Wu0bc5e022017-04-07 12:37:32 +0000192 })), );
Haojian Wu74f823a2017-04-04 09:30:06 +0000193
194TEST_P(RenameClassTest, RenameClasses) {
195 auto Param = GetParam();
196 std::string OldName = Param.OldName.empty() ? "a::Foo" : Param.OldName;
197 std::string NewName = Param.NewName.empty() ? "b::Bar" : Param.NewName;
198 std::string Actual = runClangRenameOnCode(Param.Before, OldName, NewName);
199 CompareSnippets(Param.After, Actual);
200}
201
202class NamespaceDetectionTest : public ClangRenameTest {
203protected:
204 NamespaceDetectionTest() {
205 AppendToHeader(R"(
206 class Old {};
207 namespace o1 {
208 class Old {};
209 namespace o2 {
210 class Old {};
211 namespace o3 {
212 class Old {};
213 } // namespace o3
214 } // namespace o2
215 } // namespace o1
216 )");
217 }
218};
219
220INSTANTIATE_TEST_CASE_P(
221 RenameClassTest, NamespaceDetectionTest,
222 ::testing::ValuesIn(std::vector<Case>({
223 // Test old and new namespace overlap.
224 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
225 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
226 "o1::o2::o3::Old", "o1::o2::o3::New"},
227 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
228 "namespace o1 { namespace o2 { namespace o3 { n3::New moo; } } }",
229 "o1::o2::o3::Old", "o1::o2::n3::New"},
230 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
231 "namespace o1 { namespace o2 { namespace o3 { n2::n3::New moo; } } }",
232 "o1::o2::o3::Old", "o1::n2::n3::New"},
233 {"namespace o1 { namespace o2 { Old moo; } }",
234 "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old",
235 "::o1::o2::New"},
236 {"namespace o1 { namespace o2 { Old moo; } }",
237 "namespace o1 { namespace o2 { n2::New moo; } }", "::o1::o2::Old",
238 "::o1::n2::New"},
239 {"namespace o1 { namespace o2 { Old moo; } }",
240 "namespace o1 { namespace o2 { ::n1::n2::New moo; } }",
241 "::o1::o2::Old", "::n1::n2::New"},
242 {"namespace o1 { namespace o2 { Old moo; } }",
243 "namespace o1 { namespace o2 { n1::n2::New moo; } }", "::o1::o2::Old",
244 "n1::n2::New"},
245
246 // Test old and new namespace with differing depths.
247 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
248 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
249 "o1::o2::o3::Old", "::o1::New"},
250 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
251 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
252 "o1::o2::o3::Old", "::o1::o2::New"},
253 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
254 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
255 "o1::o2::o3::Old", "o1::New"},
256 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
257 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
258 "o1::o2::o3::Old", "o1::o2::New"},
259 {"Old moo;", "o1::New moo;", "::Old", "o1::New"},
260 {"Old moo;", "o1::New moo;", "Old", "o1::New"},
261 {"namespace o1 { ::Old moo; }", "namespace o1 { New moo; }", "Old",
262 "o1::New"},
263 {"namespace o1 { namespace o2 { Old moo; } }",
264 "namespace o1 { namespace o2 { ::New moo; } }", "::o1::o2::Old",
265 "::New"},
266 {"namespace o1 { namespace o2 { Old moo; } }",
267 "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old", "New"},
268
269 // Test moving into the new namespace at different levels.
270 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
271 "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",
272 "::n1::n2::New"},
273 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
274 "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",
275 "n1::n2::New"},
276 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
277 "namespace n1 { namespace n2 { o2::New moo; } }", "::o1::o2::Old",
278 "::n1::o2::New"},
279 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
280 "namespace n1 { namespace n2 { o2::New moo; } }", "::o1::o2::Old",
281 "n1::o2::New"},
282 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
283 "namespace n1 { namespace n2 { ::o1::o2::New moo; } }",
284 "::o1::o2::Old", "::o1::o2::New"},
285 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
286 "namespace n1 { namespace n2 { o1::o2::New moo; } }", "::o1::o2::Old",
287 "o1::o2::New"},
288
289 // Test friends declarations.
290 {"class Foo { friend class o1::Old; };",
291 "class Foo { friend class o1::New; };", "o1::Old", "o1::New"},
292 {"class Foo { int i; friend class o1::Old; };",
293 "class Foo { int i; friend class ::o1::New; };", "::o1::Old",
294 "::o1::New"},
295 {"namespace o1 { class Foo { int i; friend class Old; }; }",
296 "namespace o1 { class Foo { int i; friend class New; }; }", "o1::Old",
297 "o1::New"},
298 {"namespace o1 { class Foo { int i; friend class Old; }; }",
299 "namespace o1 { class Foo { int i; friend class New; }; }",
300 "::o1::Old", "::o1::New"},
Haojian Wu0bc5e022017-04-07 12:37:32 +0000301 })), );
Haojian Wu74f823a2017-04-04 09:30:06 +0000302
303TEST_P(NamespaceDetectionTest, RenameClasses) {
304 auto Param = GetParam();
305 std::string Actual =
306 runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
307 CompareSnippets(Param.After, Actual);
308}
309
310class TemplatedClassRenameTest : public ClangRenameTest {
311protected:
312 TemplatedClassRenameTest() {
313 AppendToHeader(R"(
314 template <typename T> struct Old {
315 T t_;
316 T f() { return T(); };
317 static T s(T t) { return t; }
318 };
319 namespace ns {
320 template <typename T> struct Old {
321 T t_;
322 T f() { return T(); };
323 static T s(T t) { return t; }
324 };
325 } // namespace ns
326
327 namespace o1 {
328 namespace o2 {
329 namespace o3 {
330 template <typename T> struct Old {
331 T t_;
332 T f() { return T(); };
333 static T s(T t) { return t; }
334 };
335 } // namespace o3
336 } // namespace o2
337 } // namespace o1
338 )");
339 }
340};
341
342INSTANTIATE_TEST_CASE_P(
343 RenameClassTests, TemplatedClassRenameTest,
344 ::testing::ValuesIn(std::vector<Case>({
345 {"Old<int> gI; Old<bool> gB;", "New<int> gI; New<bool> gB;", "Old",
346 "New"},
347 {"ns::Old<int> gI; ns::Old<bool> gB;",
348 "ns::New<int> gI; ns::New<bool> gB;", "ns::Old", "ns::New"},
349 {"auto gI = &Old<int>::f; auto gB = &Old<bool>::f;",
350 "auto gI = &New<int>::f; auto gB = &New<bool>::f;", "Old", "New"},
351 {"auto gI = &ns::Old<int>::f;", "auto gI = &ns::New<int>::f;",
352 "ns::Old", "ns::New"},
353
354 {"int gI = Old<int>::s(0); bool gB = Old<bool>::s(false);",
355 "int gI = New<int>::s(0); bool gB = New<bool>::s(false);", "Old",
356 "New"},
357 {"int gI = ns::Old<int>::s(0); bool gB = ns::Old<bool>::s(false);",
358 "int gI = ns::New<int>::s(0); bool gB = ns::New<bool>::s(false);",
359 "ns::Old", "ns::New"},
360
361 {"struct S { Old<int*> o_; };", "struct S { New<int*> o_; };", "Old",
362 "New"},
363 {"struct S { ns::Old<int*> o_; };", "struct S { ns::New<int*> o_; };",
364 "ns::Old", "ns::New"},
365
366 {"auto a = reinterpret_cast<Old<int>*>(new Old<int>);",
367 "auto a = reinterpret_cast<New<int>*>(new New<int>);", "Old", "New"},
368 {"auto a = reinterpret_cast<ns::Old<int>*>(new ns::Old<int>);",
369 "auto a = reinterpret_cast<ns::New<int>*>(new ns::New<int>);",
370 "ns::Old", "ns::New"},
371 {"auto a = reinterpret_cast<const Old<int>*>(new Old<int>);",
372 "auto a = reinterpret_cast<const New<int>*>(new New<int>);", "Old",
373 "New"},
374 {"auto a = reinterpret_cast<const ns::Old<int>*>(new ns::Old<int>);",
375 "auto a = reinterpret_cast<const ns::New<int>*>(new ns::New<int>);",
376 "ns::Old", "ns::New"},
377
378 {"Old<bool>& foo();", "New<bool>& foo();", "Old", "New"},
379 {"ns::Old<bool>& foo();", "ns::New<bool>& foo();", "ns::Old",
380 "ns::New"},
381 {"o1::o2::o3::Old<bool>& foo();", "o1::o2::o3::New<bool>& foo();",
382 "o1::o2::o3::Old", "o1::o2::o3::New"},
383 {"namespace ns { Old<bool>& foo(); }",
384 "namespace ns { New<bool>& foo(); }", "ns::Old", "ns::New"},
385 {"const Old<bool>& foo();", "const New<bool>& foo();", "Old", "New"},
386 {"const ns::Old<bool>& foo();", "const ns::New<bool>& foo();",
387 "ns::Old", "ns::New"},
388
389 // FIXME: figure out why this only works when Moo gets
390 // specialized at some point.
391 {"template <typename T> struct Moo { Old<T> o_; }; Moo<int> m;",
392 "template <typename T> struct Moo { New<T> o_; }; Moo<int> m;", "Old",
393 "New"},
394 {"template <typename T> struct Moo { ns::Old<T> o_; }; Moo<int> m;",
395 "template <typename T> struct Moo { ns::New<T> o_; }; Moo<int> m;",
396 "ns::Old", "ns::New"},
Haojian Wu0bc5e022017-04-07 12:37:32 +0000397 })), );
Haojian Wu74f823a2017-04-04 09:30:06 +0000398
399TEST_P(TemplatedClassRenameTest, RenameTemplateClasses) {
400 auto Param = GetParam();
401 std::string Actual =
402 runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
403 CompareSnippets(Param.After, Actual);
404}
405
406TEST_F(ClangRenameTest, RenameClassWithOutOfLineMembers) {
407 std::string Before = R"(
408 class Old {
409 public:
410 Old();
411 ~Old();
412
413 Old* next();
414
415 private:
416 Old* next_;
417 };
418
419 Old::Old() {}
420 Old::~Old() {}
421 Old* Old::next() { return next_; }
422 )";
423 std::string Expected = R"(
424 class New {
425 public:
426 New();
427 ~New();
428
429 New* next();
430
431 private:
432 New* next_;
433 };
434
435 New::New() {}
436 New::~New() {}
437 New* New::next() { return next_; }
438 )";
439 std::string After = runClangRenameOnCode(Before, "Old", "New");
440 CompareSnippets(Expected, After);
441}
442
443TEST_F(ClangRenameTest, RenameClassWithInlineMembers) {
444 std::string Before = R"(
445 class Old {
446 public:
447 Old() {}
448 ~Old() {}
449
450 Old* next() { return next_; }
451
452 private:
453 Old* next_;
454 };
455 )";
456 std::string Expected = R"(
457 class New {
458 public:
459 New() {}
460 ~New() {}
461
462 New* next() { return next_; }
463
464 private:
465 New* next_;
466 };
467 )";
468 std::string After = runClangRenameOnCode(Before, "Old", "New");
469 CompareSnippets(Expected, After);
470}
471
472// FIXME: no prefix qualifiers being added to the class definition and
473// constructor.
474TEST_F(ClangRenameTest, RenameClassWithNamespaceWithInlineMembers) {
475 std::string Before = R"(
476 namespace ns {
477 class Old {
478 public:
479 Old() {}
480 ~Old() {}
481
482 Old* next() { return next_; }
483
484 private:
485 Old* next_;
486 };
487 } // namespace ns
488 )";
489 std::string Expected = R"(
490 namespace ns {
491 class ns::New {
492 public:
493 ns::New() {}
494 ~New() {}
495
496 New* next() { return next_; }
497
498 private:
499 New* next_;
500 };
501 } // namespace ns
502 )";
503 std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
504 CompareSnippets(Expected, After);
505}
506
507// FIXME: no prefix qualifiers being added to the class definition and
508// constructor.
509TEST_F(ClangRenameTest, RenameClassWithNamespaceWithOutOfInlineMembers) {
510 std::string Before = R"(
511 namespace ns {
512 class Old {
513 public:
514 Old();
515 ~Old();
516
517 Old* next();
518
519 private:
520 Old* next_;
521 };
522
523 Old::Old() {}
524 Old::~Old() {}
525 Old* Old::next() { return next_; }
526 } // namespace ns
527 )";
528 std::string Expected = R"(
529 namespace ns {
530 class ns::New {
531 public:
532 ns::New();
533 ~New();
534
535 New* next();
536
537 private:
538 New* next_;
539 };
540
541 New::ns::New() {}
542 New::~New() {}
543 New* New::next() { return next_; }
544 } // namespace ns
545 )";
546 std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
547 CompareSnippets(Expected, After);
548}
549
550// FIXME: no prefix qualifiers being added to the definition.
551TEST_F(ClangRenameTest, RenameClassInInheritedConstructor) {
552 // `using Base::Base;` will generate an implicit constructor containing usage
553 // of `::ns::Old` which should not be matched.
554 std::string Before = R"(
555 namespace ns {
556 class Old {
557 int x;
558 };
559 class Base {
560 protected:
561 Old *moo_;
562 public:
563 Base(Old *moo) : moo_(moo) {}
564 };
565 class Derived : public Base {
566 public:
567 using Base::Base;
568 };
569 } // namespace ns
570 int main() {
571 ::ns::Old foo;
572 ::ns::Derived d(&foo);
573 return 0;
574 })";
575 std::string Expected = R"(
576 namespace ns {
577 class ns::New {
578 int x;
579 };
580 class Base {
581 protected:
582 New *moo_;
583 public:
584 Base(New *moo) : moo_(moo) {}
585 };
586 class Derived : public Base {
587 public:
588 using Base::Base;
589 };
590 } // namespace ns
591 int main() {
592 ::ns::New foo;
593 ::ns::Derived d(&foo);
594 return 0;
595 })";
596 std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
597 CompareSnippets(Expected, After);
598}
599
600TEST_F(ClangRenameTest, DontRenameReferencesInImplicitFunction) {
601 std::string Before = R"(
602 namespace ns {
603 class Old {
604 };
605 } // namespace ns
606 struct S {
607 int y;
608 ns::Old old;
609 };
610 void f() {
611 S s1, s2, s3;
612 // This causes an implicit assignment operator to be created.
613 s1 = s2 = s3;
614 }
615 )";
616 std::string Expected = R"(
617 namespace ns {
618 class ::new_ns::New {
619 };
620 } // namespace ns
621 struct S {
622 int y;
623 ::new_ns::New old;
624 };
625 void f() {
626 S s1, s2, s3;
627 // This causes an implicit assignment operator to be created.
628 s1 = s2 = s3;
629 }
630 )";
631 std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
632 CompareSnippets(Expected, After);
633}
634
635// FIXME: no prefix qualifiers being adding to the definition.
636TEST_F(ClangRenameTest, ReferencesInLambdaFunctionParameters) {
637 std::string Before = R"(
638 template <class T>
639 class function;
640 template <class R, class... ArgTypes>
641 class function<R(ArgTypes...)> {
642 public:
643 template <typename Functor>
644 function(Functor f) {}
645
646 function() {}
647
648 R operator()(ArgTypes...) const {}
649 };
650
651 namespace ns {
652 class Old {};
653 void f() {
654 function<void(Old)> func;
655 }
656 } // namespace ns)";
657 std::string Expected = R"(
658 template <class T>
659 class function;
660 template <class R, class... ArgTypes>
661 class function<R(ArgTypes...)> {
662 public:
663 template <typename Functor>
664 function(Functor f) {}
665
666 function() {}
667
668 R operator()(ArgTypes...) const {}
669 };
670
671 namespace ns {
672 class ::new_ns::New {};
673 void f() {
674 function<void(::new_ns::New)> func;
675 }
676 } // namespace ns)";
677 std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
678 CompareSnippets(Expected, After);
679}
680
681} // anonymous namespace
682} // namespace test
683} // namespace clang_rename
684} // namesdpace clang