blob: f6ad962aad8cefb652fce642b04485d0b5932bdf [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
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 {"namespace a {a::Foo f() { return Foo(); }}",
58 "namespace a {b::Bar f() { return b::Bar(); }}"},
59 {"void f(const a::Foo& a1) {}", "void f(const b::Bar& a1) {}"},
60 {"void f(const a::Foo* a1) {}", "void f(const b::Bar* a1) {}"},
61 {"namespace a { void f(Foo a1) {} }",
62 "namespace a { void f(b::Bar a1) {} }"},
63 {"void f(MACRO(a::Foo) a1) {}", "void f(MACRO(b::Bar) a1) {}"},
64 {"void f(MACRO(a::Foo a1)) {}", "void f(MACRO(b::Bar a1)) {}"},
65 {"a::Foo::Nested ns;", "b::Bar::Nested ns;"},
66 {"auto t = a::Foo::Constant;", "auto t = b::Bar::Constant;"},
67 {"a::Foo::Nested ns;", "a::Foo::Nested2 ns;", "a::Foo::Nested",
68 "a::Foo::Nested2"},
69
70 // use namespace and typedefs
71 {"using a::Foo; Foo gA;", "using b::Bar; b::Bar gA;"},
72 {"using a::Foo; void f(Foo gA) {}", "using b::Bar; void f(Bar gA) {}"},
73 {"using a::Foo; namespace x { Foo gA; }",
74 "using b::Bar; namespace x { Bar gA; }"},
75 {"struct S { using T = a::Foo; T a_; };",
76 "struct S { using T = b::Bar; T a_; };"},
77 {"using T = a::Foo; T gA;", "using T = b::Bar; T gA;"},
78 {"typedef a::Foo T; T gA;", "typedef b::Bar T; T gA;"},
79 {"typedef MACRO(a::Foo) T; T gA;", "typedef MACRO(b::Bar) T; T gA;"},
80
81 // struct members and other oddities
82 {"struct S : public a::Foo {};", "struct S : public b::Bar {};"},
83 {"struct F { void f(a::Foo a1) {} };",
84 "struct F { void f(b::Bar a1) {} };"},
85 {"struct F { a::Foo a_; };", "struct F { b::Bar a_; };"},
86 {"struct F { ptr<a::Foo> a_; };", "struct F { ptr<b::Bar> a_; };"},
87
88 {"void f() { a::Foo::Nested ne; }", "void f() { b::Bar::Nested ne; }"},
89 {"void f() { a::Goo::Nested ne; }", "void f() { a::Goo::Nested ne; }"},
90 {"void f() { a::Foo::Nested::NestedEnum e; }",
91 "void f() { b::Bar::Nested::NestedEnum e; }"},
92 {"void f() { auto e = a::Foo::Nested::NestedEnum::E1; }",
93 "void f() { auto e = b::Bar::Nested::NestedEnum::E1; }"},
94 {"void f() { auto e = a::Foo::Nested::E1; }",
95 "void f() { auto e = b::Bar::Nested::E1; }"},
96
97 // templates
98 {"template <typename T> struct Foo { T t; };\n"
99 "void f() { Foo<a::Foo> foo; }",
100 "template <typename T> struct Foo { T t; };\n"
101 "void f() { Foo<b::Bar> foo; }"},
102 {"template <typename T> struct Foo { a::Foo a; };",
103 "template <typename T> struct Foo { b::Bar a; };"},
104 {"template <typename T> void f(T t) {}\n"
105 "void g() { f<a::Foo>(a::Foo()); }",
106 "template <typename T> void f(T t) {}\n"
107 "void g() { f<b::Bar>(b::Bar()); }"},
108 {"template <typename T> int f() { return 1; }\n"
109 "template <> int f<a::Foo>() { return 2; }\n"
110 "int g() { return f<a::Foo>(); }",
111 "template <typename T> int f() { return 1; }\n"
112 "template <> int f<b::Bar>() { return 2; }\n"
113 "int g() { return f<b::Bar>(); }"},
114 {"struct Foo { template <typename T> T foo(); };\n"
115 "void g() { Foo f; auto a = f.template foo<a::Foo>(); }",
116 "struct Foo { template <typename T> T foo(); };\n"
117 "void g() { Foo f; auto a = f.template foo<b::Bar>(); }"},
118
119 // The following two templates are distilled from regressions found in
120 // unique_ptr<> and type_traits.h
121 {"template <typename T> struct outer {\n"
122 " typedef T type;\n"
123 " type Baz();\n"
124 " };\n"
125 " outer<a::Foo> g_A;",
126 "template <typename T> struct outer {\n"
127 " typedef T type;\n"
128 " type Baz();\n"
129 " };\n"
130 " outer<b::Bar> g_A;"},
131 {"template <typename T> struct nested { typedef T type; };\n"
132 "template <typename T> struct outer { typename nested<T>::type Foo(); "
133 "};\n"
134 "outer<a::Foo> g_A;",
135 "template <typename T> struct nested { typedef T type; };\n"
136 "template <typename T> struct outer { typename nested<T>::type Foo(); "
137 "};\n"
138 "outer<b::Bar> g_A;"},
139
140 // macros
141 {"#define FOO(T, t) T t\n"
142 "void f() { FOO(a::Foo, a1); FOO(a::Foo, a2); }",
143 "#define FOO(T, t) T t\n"
144 "void f() { FOO(b::Bar, a1); FOO(b::Bar, a2); }"},
145 {"#define FOO(n) a::Foo n\n"
146 " void f() { FOO(a1); FOO(a2); }",
147 "#define FOO(n) b::Bar n\n"
148 " void f() { FOO(a1); FOO(a2); }"},
149
150 // Pointer to member functions
151 {"auto gA = &a::Foo::func;", "auto gA = &b::Bar::func;"},
152 {"using a::Foo; auto gA = &Foo::func;",
153 "using b::Bar; auto gA = &b::Bar::func;"},
154 {"using a::Foo; namespace x { auto gA = &Foo::func; }",
155 "using b::Bar; namespace x { auto gA = &Bar::func; }"},
156 {"typedef a::Foo T; auto gA = &T::func;",
157 "typedef b::Bar T; auto gA = &T::func;"},
158 {"auto gA = &MACRO(a::Foo)::func;", "auto gA = &MACRO(b::Bar)::func;"},
159
160 // Short match inside a namespace
161 {"namespace a { void f(Foo a1) {} }",
162 "namespace a { void f(b::Bar a1) {} }"},
163
164 // Correct match.
165 {"using a::Foo; struct F { ptr<Foo> a_; };",
166 "using b::Bar; struct F { ptr<Bar> a_; };"},
167
168 // avoid false positives
169 {"void f(b::Foo a) {}", "void f(b::Foo a) {}"},
170 {"namespace b { void f(Foo a) {} }",
171 "namespace b { void f(Foo a) {} }"},
172
173 // friends, everyone needs friends.
174 {"class Foo { int i; friend class a::Foo; };",
175 "class Foo { int i; friend class b::Bar; };"},
176 })));
177
178TEST_P(RenameClassTest, RenameClasses) {
179 auto Param = GetParam();
180 std::string OldName = Param.OldName.empty() ? "a::Foo" : Param.OldName;
181 std::string NewName = Param.NewName.empty() ? "b::Bar" : Param.NewName;
182 std::string Actual = runClangRenameOnCode(Param.Before, OldName, NewName);
183 CompareSnippets(Param.After, Actual);
184}
185
186class NamespaceDetectionTest : public ClangRenameTest {
187protected:
188 NamespaceDetectionTest() {
189 AppendToHeader(R"(
190 class Old {};
191 namespace o1 {
192 class Old {};
193 namespace o2 {
194 class Old {};
195 namespace o3 {
196 class Old {};
197 } // namespace o3
198 } // namespace o2
199 } // namespace o1
200 )");
201 }
202};
203
204INSTANTIATE_TEST_CASE_P(
205 RenameClassTest, NamespaceDetectionTest,
206 ::testing::ValuesIn(std::vector<Case>({
207 // Test old and new namespace overlap.
208 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
209 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
210 "o1::o2::o3::Old", "o1::o2::o3::New"},
211 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
212 "namespace o1 { namespace o2 { namespace o3 { n3::New moo; } } }",
213 "o1::o2::o3::Old", "o1::o2::n3::New"},
214 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
215 "namespace o1 { namespace o2 { namespace o3 { n2::n3::New moo; } } }",
216 "o1::o2::o3::Old", "o1::n2::n3::New"},
217 {"namespace o1 { namespace o2 { Old moo; } }",
218 "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old",
219 "::o1::o2::New"},
220 {"namespace o1 { namespace o2 { Old moo; } }",
221 "namespace o1 { namespace o2 { n2::New moo; } }", "::o1::o2::Old",
222 "::o1::n2::New"},
223 {"namespace o1 { namespace o2 { Old moo; } }",
224 "namespace o1 { namespace o2 { ::n1::n2::New moo; } }",
225 "::o1::o2::Old", "::n1::n2::New"},
226 {"namespace o1 { namespace o2 { Old moo; } }",
227 "namespace o1 { namespace o2 { n1::n2::New moo; } }", "::o1::o2::Old",
228 "n1::n2::New"},
229
230 // Test old and new namespace with differing depths.
231 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
232 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
233 "o1::o2::o3::Old", "::o1::New"},
234 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
235 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
236 "o1::o2::o3::Old", "::o1::o2::New"},
237 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
238 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
239 "o1::o2::o3::Old", "o1::New"},
240 {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
241 "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
242 "o1::o2::o3::Old", "o1::o2::New"},
243 {"Old moo;", "o1::New moo;", "::Old", "o1::New"},
244 {"Old moo;", "o1::New moo;", "Old", "o1::New"},
245 {"namespace o1 { ::Old moo; }", "namespace o1 { New moo; }", "Old",
246 "o1::New"},
247 {"namespace o1 { namespace o2 { Old moo; } }",
248 "namespace o1 { namespace o2 { ::New moo; } }", "::o1::o2::Old",
249 "::New"},
250 {"namespace o1 { namespace o2 { Old moo; } }",
251 "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old", "New"},
252
253 // Test moving into the new namespace at different levels.
254 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
255 "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",
256 "::n1::n2::New"},
257 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
258 "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",
259 "n1::n2::New"},
260 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
261 "namespace n1 { namespace n2 { o2::New moo; } }", "::o1::o2::Old",
262 "::n1::o2::New"},
263 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
264 "namespace n1 { namespace n2 { o2::New moo; } }", "::o1::o2::Old",
265 "n1::o2::New"},
266 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
267 "namespace n1 { namespace n2 { ::o1::o2::New moo; } }",
268 "::o1::o2::Old", "::o1::o2::New"},
269 {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
270 "namespace n1 { namespace n2 { o1::o2::New moo; } }", "::o1::o2::Old",
271 "o1::o2::New"},
272
273 // Test friends declarations.
274 {"class Foo { friend class o1::Old; };",
275 "class Foo { friend class o1::New; };", "o1::Old", "o1::New"},
276 {"class Foo { int i; friend class o1::Old; };",
277 "class Foo { int i; friend class ::o1::New; };", "::o1::Old",
278 "::o1::New"},
279 {"namespace o1 { class Foo { int i; friend class Old; }; }",
280 "namespace o1 { class Foo { int i; friend class New; }; }", "o1::Old",
281 "o1::New"},
282 {"namespace o1 { class Foo { int i; friend class Old; }; }",
283 "namespace o1 { class Foo { int i; friend class New; }; }",
284 "::o1::Old", "::o1::New"},
285 })));
286
287TEST_P(NamespaceDetectionTest, RenameClasses) {
288 auto Param = GetParam();
289 std::string Actual =
290 runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
291 CompareSnippets(Param.After, Actual);
292}
293
294class TemplatedClassRenameTest : public ClangRenameTest {
295protected:
296 TemplatedClassRenameTest() {
297 AppendToHeader(R"(
298 template <typename T> struct Old {
299 T t_;
300 T f() { return T(); };
301 static T s(T t) { return t; }
302 };
303 namespace ns {
304 template <typename T> struct Old {
305 T t_;
306 T f() { return T(); };
307 static T s(T t) { return t; }
308 };
309 } // namespace ns
310
311 namespace o1 {
312 namespace o2 {
313 namespace o3 {
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 o3
320 } // namespace o2
321 } // namespace o1
322 )");
323 }
324};
325
326INSTANTIATE_TEST_CASE_P(
327 RenameClassTests, TemplatedClassRenameTest,
328 ::testing::ValuesIn(std::vector<Case>({
329 {"Old<int> gI; Old<bool> gB;", "New<int> gI; New<bool> gB;", "Old",
330 "New"},
331 {"ns::Old<int> gI; ns::Old<bool> gB;",
332 "ns::New<int> gI; ns::New<bool> gB;", "ns::Old", "ns::New"},
333 {"auto gI = &Old<int>::f; auto gB = &Old<bool>::f;",
334 "auto gI = &New<int>::f; auto gB = &New<bool>::f;", "Old", "New"},
335 {"auto gI = &ns::Old<int>::f;", "auto gI = &ns::New<int>::f;",
336 "ns::Old", "ns::New"},
337
338 {"int gI = Old<int>::s(0); bool gB = Old<bool>::s(false);",
339 "int gI = New<int>::s(0); bool gB = New<bool>::s(false);", "Old",
340 "New"},
341 {"int gI = ns::Old<int>::s(0); bool gB = ns::Old<bool>::s(false);",
342 "int gI = ns::New<int>::s(0); bool gB = ns::New<bool>::s(false);",
343 "ns::Old", "ns::New"},
344
345 {"struct S { Old<int*> o_; };", "struct S { New<int*> o_; };", "Old",
346 "New"},
347 {"struct S { ns::Old<int*> o_; };", "struct S { ns::New<int*> o_; };",
348 "ns::Old", "ns::New"},
349
350 {"auto a = reinterpret_cast<Old<int>*>(new Old<int>);",
351 "auto a = reinterpret_cast<New<int>*>(new New<int>);", "Old", "New"},
352 {"auto a = reinterpret_cast<ns::Old<int>*>(new ns::Old<int>);",
353 "auto a = reinterpret_cast<ns::New<int>*>(new ns::New<int>);",
354 "ns::Old", "ns::New"},
355 {"auto a = reinterpret_cast<const Old<int>*>(new Old<int>);",
356 "auto a = reinterpret_cast<const New<int>*>(new New<int>);", "Old",
357 "New"},
358 {"auto a = reinterpret_cast<const ns::Old<int>*>(new ns::Old<int>);",
359 "auto a = reinterpret_cast<const ns::New<int>*>(new ns::New<int>);",
360 "ns::Old", "ns::New"},
361
362 {"Old<bool>& foo();", "New<bool>& foo();", "Old", "New"},
363 {"ns::Old<bool>& foo();", "ns::New<bool>& foo();", "ns::Old",
364 "ns::New"},
365 {"o1::o2::o3::Old<bool>& foo();", "o1::o2::o3::New<bool>& foo();",
366 "o1::o2::o3::Old", "o1::o2::o3::New"},
367 {"namespace ns { Old<bool>& foo(); }",
368 "namespace ns { New<bool>& foo(); }", "ns::Old", "ns::New"},
369 {"const Old<bool>& foo();", "const New<bool>& foo();", "Old", "New"},
370 {"const ns::Old<bool>& foo();", "const ns::New<bool>& foo();",
371 "ns::Old", "ns::New"},
372
373 // FIXME: figure out why this only works when Moo gets
374 // specialized at some point.
375 {"template <typename T> struct Moo { Old<T> o_; }; Moo<int> m;",
376 "template <typename T> struct Moo { New<T> o_; }; Moo<int> m;", "Old",
377 "New"},
378 {"template <typename T> struct Moo { ns::Old<T> o_; }; Moo<int> m;",
379 "template <typename T> struct Moo { ns::New<T> o_; }; Moo<int> m;",
380 "ns::Old", "ns::New"},
381 })));
382
383TEST_P(TemplatedClassRenameTest, RenameTemplateClasses) {
384 auto Param = GetParam();
385 std::string Actual =
386 runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
387 CompareSnippets(Param.After, Actual);
388}
389
390TEST_F(ClangRenameTest, RenameClassWithOutOfLineMembers) {
391 std::string Before = R"(
392 class Old {
393 public:
394 Old();
395 ~Old();
396
397 Old* next();
398
399 private:
400 Old* next_;
401 };
402
403 Old::Old() {}
404 Old::~Old() {}
405 Old* Old::next() { return next_; }
406 )";
407 std::string Expected = R"(
408 class New {
409 public:
410 New();
411 ~New();
412
413 New* next();
414
415 private:
416 New* next_;
417 };
418
419 New::New() {}
420 New::~New() {}
421 New* New::next() { return next_; }
422 )";
423 std::string After = runClangRenameOnCode(Before, "Old", "New");
424 CompareSnippets(Expected, After);
425}
426
427TEST_F(ClangRenameTest, RenameClassWithInlineMembers) {
428 std::string Before = R"(
429 class Old {
430 public:
431 Old() {}
432 ~Old() {}
433
434 Old* next() { return next_; }
435
436 private:
437 Old* next_;
438 };
439 )";
440 std::string Expected = R"(
441 class New {
442 public:
443 New() {}
444 ~New() {}
445
446 New* next() { return next_; }
447
448 private:
449 New* next_;
450 };
451 )";
452 std::string After = runClangRenameOnCode(Before, "Old", "New");
453 CompareSnippets(Expected, After);
454}
455
456// FIXME: no prefix qualifiers being added to the class definition and
457// constructor.
458TEST_F(ClangRenameTest, RenameClassWithNamespaceWithInlineMembers) {
459 std::string Before = R"(
460 namespace ns {
461 class Old {
462 public:
463 Old() {}
464 ~Old() {}
465
466 Old* next() { return next_; }
467
468 private:
469 Old* next_;
470 };
471 } // namespace ns
472 )";
473 std::string Expected = R"(
474 namespace ns {
475 class ns::New {
476 public:
477 ns::New() {}
478 ~New() {}
479
480 New* next() { return next_; }
481
482 private:
483 New* next_;
484 };
485 } // namespace ns
486 )";
487 std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
488 CompareSnippets(Expected, After);
489}
490
491// FIXME: no prefix qualifiers being added to the class definition and
492// constructor.
493TEST_F(ClangRenameTest, RenameClassWithNamespaceWithOutOfInlineMembers) {
494 std::string Before = R"(
495 namespace ns {
496 class Old {
497 public:
498 Old();
499 ~Old();
500
501 Old* next();
502
503 private:
504 Old* next_;
505 };
506
507 Old::Old() {}
508 Old::~Old() {}
509 Old* Old::next() { return next_; }
510 } // namespace ns
511 )";
512 std::string Expected = R"(
513 namespace ns {
514 class ns::New {
515 public:
516 ns::New();
517 ~New();
518
519 New* next();
520
521 private:
522 New* next_;
523 };
524
525 New::ns::New() {}
526 New::~New() {}
527 New* New::next() { return next_; }
528 } // namespace ns
529 )";
530 std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
531 CompareSnippets(Expected, After);
532}
533
534// FIXME: no prefix qualifiers being added to the definition.
535TEST_F(ClangRenameTest, RenameClassInInheritedConstructor) {
536 // `using Base::Base;` will generate an implicit constructor containing usage
537 // of `::ns::Old` which should not be matched.
538 std::string Before = R"(
539 namespace ns {
540 class Old {
541 int x;
542 };
543 class Base {
544 protected:
545 Old *moo_;
546 public:
547 Base(Old *moo) : moo_(moo) {}
548 };
549 class Derived : public Base {
550 public:
551 using Base::Base;
552 };
553 } // namespace ns
554 int main() {
555 ::ns::Old foo;
556 ::ns::Derived d(&foo);
557 return 0;
558 })";
559 std::string Expected = R"(
560 namespace ns {
561 class ns::New {
562 int x;
563 };
564 class Base {
565 protected:
566 New *moo_;
567 public:
568 Base(New *moo) : moo_(moo) {}
569 };
570 class Derived : public Base {
571 public:
572 using Base::Base;
573 };
574 } // namespace ns
575 int main() {
576 ::ns::New foo;
577 ::ns::Derived d(&foo);
578 return 0;
579 })";
580 std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
581 CompareSnippets(Expected, After);
582}
583
584TEST_F(ClangRenameTest, DontRenameReferencesInImplicitFunction) {
585 std::string Before = R"(
586 namespace ns {
587 class Old {
588 };
589 } // namespace ns
590 struct S {
591 int y;
592 ns::Old old;
593 };
594 void f() {
595 S s1, s2, s3;
596 // This causes an implicit assignment operator to be created.
597 s1 = s2 = s3;
598 }
599 )";
600 std::string Expected = R"(
601 namespace ns {
602 class ::new_ns::New {
603 };
604 } // namespace ns
605 struct S {
606 int y;
607 ::new_ns::New old;
608 };
609 void f() {
610 S s1, s2, s3;
611 // This causes an implicit assignment operator to be created.
612 s1 = s2 = s3;
613 }
614 )";
615 std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
616 CompareSnippets(Expected, After);
617}
618
619// FIXME: no prefix qualifiers being adding to the definition.
620TEST_F(ClangRenameTest, ReferencesInLambdaFunctionParameters) {
621 std::string Before = R"(
622 template <class T>
623 class function;
624 template <class R, class... ArgTypes>
625 class function<R(ArgTypes...)> {
626 public:
627 template <typename Functor>
628 function(Functor f) {}
629
630 function() {}
631
632 R operator()(ArgTypes...) const {}
633 };
634
635 namespace ns {
636 class Old {};
637 void f() {
638 function<void(Old)> func;
639 }
640 } // namespace ns)";
641 std::string Expected = R"(
642 template <class T>
643 class function;
644 template <class R, class... ArgTypes>
645 class function<R(ArgTypes...)> {
646 public:
647 template <typename Functor>
648 function(Functor f) {}
649
650 function() {}
651
652 R operator()(ArgTypes...) const {}
653 };
654
655 namespace ns {
656 class ::new_ns::New {};
657 void f() {
658 function<void(::new_ns::New)> func;
659 }
660 } // namespace ns)";
661 std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
662 CompareSnippets(Expected, After);
663}
664
665} // anonymous namespace
666} // namespace test
667} // namespace clang_rename
668} // namesdpace clang