1 //===-- RenameClassTest.cpp - unit tests for renaming classes -------------===//
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 RenameClassTest : public ClangRenameTest {
17 public:
RenameClassTest()18   RenameClassTest() {
19     AppendToHeader(R"(
20       namespace a {
21         class Foo {
22           public:
23             struct Nested {
24               enum NestedEnum {E1, E2};
25             };
26             void func() {}
27           static int Constant;
28         };
29         class Goo {
30           public:
31             struct Nested {
32               enum NestedEnum {E1, E2};
33             };
34         };
35         int Foo::Constant = 1;
36       } // namespace a
37       namespace b {
38       class Foo {};
39       } // namespace b
40 
41       #define MACRO(x) x
42 
43       template<typename T> class ptr {};
44     )");
45   }
46 };
47 
48 INSTANTIATE_TEST_CASE_P(
49     RenameClassTests, RenameClassTest,
50     testing::ValuesIn(std::vector<Case>({
51         // basic classes
52         {"a::Foo f;", "b::Bar f;", "", ""},
53         {"::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          "", ""},
58         {"namespace a {a::Foo f() { return Foo(); }}",
59          "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) {}", "", ""},
62         {"namespace a { void f(Foo a1) {} }",
63          "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;", "", ""},
68         {"a::Foo::Nested ns;", "a::Foo::Nested2 ns;", "a::Foo::Nested",
69          "a::Foo::Nested2"},
70 
71         // use namespace and typedefs
72         {"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          "", ""},
75         {"using a::Foo; namespace x { Foo gA; }",
76          "using b::Bar; namespace x { Bar gA; }", "", ""},
77         {"struct S { using T = a::Foo; T a_; };",
78          "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          ""},
83 
84         // struct members and other oddities
85         {"struct S : public a::Foo {};", "struct S : public b::Bar {};", "",
86          ""},
87         {"struct F { void f(a::Foo a1) {} };",
88          "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          ""},
92 
93         {"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          "", ""},
97         {"void f() { a::Foo::Nested::NestedEnum e; }",
98          "void f() { b::Bar::Nested::NestedEnum e; }", "", ""},
99         {"void f() { auto e = a::Foo::Nested::NestedEnum::E1; }",
100          "void f() { auto e = b::Bar::Nested::NestedEnum::E1; }", "", ""},
101         {"void f() { auto e = a::Foo::Nested::E1; }",
102          "void f() { auto e = b::Bar::Nested::E1; }", "", ""},
103 
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"
108          "void f() { Foo<b::Bar> foo; }",
109          "", ""},
110         {"template <typename T> struct Foo { a::Foo a; };",
111          "template <typename T> struct Foo { b::Bar a; };", "", ""},
112         {"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"
115          "void g() { f<b::Bar>(b::Bar()); }",
116          "", ""},
117         {"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"
122          "int g() { return f<b::Bar>(); }",
123          "", ""},
124         {"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"
127          "void g() { Foo f;  auto a = f.template foo<b::Bar>(); }",
128          "", ""},
129 
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"
141          "    outer<b::Bar> g_A;",
142          "", ""},
143         {"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"
150          "outer<b::Bar> g_A;",
151          "", ""},
152 
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"
157          "void f() { FOO(b::Bar, a1); FOO(b::Bar, a2); }",
158          "", ""},
159         {"#define FOO(n) a::Foo n\n"
160          " void f() { FOO(a1); FOO(a2); }",
161          "#define FOO(n) b::Bar n\n"
162          " void f() { FOO(a1); FOO(a2); }",
163          "", ""},
164 
165         // Pointer to member functions
166         {"auto gA = &a::Foo::func;", "auto gA = &b::Bar::func;", "", ""},
167         {"using a::Foo; auto gA = &Foo::func;",
168          "using b::Bar; auto gA = &b::Bar::func;", "", ""},
169         {"using a::Foo; namespace x { auto gA = &Foo::func; }",
170          "using b::Bar; namespace x { auto gA = &Bar::func; }", "", ""},
171         {"typedef a::Foo T; auto gA = &T::func;",
172          "typedef b::Bar T; auto gA = &T::func;", "", ""},
173         {"auto gA = &MACRO(a::Foo)::func;", "auto gA = &MACRO(b::Bar)::func;",
174          "", ""},
175 
176         // Short match inside a namespace
177         {"namespace a { void f(Foo a1) {} }",
178          "namespace a { void f(b::Bar a1) {} }", "", ""},
179 
180         // Correct match.
181         {"using a::Foo; struct F { ptr<Foo> a_; };",
182          "using b::Bar; struct F { ptr<Bar> a_; };", "", ""},
183 
184         // avoid false positives
185         {"void f(b::Foo a) {}", "void f(b::Foo a) {}", "", ""},
186         {"namespace b { void f(Foo a) {} }", "namespace b { void f(Foo a) {} }",
187          "", ""},
188 
189         // friends, everyone needs friends.
190         {"class Foo { int i; friend class a::Foo; };",
191          "class Foo { int i; friend class b::Bar; };", "", ""},
192     })), );
193 
TEST_P(RenameClassTest,RenameClasses)194 TEST_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 
202 class NamespaceDetectionTest : public ClangRenameTest {
203 protected:
NamespaceDetectionTest()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 
220 INSTANTIATE_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"},
301     })), );
302 
TEST_P(NamespaceDetectionTest,RenameClasses)303 TEST_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 
310 class TemplatedClassRenameTest : public ClangRenameTest {
311 protected:
TemplatedClassRenameTest()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 
342 INSTANTIATE_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"},
397     })), );
398 
TEST_P(TemplatedClassRenameTest,RenameTemplateClasses)399 TEST_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 
TEST_F(ClangRenameTest,RenameClassWithOutOfLineMembers)406 TEST_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 
TEST_F(ClangRenameTest,RenameClassWithInlineMembers)443 TEST_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 
TEST_F(ClangRenameTest,RenameClassWithNamespaceWithInlineMembers)472 TEST_F(ClangRenameTest, RenameClassWithNamespaceWithInlineMembers) {
473   std::string Before = R"(
474       namespace ns {
475       class Old {
476        public:
477         Old() {}
478         ~Old() {}
479 
480         Old* next() { return next_; }
481 
482        private:
483         Old* next_;
484       };
485       }  // namespace ns
486     )";
487   std::string Expected = R"(
488       namespace ns {
489       class New {
490        public:
491         New() {}
492         ~New() {}
493 
494         New* next() { return next_; }
495 
496        private:
497         New* next_;
498       };
499       }  // namespace ns
500     )";
501   std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
502   CompareSnippets(Expected, After);
503 }
504 
TEST_F(ClangRenameTest,RenameClassWithNamespaceWithOutOfInlineMembers)505 TEST_F(ClangRenameTest, RenameClassWithNamespaceWithOutOfInlineMembers) {
506   std::string Before = R"(
507       namespace ns {
508       class Old {
509        public:
510         Old();
511         ~Old();
512 
513         Old* next();
514 
515        private:
516         Old* next_;
517       };
518 
519       Old::Old() {}
520       Old::~Old() {}
521       Old* Old::next() { return next_; }
522       }  // namespace ns
523     )";
524   std::string Expected = R"(
525       namespace ns {
526       class New {
527        public:
528         New();
529         ~New();
530 
531         New* next();
532 
533        private:
534         New* next_;
535       };
536 
537       New::New() {}
538       New::~New() {}
539       New* New::next() { return next_; }
540       }  // namespace ns
541     )";
542   std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
543   CompareSnippets(Expected, After);
544 }
545 
TEST_F(ClangRenameTest,RenameClassInInheritedConstructor)546 TEST_F(ClangRenameTest, RenameClassInInheritedConstructor) {
547   // `using Base::Base;` will generate an implicit constructor containing usage
548   // of `::ns::Old` which should not be matched.
549   std::string Before = R"(
550       namespace ns {
551       class Old;
552       class Old {
553         int x;
554       };
555       class Base {
556        protected:
557         Old *moo_;
558        public:
559         Base(Old *moo) : moo_(moo) {}
560       };
561       class Derived : public Base {
562        public:
563          using Base::Base;
564       };
565       }  // namespace ns
566       int main() {
567         ::ns::Old foo;
568         ::ns::Derived d(&foo);
569         return 0;
570       })";
571   std::string Expected = R"(
572       namespace ns {
573       class New;
574       class New {
575         int x;
576       };
577       class Base {
578        protected:
579         New *moo_;
580        public:
581         Base(New *moo) : moo_(moo) {}
582       };
583       class Derived : public Base {
584        public:
585          using Base::Base;
586       };
587       }  // namespace ns
588       int main() {
589         ::ns::New foo;
590         ::ns::Derived d(&foo);
591         return 0;
592       })";
593   std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
594   CompareSnippets(Expected, After);
595 }
596 
TEST_F(ClangRenameTest,DontRenameReferencesInImplicitFunction)597 TEST_F(ClangRenameTest, DontRenameReferencesInImplicitFunction) {
598   std::string Before = R"(
599       namespace ns {
600       class Old {
601       };
602       } // namespace ns
603       struct S {
604         int y;
605         ns::Old old;
606       };
607       void f() {
608         S s1, s2, s3;
609         // This causes an implicit assignment operator to be created.
610         s1 = s2 = s3;
611       }
612       )";
613   std::string Expected = R"(
614       namespace ns {
615       class New {
616       };
617       } // namespace ns
618       struct S {
619         int y;
620         ::new_ns::New old;
621       };
622       void f() {
623         S s1, s2, s3;
624         // This causes an implicit assignment operator to be created.
625         s1 = s2 = s3;
626       }
627       )";
628   std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
629   CompareSnippets(Expected, After);
630 }
631 
TEST_F(ClangRenameTest,ReferencesInLambdaFunctionParameters)632 TEST_F(ClangRenameTest, ReferencesInLambdaFunctionParameters) {
633   std::string Before = R"(
634       template <class T>
635       class function;
636       template <class R, class... ArgTypes>
637       class function<R(ArgTypes...)> {
638       public:
639         template <typename Functor>
640         function(Functor f) {}
641 
642         function() {}
643 
644         R operator()(ArgTypes...) const {}
645       };
646 
647       namespace ns {
648       class Old {};
649       void f() {
650         function<void(Old)> func;
651       }
652       }  // namespace ns)";
653   std::string Expected = R"(
654       template <class T>
655       class function;
656       template <class R, class... ArgTypes>
657       class function<R(ArgTypes...)> {
658       public:
659         template <typename Functor>
660         function(Functor f) {}
661 
662         function() {}
663 
664         R operator()(ArgTypes...) const {}
665       };
666 
667       namespace ns {
668       class New {};
669       void f() {
670         function<void(::new_ns::New)> func;
671       }
672       }  // namespace ns)";
673   std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
674   CompareSnippets(Expected, After);
675 }
676 
TEST_F(ClangRenameTest,DontChangeIfSameName)677 TEST_F(ClangRenameTest, DontChangeIfSameName) {
678   std::string Before = R"(
679       namespace foo {
680       class Old {
681        public:
682          static void foo() {}
683       };
684       }
685 
686       void f(foo::Old * x) {
687         foo::Old::foo() ;
688       }
689       using foo::Old;)";
690   std::string Expected = R"(
691       namespace foo {
692       class Old {
693        public:
694          static void foo() {}
695       };
696       }
697 
698       void f(foo::Old * x) {
699         foo::Old::foo() ;
700       }
701       using foo::Old;)";
702   std::string After = runClangRenameOnCode(Before, "foo::Old", "foo::Old");
703   CompareSnippets(Expected, After);
704 }
705 
TEST_F(ClangRenameTest,ChangeIfNewNameWithLeadingDotDot)706 TEST_F(ClangRenameTest, ChangeIfNewNameWithLeadingDotDot) {
707   std::string Before = R"(
708       namespace foo {
709       class Old {
710        public:
711          static void foo() {}
712       };
713       }
714 
715       void f(foo::Old * x) {
716         foo::Old::foo() ;
717       }
718       using foo::Old;)";
719   std::string Expected = R"(
720       namespace foo {
721       class Old {
722        public:
723          static void foo() {}
724       };
725       }
726 
727       void f(::foo::Old * x) {
728         ::foo::Old::foo() ;
729       }
730       using ::foo::Old;)";
731   std::string After = runClangRenameOnCode(Before, "foo::Old", "::foo::Old");
732   CompareSnippets(Expected, After);
733 }
734 
TEST_F(ClangRenameTest,ChangeIfSameNameWithLeadingDotDot)735 TEST_F(ClangRenameTest, ChangeIfSameNameWithLeadingDotDot) {
736   std::string Before = R"(
737       namespace foo {
738       class Old {
739        public:
740          static void foo() {}
741       };
742       }
743 
744       void f(foo::Old * x) {
745         foo::Old::foo() ;
746       }
747       using foo::Old;)";
748   std::string Expected = R"(
749       namespace foo {
750       class Old {
751        public:
752          static void foo() {}
753       };
754       }
755 
756       void f(::foo::Old * x) {
757         ::foo::Old::foo() ;
758       }
759       using ::foo::Old;)";
760   std::string After = runClangRenameOnCode(Before, "::foo::Old", "::foo::Old");
761   CompareSnippets(Expected, After);
762 }
763 
TEST_F(RenameClassTest,UsingAlias)764 TEST_F(RenameClassTest, UsingAlias) {
765   std::string Before = R"(
766       namespace a { struct A {}; }
767 
768       namespace foo {
769       using Alias = a::A;
770       Alias a;
771       })";
772   std::string Expected = R"(
773       namespace a { struct B {}; }
774 
775       namespace foo {
776       using Alias = b::B;
777       Alias a;
778       })";
779   std::string After = runClangRenameOnCode(Before, "a::A", "b::B");
780   CompareSnippets(Expected, After);
781 }
782 
TEST_F(ClangRenameTest,NestedTemplates)783 TEST_F(ClangRenameTest, NestedTemplates) {
784   std::string Before = R"(
785       namespace a { template <typename T> struct A {}; }
786       a::A<a::A<int>> foo;)";
787   std::string Expected = R"(
788       namespace a { template <typename T> struct B {}; }
789       b::B<b::B<int>> foo;)";
790   std::string After = runClangRenameOnCode(Before, "a::A", "b::B");
791   CompareSnippets(Expected, After);
792 }
793 
794 
795 } // anonymous namespace
796 } // namespace test
797 } // namespace clang_rename
798 } // namesdpace clang
799