Clang Project

clang_source_code/unittests/Rename/RenameClassTest.cpp
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
11namespace clang {
12namespace clang_rename {
13namespace test {
14namespace {
15
16class RenameClassTest : public ClangRenameTest {
17public:
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
48INSTANTIATE_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
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"},
301    })), );
302
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"},
397    })), );
398
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(ExpectedAfter);
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(ExpectedAfter);
470}
471
472TEST_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(ExpectedAfter);
503}
504
505TEST_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(ExpectedAfter);
544}
545
546TEST_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(ExpectedAfter);
595}
596
597TEST_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(ExpectedAfter);
630}
631
632TEST_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(ExpectedAfter);
675}
676
677TEST_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(ExpectedAfter);
704}
705
706TEST_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(ExpectedAfter);
733}
734
735TEST_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(ExpectedAfter);
762}
763
764TEST_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(ExpectedAfter);
781}
782
783TEST_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(ExpectedAfter);
792}
793
794
795// anonymous namespace
796// namespace test
797// namespace clang_rename
798// namesdpace clang
799