blob: ef84b4bdb72bd9b7eb22c8b1e955285bec33be9f [file] [log] [blame]
Haojian Wu6f60ff82017-10-16 10:37:42 +00001//===-- RenameFunctionTest.cpp - unit tests for renaming functions --------===//
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 RenameFunctionTest : public ClangRenameTest {
18public:
19 RenameFunctionTest() {
20 AppendToHeader(R"(
21 struct A {
22 static bool Foo();
23 static bool Spam();
24 };
25 struct B {
26 static void Same();
27 static bool Foo();
28 static int Eric(int x);
29 };
30 void Same(int x);
31 int Eric(int x);
32 namespace base {
33 void Same();
34 void ToNanoSeconds();
35 void ToInt64NanoSeconds();
36 })");
37 }
38};
39
40TEST_F(RenameFunctionTest, RefactorsAFoo) {
41 std::string Before = R"(
42 void f() {
43 A::Foo();
44 ::A::Foo();
45 })";
46 std::string Expected = R"(
47 void f() {
48 A::Bar();
49 ::A::Bar();
50 })";
51
52 std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar");
53 CompareSnippets(Expected, After);
54}
55
56TEST_F(RenameFunctionTest, RefactorsNonCallingAFoo) {
57 std::string Before = R"(
58 bool g(bool (*func)()) {
59 return func();
60 }
61 void f() {
62 auto *ref1 = A::Foo;
63 auto *ref2 = ::A::Foo;
64 g(A::Foo);
65 })";
66 std::string Expected = R"(
67 bool g(bool (*func)()) {
68 return func();
69 }
70 void f() {
71 auto *ref1 = A::Bar;
72 auto *ref2 = ::A::Bar;
73 g(A::Bar);
74 })";
75 std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar");
76 CompareSnippets(Expected, After);
77}
78
79TEST_F(RenameFunctionTest, RefactorsEric) {
80 std::string Before = R"(
81 void f() {
82 if (Eric(3)==4) ::Eric(2);
83 })";
84 std::string Expected = R"(
85 void f() {
86 if (Larry(3)==4) ::Larry(2);
87 })";
88 std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
89 CompareSnippets(Expected, After);
90}
91
92TEST_F(RenameFunctionTest, RefactorsNonCallingEric) {
93 std::string Before = R"(
94 int g(int (*func)(int)) {
95 return func(1);
96 }
97 void f() {
98 auto *ref = ::Eric;
99 g(Eric);
100 })";
101 std::string Expected = R"(
102 int g(int (*func)(int)) {
103 return func(1);
104 }
105 void f() {
106 auto *ref = ::Larry;
107 g(Larry);
108 })";
109 std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
110 CompareSnippets(Expected, After);
111}
112
113TEST_F(RenameFunctionTest, DoesNotRefactorBFoo) {
114 std::string Before = R"(
115 void f() {
116 B::Foo();
117 })";
118 std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar");
119 CompareSnippets(Before, After);
120}
121
122TEST_F(RenameFunctionTest, DoesNotRefactorBEric) {
123 std::string Before = R"(
124 void f() {
125 B::Eric(2);
126 })";
127 std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
128 CompareSnippets(Before, After);
129}
130
131TEST_F(RenameFunctionTest, DoesNotRefactorCEric) {
132 std::string Before = R"(
133 namespace C { int Eric(int x); }
134 void f() {
135 if (C::Eric(3)==4) ::C::Eric(2);
136 })";
137 std::string Expected = R"(
138 namespace C { int Eric(int x); }
139 void f() {
140 if (C::Eric(3)==4) ::C::Eric(2);
141 })";
142 std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
143 CompareSnippets(Expected, After);
144}
145
146TEST_F(RenameFunctionTest, DoesNotRefactorEricInNamespaceC) {
147 std::string Before = R"(
148 namespace C {
149 int Eric(int x);
150 void f() {
151 if (Eric(3)==4) Eric(2);
152 }
153 } // namespace C)";
154 std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
155 CompareSnippets(Before, After);
156}
157
158TEST_F(RenameFunctionTest, NamespaceQualified) {
159 std::string Before = R"(
160 void f() {
161 base::ToNanoSeconds();
162 ::base::ToNanoSeconds();
163 }
164 void g() {
165 using base::ToNanoSeconds;
166 base::ToNanoSeconds();
167 ::base::ToNanoSeconds();
168 ToNanoSeconds();
169 }
170 namespace foo {
171 namespace base {
172 void ToNanoSeconds();
173 void f() {
174 base::ToNanoSeconds();
175 }
176 }
177 void f() {
178 ::base::ToNanoSeconds();
179 }
180 })";
181 std::string Expected = R"(
182 void f() {
183 base::ToInt64NanoSeconds();
184 ::base::ToInt64NanoSeconds();
185 }
186 void g() {
187 using base::ToInt64NanoSeconds;
188 base::ToInt64NanoSeconds();
189 ::base::ToInt64NanoSeconds();
190 base::ToInt64NanoSeconds();
191 }
192 namespace foo {
193 namespace base {
194 void ToNanoSeconds();
195 void f() {
196 base::ToNanoSeconds();
197 }
198 }
199 void f() {
200 ::base::ToInt64NanoSeconds();
201 }
202 })";
203 std::string After = runClangRenameOnCode(Before, "base::ToNanoSeconds",
204 "base::ToInt64NanoSeconds");
205 CompareSnippets(Expected, After);
206}
207
208TEST_F(RenameFunctionTest, RenameFunctionDecls) {
209 std::string Before = R"(
210 namespace na {
211 void X();
212 void X() {}
213 })";
214 std::string Expected = R"(
215 namespace na {
216 void Y();
217 void Y() {}
218 })";
219 std::string After = runClangRenameOnCode(Before, "na::X", "na::Y");
220 CompareSnippets(Expected, After);
221}
222
223TEST_F(RenameFunctionTest, RenameOutOfLineFunctionDecls) {
224 std::string Before = R"(
225 namespace na {
226 void X();
227 }
228 void na::X() {}
229 )";
230 std::string Expected = R"(
231 namespace na {
232 void Y();
233 }
234 void na::Y() {}
235 )";
236 std::string After = runClangRenameOnCode(Before, "na::X", "na::Y");
237 CompareSnippets(Expected, After);
238}
239
240TEST_F(RenameFunctionTest, NewNamespaceWithoutLeadingDotDot) {
241 std::string Before = R"(
242 namespace old_ns {
243 void X();
244 void X() {}
245 }
246 // Assume that the reference is in another file.
247 void f() { old_ns::X(); }
248 namespace old_ns { void g() { X(); } }
249 namespace new_ns { void h() { ::old_ns::X(); } }
250 )";
251 std::string Expected = R"(
252 namespace old_ns {
253 void Y();
254 void Y() {}
255 }
256 // Assume that the reference is in another file.
257 void f() { new_ns::Y(); }
258 namespace old_ns { void g() { new_ns::Y(); } }
259 namespace new_ns { void h() { Y(); } }
260 )";
261 std::string After = runClangRenameOnCode(Before, "::old_ns::X", "new_ns::Y");
262 CompareSnippets(Expected, After);
263}
264
265TEST_F(RenameFunctionTest, NewNamespaceWithLeadingDotDot) {
266 std::string Before = R"(
267 namespace old_ns {
268 void X();
269 void X() {}
270 }
271 // Assume that the reference is in another file.
272 void f() { old_ns::X(); }
273 namespace old_ns { void g() { X(); } }
274 namespace new_ns { void h() { ::old_ns::X(); } }
275 )";
276 std::string Expected = R"(
277 namespace old_ns {
278 void Y();
279 void Y() {}
280 }
281 // Assume that the reference is in another file.
282 void f() { ::new_ns::Y(); }
283 namespace old_ns { void g() { ::new_ns::Y(); } }
284 namespace new_ns { void h() { Y(); } }
285 )";
286 std::string After =
287 runClangRenameOnCode(Before, "::old_ns::X", "::new_ns::Y");
288 CompareSnippets(Expected, After);
289}
290
291TEST_F(RenameFunctionTest, DontRenameSymbolsDefinedInAnonymousNamespace) {
292 std::string Before = R"(
293 namespace old_ns {
294 class X {};
295 namespace {
296 void X();
297 void X() {}
298 void f() { X(); }
299 }
300 }
301 )";
302 std::string Expected = R"(
303 namespace old_ns {
304 class Y {};
305 namespace {
306 void X();
307 void X() {}
308 void f() { X(); }
309 }
310 }
311 )";
312 std::string After =
313 runClangRenameOnCode(Before, "::old_ns::X", "::old_ns::Y");
314 CompareSnippets(Expected, After);
315}
316
317TEST_F(RenameFunctionTest, NewNestedNamespace) {
318 std::string Before = R"(
319 namespace old_ns {
320 void X();
321 void X() {}
322 }
323 // Assume that the reference is in another file.
324 namespace old_ns {
325 void f() { X(); }
326 }
327 )";
328 std::string Expected = R"(
329 namespace old_ns {
330 void X();
331 void X() {}
332 }
333 // Assume that the reference is in another file.
334 namespace old_ns {
335 void f() { older_ns::X(); }
336 }
337 )";
338 std::string After =
339 runClangRenameOnCode(Before, "::old_ns::X", "::old_ns::older_ns::X");
340 CompareSnippets(Expected, After);
341}
342
343TEST_F(RenameFunctionTest, MoveFromGlobalToNamespaceWithoutLeadingDotDot) {
344 std::string Before = R"(
345 void X();
346 void X() {}
347
348 // Assume that the reference is in another file.
349 namespace some_ns {
350 void f() { X(); }
351 }
352 )";
353 std::string Expected = R"(
354 void X();
355 void X() {}
356
357 // Assume that the reference is in another file.
358 namespace some_ns {
359 void f() { ns::X(); }
360 }
361 )";
362 std::string After =
363 runClangRenameOnCode(Before, "::X", "ns::X");
364 CompareSnippets(Expected, After);
365}
366
367TEST_F(RenameFunctionTest, MoveFromGlobalToNamespaceWithLeadingDotDot) {
368 std::string Before = R"(
369 void Y() {}
370
371 // Assume that the reference is in another file.
372 namespace some_ns {
373 void f() { Y(); }
374 }
375 )";
376 std::string Expected = R"(
377 void Y() {}
378
379 // Assume that the reference is in another file.
380 namespace some_ns {
381 void f() { ::ns::Y(); }
382 }
383 )";
384 std::string After =
385 runClangRenameOnCode(Before, "::Y", "::ns::Y");
386 CompareSnippets(Expected, After);
387}
388
389// FIXME: the rename of overloaded operator is not fully supported yet.
390TEST_F(RenameFunctionTest, DISABLED_DoNotRenameOverloadedOperatorCalls) {
391 std::string Before = R"(
392 namespace old_ns {
393 class T { public: int x; };
394 bool operator==(const T& lhs, const T& rhs) {
395 return lhs.x == rhs.x;
396 }
397 } // namespace old_ns
398
399 // Assume that the reference is in another file.
400 bool f() {
401 auto eq = old_ns::operator==;
402 old_ns::T t1, t2;
403 old_ns::operator==(t1, t2);
404 return t1 == t2;
405 }
406 )";
407 std::string Expected = R"(
408 namespace old_ns {
409 class T { public: int x; };
410 bool operator==(const T& lhs, const T& rhs) {
411 return lhs.x == rhs.x;
412 }
413 } // namespace old_ns
414
415 // Assume that the reference is in another file.
416 bool f() {
417 auto eq = new_ns::operator==;
418 old_ns::T t1, t2;
419 new_ns::operator==(t1, t2);
420 return t1 == t2;
421 }
422 )";
423 std::string After =
424 runClangRenameOnCode(Before, "old_ns::operator==", "new_ns::operator==");
425 CompareSnippets(Expected, After);
426}
427
428TEST_F(RenameFunctionTest, FunctionRefAsTemplate) {
429 std::string Before = R"(
430 void X();
431
432 // Assume that the reference is in another file.
433 namespace some_ns {
434 template <void (*Func)(void)>
435 class TIterator {};
436
437 template <void (*Func)(void)>
438 class T {
439 public:
440 typedef TIterator<Func> IterType;
441 using TI = TIterator<Func>;
442 void g() {
443 Func();
444 auto func = Func;
445 TIterator<Func> iter;
446 }
447 };
448
449
450 void f() { T<X> tx; tx.g(); }
451 } // namespace some_ns
452 )";
453 std::string Expected = R"(
454 void X();
455
456 // Assume that the reference is in another file.
457 namespace some_ns {
458 template <void (*Func)(void)>
459 class TIterator {};
460
461 template <void (*Func)(void)>
462 class T {
463 public:
464 typedef TIterator<Func> IterType;
465 using TI = TIterator<Func>;
466 void g() {
467 Func();
468 auto func = Func;
469 TIterator<Func> iter;
470 }
471 };
472
473
474 void f() { T<ns::X> tx; tx.g(); }
475 } // namespace some_ns
476 )";
477 std::string After = runClangRenameOnCode(Before, "::X", "ns::X");
478 CompareSnippets(Expected, After);
479}
480
481TEST_F(RenameFunctionTest, RenameFunctionInUsingDecl) {
482 std::string Before = R"(
483 using base::ToNanoSeconds;
484 namespace old_ns {
485 using base::ToNanoSeconds;
486 void f() {
487 using base::ToNanoSeconds;
488 }
489 }
490 )";
491 std::string Expected = R"(
492 using base::ToInt64NanoSeconds;
493 namespace old_ns {
494 using base::ToInt64NanoSeconds;
495 void f() {
496 using base::ToInt64NanoSeconds;
497 }
498 }
499 )";
500 std::string After = runClangRenameOnCode(Before, "base::ToNanoSeconds",
501 "base::ToInt64NanoSeconds");
502 CompareSnippets(Expected, After);
503}
504
505// FIXME: Fix the complex the case where the symbol being renamed is located in
506// `std::function<decltype<renamed_symbol>>`.
507TEST_F(ClangRenameTest, DISABLED_ReferencesInLambdaFunctionParameters) {
508 std::string Before = R"(
509 template <class T>
510 class function;
511 template <class R, class... ArgTypes>
512 class function<R(ArgTypes...)> {
513 public:
514 template <typename Functor>
515 function(Functor f) {}
516
517 function() {}
518
519 R operator()(ArgTypes...) const {}
520 };
521
522 namespace ns {
523 void Old() {}
524 void f() {
525 function<decltype(Old)> func;
526 }
527 } // namespace ns)";
528 std::string Expected = R"(
529 template <class T>
530 class function;
531 template <class R, class... ArgTypes>
532 class function<R(ArgTypes...)> {
533 public:
534 template <typename Functor>
535 function(Functor f) {}
536
537 function() {}
538
539 R operator()(ArgTypes...) const {}
540 };
541
542 namespace ns {
543 void New() {}
544 void f() {
545 function<decltype(::new_ns::New)> func;
546 }
547 } // namespace ns)";
548 std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
549 CompareSnippets(Expected, After);
550}
551
552} // anonymous namespace
553} // namespace test
554} // namespace clang_rename
555} // namesdpace clang