blob: 5845d63412b6b4802622a4e1c20c01825bb4fa88 [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;", "", ""},
Haojian Wu6f60ff82017-10-16 10:37:42 +000054 {"::a::Foo f;", "::b::Bar f;", "", ""},
David Blaikie0c0c8c42017-04-05 16:50:19 +000055 {"void f(a::Foo f) {}", "void f(b::Bar f) {}", "", ""},
56 {"void f(a::Foo *f) {}", "void f(b::Bar *f) {}", "", ""},
57 {"a::Foo f() { return a::Foo(); }", "b::Bar f() { return b::Bar(); }",
58 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000059 {"namespace a {a::Foo f() { return Foo(); }}",
David Blaikie0c0c8c42017-04-05 16:50:19 +000060 "namespace a {b::Bar f() { return b::Bar(); }}", "", ""},
61 {"void f(const a::Foo& a1) {}", "void f(const b::Bar& a1) {}", "", ""},
62 {"void f(const a::Foo* a1) {}", "void f(const b::Bar* a1) {}", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000063 {"namespace a { void f(Foo a1) {} }",
David Blaikie0c0c8c42017-04-05 16:50:19 +000064 "namespace a { void f(b::Bar a1) {} }", "", ""},
65 {"void f(MACRO(a::Foo) a1) {}", "void f(MACRO(b::Bar) a1) {}", "", ""},
66 {"void f(MACRO(a::Foo a1)) {}", "void f(MACRO(b::Bar a1)) {}", "", ""},
67 {"a::Foo::Nested ns;", "b::Bar::Nested ns;", "", ""},
68 {"auto t = a::Foo::Constant;", "auto t = b::Bar::Constant;", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000069 {"a::Foo::Nested ns;", "a::Foo::Nested2 ns;", "a::Foo::Nested",
70 "a::Foo::Nested2"},
71
72 // use namespace and typedefs
David Blaikie0c0c8c42017-04-05 16:50:19 +000073 {"using a::Foo; Foo gA;", "using b::Bar; b::Bar gA;", "", ""},
74 {"using a::Foo; void f(Foo gA) {}", "using b::Bar; void f(Bar gA) {}",
75 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000076 {"using a::Foo; namespace x { Foo gA; }",
David Blaikie0c0c8c42017-04-05 16:50:19 +000077 "using b::Bar; namespace x { Bar gA; }", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000078 {"struct S { using T = a::Foo; T a_; };",
David Blaikie0c0c8c42017-04-05 16:50:19 +000079 "struct S { using T = b::Bar; T a_; };", "", ""},
80 {"using T = a::Foo; T gA;", "using T = b::Bar; T gA;", "", ""},
81 {"typedef a::Foo T; T gA;", "typedef b::Bar T; T gA;", "", ""},
82 {"typedef MACRO(a::Foo) T; T gA;", "typedef MACRO(b::Bar) T; T gA;", "",
83 ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000084
85 // struct members and other oddities
David Blaikie0c0c8c42017-04-05 16:50:19 +000086 {"struct S : public a::Foo {};", "struct S : public b::Bar {};", "",
87 ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000088 {"struct F { void f(a::Foo a1) {} };",
David Blaikie0c0c8c42017-04-05 16:50:19 +000089 "struct F { void f(b::Bar a1) {} };", "", ""},
90 {"struct F { a::Foo a_; };", "struct F { b::Bar a_; };", "", ""},
91 {"struct F { ptr<a::Foo> a_; };", "struct F { ptr<b::Bar> a_; };", "",
92 ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000093
David Blaikie0c0c8c42017-04-05 16:50:19 +000094 {"void f() { a::Foo::Nested ne; }", "void f() { b::Bar::Nested ne; }",
95 "", ""},
96 {"void f() { a::Goo::Nested ne; }", "void f() { a::Goo::Nested ne; }",
97 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +000098 {"void f() { a::Foo::Nested::NestedEnum e; }",
David Blaikie0c0c8c42017-04-05 16:50:19 +000099 "void f() { b::Bar::Nested::NestedEnum e; }", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000100 {"void f() { auto e = a::Foo::Nested::NestedEnum::E1; }",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000101 "void f() { auto e = b::Bar::Nested::NestedEnum::E1; }", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000102 {"void f() { auto e = a::Foo::Nested::E1; }",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000103 "void f() { auto e = b::Bar::Nested::E1; }", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000104
105 // templates
106 {"template <typename T> struct Foo { T t; };\n"
107 "void f() { Foo<a::Foo> foo; }",
108 "template <typename T> struct Foo { T t; };\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000109 "void f() { Foo<b::Bar> foo; }",
110 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000111 {"template <typename T> struct Foo { a::Foo a; };",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000112 "template <typename T> struct Foo { b::Bar a; };", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000113 {"template <typename T> void f(T t) {}\n"
114 "void g() { f<a::Foo>(a::Foo()); }",
115 "template <typename T> void f(T t) {}\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000116 "void g() { f<b::Bar>(b::Bar()); }",
117 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000118 {"template <typename T> int f() { return 1; }\n"
119 "template <> int f<a::Foo>() { return 2; }\n"
120 "int g() { return f<a::Foo>(); }",
121 "template <typename T> int f() { return 1; }\n"
122 "template <> int f<b::Bar>() { return 2; }\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000123 "int g() { return f<b::Bar>(); }",
124 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000125 {"struct Foo { template <typename T> T foo(); };\n"
126 "void g() { Foo f; auto a = f.template foo<a::Foo>(); }",
127 "struct Foo { template <typename T> T foo(); };\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000128 "void g() { Foo f; auto a = f.template foo<b::Bar>(); }",
129 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000130
131 // The following two templates are distilled from regressions found in
132 // unique_ptr<> and type_traits.h
133 {"template <typename T> struct outer {\n"
134 " typedef T type;\n"
135 " type Baz();\n"
136 " };\n"
137 " outer<a::Foo> g_A;",
138 "template <typename T> struct outer {\n"
139 " typedef T type;\n"
140 " type Baz();\n"
141 " };\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000142 " outer<b::Bar> g_A;",
143 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000144 {"template <typename T> struct nested { typedef T type; };\n"
145 "template <typename T> struct outer { typename nested<T>::type Foo(); "
146 "};\n"
147 "outer<a::Foo> g_A;",
148 "template <typename T> struct nested { typedef T type; };\n"
149 "template <typename T> struct outer { typename nested<T>::type Foo(); "
150 "};\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000151 "outer<b::Bar> g_A;",
152 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000153
154 // macros
155 {"#define FOO(T, t) T t\n"
156 "void f() { FOO(a::Foo, a1); FOO(a::Foo, a2); }",
157 "#define FOO(T, t) T t\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000158 "void f() { FOO(b::Bar, a1); FOO(b::Bar, a2); }",
159 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000160 {"#define FOO(n) a::Foo n\n"
161 " void f() { FOO(a1); FOO(a2); }",
162 "#define FOO(n) b::Bar n\n"
David Blaikie0c0c8c42017-04-05 16:50:19 +0000163 " void f() { FOO(a1); FOO(a2); }",
164 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000165
166 // Pointer to member functions
David Blaikie0c0c8c42017-04-05 16:50:19 +0000167 {"auto gA = &a::Foo::func;", "auto gA = &b::Bar::func;", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000168 {"using a::Foo; auto gA = &Foo::func;",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000169 "using b::Bar; auto gA = &b::Bar::func;", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000170 {"using a::Foo; namespace x { auto gA = &Foo::func; }",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000171 "using b::Bar; namespace x { auto gA = &Bar::func; }", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000172 {"typedef a::Foo T; auto gA = &T::func;",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000173 "typedef b::Bar T; auto gA = &T::func;", "", ""},
174 {"auto gA = &MACRO(a::Foo)::func;", "auto gA = &MACRO(b::Bar)::func;",
175 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000176
177 // Short match inside a namespace
178 {"namespace a { void f(Foo a1) {} }",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000179 "namespace a { void f(b::Bar a1) {} }", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000180
181 // Correct match.
182 {"using a::Foo; struct F { ptr<Foo> a_; };",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000183 "using b::Bar; struct F { ptr<Bar> a_; };", "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000184
185 // avoid false positives
David Blaikie0c0c8c42017-04-05 16:50:19 +0000186 {"void f(b::Foo a) {}", "void f(b::Foo a) {}", "", ""},
187 {"namespace b { void f(Foo a) {} }", "namespace b { void f(Foo a) {} }",
188 "", ""},
Haojian Wu74f823a2017-04-04 09:30:06 +0000189
190 // friends, everyone needs friends.
191 {"class Foo { int i; friend class a::Foo; };",
David Blaikie0c0c8c42017-04-05 16:50:19 +0000192 "class Foo { int i; friend class b::Bar; };", "", ""},
Haojian Wu0bc5e022017-04-07 12:37:32 +0000193 })), );
Haojian Wu74f823a2017-04-04 09:30:06 +0000194
195TEST_P(RenameClassTest, RenameClasses) {
196 auto Param = GetParam();
197 std::string OldName = Param.OldName.empty() ? "a::Foo" : Param.OldName;
198 std::string NewName = Param.NewName.empty() ? "b::Bar" : Param.NewName;
199 std::string Actual = runClangRenameOnCode(Param.Before, OldName, NewName);
200 CompareSnippets(Param.After, Actual);
201}
202
203class NamespaceDetectionTest : public ClangRenameTest {
204protected:
205 NamespaceDetectionTest() {
206 AppendToHeader(R"(
207 class Old {};
208 namespace o1 {
209 class Old {};
210 namespace o2 {
211 class Old {};
212 namespace o3 {
213 class Old {};
214 } // namespace o3
215 } // namespace o2
216 } // namespace o1
217 )");
218 }
219};
220
221INSTANTIATE_TEST_CASE_P(
222 RenameClassTest, NamespaceDetectionTest,
223 ::testing::ValuesIn(std::vector<Case>({
224 // Test old and new namespace overlap.
225 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
226 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
227 "o1::o2::o3::Old", "o1::o2::o3::New"},
228 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
229 "namespace o1 { namespace o2 { namespace o3 { n3::New moo; } } }",
230 "o1::o2::o3::Old", "o1::o2::n3::New"},
231 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
232 "namespace o1 { namespace o2 { namespace o3 { n2::n3::New moo; } } }",
233 "o1::o2::o3::Old", "o1::n2::n3::New"},
234 {"namespace o1 { namespace o2 { Old moo; } }",
235 "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old",
236 "::o1::o2::New"},
237 {"namespace o1 { namespace o2 { Old moo; } }",
238 "namespace o1 { namespace o2 { n2::New moo; } }", "::o1::o2::Old",
239 "::o1::n2::New"},
240 {"namespace o1 { namespace o2 { Old moo; } }",
241 "namespace o1 { namespace o2 { ::n1::n2::New moo; } }",
242 "::o1::o2::Old", "::n1::n2::New"},
243 {"namespace o1 { namespace o2 { Old moo; } }",
244 "namespace o1 { namespace o2 { n1::n2::New moo; } }", "::o1::o2::Old",
245 "n1::n2::New"},
246
247 // Test old and new namespace with differing depths.
248 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
249 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
250 "o1::o2::o3::Old", "::o1::New"},
251 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
252 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
253 "o1::o2::o3::Old", "::o1::o2::New"},
254 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
255 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
256 "o1::o2::o3::Old", "o1::New"},
257 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
258 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
259 "o1::o2::o3::Old", "o1::o2::New"},
260 {"Old moo;", "o1::New moo;", "::Old", "o1::New"},
261 {"Old moo;", "o1::New moo;", "Old", "o1::New"},
262 {"namespace o1 { ::Old moo; }", "namespace o1 { New moo; }", "Old",
263 "o1::New"},
264 {"namespace o1 { namespace o2 { Old moo; } }",
265 "namespace o1 { namespace o2 { ::New moo; } }", "::o1::o2::Old",
266 "::New"},
267 {"namespace o1 { namespace o2 { Old moo; } }",
268 "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old", "New"},
269
270 // Test moving into the new namespace at different levels.
271 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
272 "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",
273 "::n1::n2::New"},
274 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
275 "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",
276 "n1::n2::New"},
277 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
278 "namespace n1 { namespace n2 { o2::New moo; } }", "::o1::o2::Old",
279 "::n1::o2::New"},
280 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
281 "namespace n1 { namespace n2 { o2::New moo; } }", "::o1::o2::Old",
282 "n1::o2::New"},
283 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
284 "namespace n1 { namespace n2 { ::o1::o2::New moo; } }",
285 "::o1::o2::Old", "::o1::o2::New"},
286 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
287 "namespace n1 { namespace n2 { o1::o2::New moo; } }", "::o1::o2::Old",
288 "o1::o2::New"},
289
290 // Test friends declarations.
291 {"class Foo { friend class o1::Old; };",
292 "class Foo { friend class o1::New; };", "o1::Old", "o1::New"},
293 {"class Foo { int i; friend class o1::Old; };",
294 "class Foo { int i; friend class ::o1::New; };", "::o1::Old",
295 "::o1::New"},
296 {"namespace o1 { class Foo { int i; friend class Old; }; }",
297 "namespace o1 { class Foo { int i; friend class New; }; }", "o1::Old",
298 "o1::New"},
299 {"namespace o1 { class Foo { int i; friend class Old; }; }",
300 "namespace o1 { class Foo { int i; friend class New; }; }",
301 "::o1::Old", "::o1::New"},
Haojian Wu0bc5e022017-04-07 12:37:32 +0000302 })), );
Haojian Wu74f823a2017-04-04 09:30:06 +0000303
304TEST_P(NamespaceDetectionTest, RenameClasses) {
305 auto Param = GetParam();
306 std::string Actual =
307 runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
308 CompareSnippets(Param.After, Actual);
309}
310
311class TemplatedClassRenameTest : public ClangRenameTest {
312protected:
313 TemplatedClassRenameTest() {
314 AppendToHeader(R"(
315 template <typename T> struct Old {
316 T t_;
317 T f() { return T(); };
318 static T s(T t) { return t; }
319 };
320 namespace ns {
321 template <typename T> struct Old {
322 T t_;
323 T f() { return T(); };
324 static T s(T t) { return t; }
325 };
326 } // namespace ns
327
328 namespace o1 {
329 namespace o2 {
330 namespace o3 {
331 template <typename T> struct Old {
332 T t_;
333 T f() { return T(); };
334 static T s(T t) { return t; }
335 };
336 } // namespace o3
337 } // namespace o2
338 } // namespace o1
339 )");
340 }
341};
342
343INSTANTIATE_TEST_CASE_P(
344 RenameClassTests, TemplatedClassRenameTest,
345 ::testing::ValuesIn(std::vector<Case>({
346 {"Old<int> gI; Old<bool> gB;", "New<int> gI; New<bool> gB;", "Old",
347 "New"},
348 {"ns::Old<int> gI; ns::Old<bool> gB;",
349 "ns::New<int> gI; ns::New<bool> gB;", "ns::Old", "ns::New"},
350 {"auto gI = &Old<int>::f; auto gB = &Old<bool>::f;",
351 "auto gI = &New<int>::f; auto gB = &New<bool>::f;", "Old", "New"},
352 {"auto gI = &ns::Old<int>::f;", "auto gI = &ns::New<int>::f;",
353 "ns::Old", "ns::New"},
354
355 {"int gI = Old<int>::s(0); bool gB = Old<bool>::s(false);",
356 "int gI = New<int>::s(0); bool gB = New<bool>::s(false);", "Old",
357 "New"},
358 {"int gI = ns::Old<int>::s(0); bool gB = ns::Old<bool>::s(false);",
359 "int gI = ns::New<int>::s(0); bool gB = ns::New<bool>::s(false);",
360 "ns::Old", "ns::New"},
361
362 {"struct S { Old<int*> o_; };", "struct S { New<int*> o_; };", "Old",
363 "New"},
364 {"struct S { ns::Old<int*> o_; };", "struct S { ns::New<int*> o_; };",
365 "ns::Old", "ns::New"},
366
367 {"auto a = reinterpret_cast<Old<int>*>(new Old<int>);",
368 "auto a = reinterpret_cast<New<int>*>(new New<int>);", "Old", "New"},
369 {"auto a = reinterpret_cast<ns::Old<int>*>(new ns::Old<int>);",
370 "auto a = reinterpret_cast<ns::New<int>*>(new ns::New<int>);",
371 "ns::Old", "ns::New"},
372 {"auto a = reinterpret_cast<const Old<int>*>(new Old<int>);",
373 "auto a = reinterpret_cast<const New<int>*>(new New<int>);", "Old",
374 "New"},
375 {"auto a = reinterpret_cast<const ns::Old<int>*>(new ns::Old<int>);",
376 "auto a = reinterpret_cast<const ns::New<int>*>(new ns::New<int>);",
377 "ns::Old", "ns::New"},
378
379 {"Old<bool>& foo();", "New<bool>& foo();", "Old", "New"},
380 {"ns::Old<bool>& foo();", "ns::New<bool>& foo();", "ns::Old",
381 "ns::New"},
382 {"o1::o2::o3::Old<bool>& foo();", "o1::o2::o3::New<bool>& foo();",
383 "o1::o2::o3::Old", "o1::o2::o3::New"},
384 {"namespace ns { Old<bool>& foo(); }",
385 "namespace ns { New<bool>& foo(); }", "ns::Old", "ns::New"},
386 {"const Old<bool>& foo();", "const New<bool>& foo();", "Old", "New"},
387 {"const ns::Old<bool>& foo();", "const ns::New<bool>& foo();",
388 "ns::Old", "ns::New"},
389
390 // FIXME: figure out why this only works when Moo gets
391 // specialized at some point.
392 {"template <typename T> struct Moo { Old<T> o_; }; Moo<int> m;",
393 "template <typename T> struct Moo { New<T> o_; }; Moo<int> m;", "Old",
394 "New"},
395 {"template <typename T> struct Moo { ns::Old<T> o_; }; Moo<int> m;",
396 "template <typename T> struct Moo { ns::New<T> o_; }; Moo<int> m;",
397 "ns::Old", "ns::New"},
Haojian Wu0bc5e022017-04-07 12:37:32 +0000398 })), );
Haojian Wu74f823a2017-04-04 09:30:06 +0000399
400TEST_P(TemplatedClassRenameTest, RenameTemplateClasses) {
401 auto Param = GetParam();
402 std::string Actual =
403 runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
404 CompareSnippets(Param.After, Actual);
405}
406
407TEST_F(ClangRenameTest, RenameClassWithOutOfLineMembers) {
408 std::string Before = R"(
409 class Old {
410 public:
411 Old();
412 ~Old();
413
414 Old* next();
415
416 private:
417 Old* next_;
418 };
419
420 Old::Old() {}
421 Old::~Old() {}
422 Old* Old::next() { return next_; }
423 )";
424 std::string Expected = R"(
425 class New {
426 public:
427 New();
428 ~New();
429
430 New* next();
431
432 private:
433 New* next_;
434 };
435
436 New::New() {}
437 New::~New() {}
438 New* New::next() { return next_; }
439 )";
440 std::string After = runClangRenameOnCode(Before, "Old", "New");
441 CompareSnippets(Expected, After);
442}
443
444TEST_F(ClangRenameTest, RenameClassWithInlineMembers) {
445 std::string Before = R"(
446 class Old {
447 public:
448 Old() {}
449 ~Old() {}
450
451 Old* next() { return next_; }
452
453 private:
454 Old* next_;
455 };
456 )";
457 std::string Expected = R"(
458 class New {
459 public:
460 New() {}
461 ~New() {}
462
463 New* next() { return next_; }
464
465 private:
466 New* next_;
467 };
468 )";
469 std::string After = runClangRenameOnCode(Before, "Old", "New");
470 CompareSnippets(Expected, After);
471}
472
Haojian Wu74f823a2017-04-04 09:30:06 +0000473TEST_F(ClangRenameTest, RenameClassWithNamespaceWithInlineMembers) {
474 std::string Before = R"(
475 namespace ns {
476 class Old {
477 public:
478 Old() {}
479 ~Old() {}
480
481 Old* next() { return next_; }
482
483 private:
484 Old* next_;
485 };
486 } // namespace ns
487 )";
488 std::string Expected = R"(
489 namespace ns {
Haojian Wu19d72992017-10-11 11:15:48 +0000490 class New {
Haojian Wu74f823a2017-04-04 09:30:06 +0000491 public:
Haojian Wu19d72992017-10-11 11:15:48 +0000492 New() {}
Haojian Wu74f823a2017-04-04 09:30:06 +0000493 ~New() {}
494
495 New* next() { return next_; }
496
497 private:
498 New* next_;
499 };
500 } // namespace ns
501 )";
502 std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
503 CompareSnippets(Expected, After);
504}
505
Haojian Wu74f823a2017-04-04 09:30:06 +0000506TEST_F(ClangRenameTest, RenameClassWithNamespaceWithOutOfInlineMembers) {
507 std::string Before = R"(
508 namespace ns {
509 class Old {
510 public:
511 Old();
512 ~Old();
513
514 Old* next();
515
516 private:
517 Old* next_;
518 };
519
520 Old::Old() {}
521 Old::~Old() {}
522 Old* Old::next() { return next_; }
523 } // namespace ns
524 )";
525 std::string Expected = R"(
526 namespace ns {
Haojian Wu19d72992017-10-11 11:15:48 +0000527 class New {
Haojian Wu74f823a2017-04-04 09:30:06 +0000528 public:
Haojian Wu19d72992017-10-11 11:15:48 +0000529 New();
Haojian Wu74f823a2017-04-04 09:30:06 +0000530 ~New();
531
532 New* next();
533
534 private:
535 New* next_;
536 };
537
Haojian Wu19d72992017-10-11 11:15:48 +0000538 New::New() {}
Haojian Wu74f823a2017-04-04 09:30:06 +0000539 New::~New() {}
540 New* New::next() { return next_; }
541 } // namespace ns
542 )";
543 std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
544 CompareSnippets(Expected, After);
545}
546
Haojian Wu74f823a2017-04-04 09:30:06 +0000547TEST_F(ClangRenameTest, RenameClassInInheritedConstructor) {
548 // `using Base::Base;` will generate an implicit constructor containing usage
549 // of `::ns::Old` which should not be matched.
550 std::string Before = R"(
551 namespace ns {
Haojian Wu19d72992017-10-11 11:15:48 +0000552 class Old;
Haojian Wu74f823a2017-04-04 09:30:06 +0000553 class Old {
554 int x;
555 };
556 class Base {
557 protected:
558 Old *moo_;
559 public:
560 Base(Old *moo) : moo_(moo) {}
561 };
562 class Derived : public Base {
563 public:
564 using Base::Base;
565 };
566 } // namespace ns
567 int main() {
568 ::ns::Old foo;
569 ::ns::Derived d(&foo);
570 return 0;
571 })";
572 std::string Expected = R"(
573 namespace ns {
Haojian Wu19d72992017-10-11 11:15:48 +0000574 class New;
575 class New {
Haojian Wu74f823a2017-04-04 09:30:06 +0000576 int x;
577 };
578 class Base {
579 protected:
580 New *moo_;
581 public:
582 Base(New *moo) : moo_(moo) {}
583 };
584 class Derived : public Base {
585 public:
586 using Base::Base;
587 };
588 } // namespace ns
589 int main() {
590 ::ns::New foo;
591 ::ns::Derived d(&foo);
592 return 0;
593 })";
594 std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
595 CompareSnippets(Expected, After);
596}
597
598TEST_F(ClangRenameTest, DontRenameReferencesInImplicitFunction) {
599 std::string Before = R"(
600 namespace ns {
601 class Old {
602 };
603 } // namespace ns
604 struct S {
605 int y;
606 ns::Old old;
607 };
608 void f() {
609 S s1, s2, s3;
610 // This causes an implicit assignment operator to be created.
611 s1 = s2 = s3;
612 }
613 )";
614 std::string Expected = R"(
615 namespace ns {
Haojian Wu19d72992017-10-11 11:15:48 +0000616 class New {
Haojian Wu74f823a2017-04-04 09:30:06 +0000617 };
618 } // namespace ns
619 struct S {
620 int y;
621 ::new_ns::New old;
622 };
623 void f() {
624 S s1, s2, s3;
625 // This causes an implicit assignment operator to be created.
626 s1 = s2 = s3;
627 }
628 )";
629 std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
630 CompareSnippets(Expected, After);
631}
632
Haojian Wu74f823a2017-04-04 09:30:06 +0000633TEST_F(ClangRenameTest, ReferencesInLambdaFunctionParameters) {
634 std::string Before = R"(
635 template <class T>
636 class function;
637 template <class R, class... ArgTypes>
638 class function<R(ArgTypes...)> {
639 public:
640 template <typename Functor>
641 function(Functor f) {}
642
643 function() {}
644
645 R operator()(ArgTypes...) const {}
646 };
647
648 namespace ns {
649 class Old {};
650 void f() {
651 function<void(Old)> func;
652 }
653 } // namespace ns)";
654 std::string Expected = R"(
655 template <class T>
656 class function;
657 template <class R, class... ArgTypes>
658 class function<R(ArgTypes...)> {
659 public:
660 template <typename Functor>
661 function(Functor f) {}
662
663 function() {}
664
665 R operator()(ArgTypes...) const {}
666 };
667
668 namespace ns {
Haojian Wu19d72992017-10-11 11:15:48 +0000669 class New {};
Haojian Wu74f823a2017-04-04 09:30:06 +0000670 void f() {
671 function<void(::new_ns::New)> func;
672 }
673 } // namespace ns)";
674 std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
675 CompareSnippets(Expected, After);
676}
677
Haojian Wu3a4b7ec2017-10-11 14:00:42 +0000678TEST_F(ClangRenameTest, DontChangeIfSameName) {
679 std::string Before = R"(
680 namespace foo {
681 class Old {
682 public:
683 static void foo() {}
684 };
685 }
686
687 void f(foo::Old * x) {
688 foo::Old::foo() ;
689 }
690 using foo::Old;)";
691 std::string Expected = R"(
692 namespace foo {
693 class Old {
694 public:
695 static void foo() {}
696 };
697 }
698
699 void f(foo::Old * x) {
700 foo::Old::foo() ;
701 }
702 using foo::Old;)";
703 std::string After = runClangRenameOnCode(Before, "foo::Old", "foo::Old");
704 CompareSnippets(Expected, After);
705}
706
707TEST_F(ClangRenameTest, ChangeIfNewNameWithLeadingDotDot) {
708 std::string Before = R"(
709 namespace foo {
710 class Old {
711 public:
712 static void foo() {}
713 };
714 }
715
716 void f(foo::Old * x) {
717 foo::Old::foo() ;
718 }
719 using foo::Old;)";
720 std::string Expected = R"(
721 namespace foo {
722 class Old {
723 public:
724 static void foo() {}
725 };
726 }
727
728 void f(::foo::Old * x) {
729 ::foo::Old::foo() ;
730 }
731 using ::foo::Old;)";
732 std::string After = runClangRenameOnCode(Before, "foo::Old", "::foo::Old");
733 CompareSnippets(Expected, After);
734}
735
736TEST_F(ClangRenameTest, ChangeIfSameNameWithLeadingDotDot) {
737 std::string Before = R"(
738 namespace foo {
739 class Old {
740 public:
741 static void foo() {}
742 };
743 }
744
745 void f(foo::Old * x) {
746 foo::Old::foo() ;
747 }
748 using foo::Old;)";
749 std::string Expected = R"(
750 namespace foo {
751 class Old {
752 public:
753 static void foo() {}
754 };
755 }
756
757 void f(::foo::Old * x) {
758 ::foo::Old::foo() ;
759 }
760 using ::foo::Old;)";
761 std::string After = runClangRenameOnCode(Before, "::foo::Old", "::foo::Old");
762 CompareSnippets(Expected, After);
763}
764
765TEST_F(RenameClassTest, UsingAlias) {
766 std::string Before = R"(
767 namespace a { struct A {}; }
768
769 namespace foo {
770 using Alias = a::A;
771 Alias a;
772 })";
773 std::string Expected = R"(
774 namespace a { struct B {}; }
775
776 namespace foo {
777 using Alias = b::B;
778 Alias a;
779 })";
780 std::string After = runClangRenameOnCode(Before, "a::A", "b::B");
781 CompareSnippets(Expected, After);
782}
783
784TEST_F(ClangRenameTest, NestedTemplates) {
785 std::string Before = R"(
786 namespace a { template <typename T> struct A {}; }
787 a::A<a::A<int>> foo;)";
788 std::string Expected = R"(
789 namespace a { template <typename T> struct B {}; }
790 b::B<b::B<int>> foo;)";
791 std::string After = runClangRenameOnCode(Before, "a::A", "b::B");
792 CompareSnippets(Expected, After);
793}
794
795
Haojian Wu74f823a2017-04-04 09:30:06 +0000796} // anonymous namespace
797} // namespace test
798} // namespace clang_rename
799} // namesdpace clang