1 //===-- 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 
12 namespace clang {
13 namespace clang_rename {
14 namespace test {
15 namespace {
16 
17 class RenameFunctionTest : public ClangRenameTest {
18 public:
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 
40 TEST_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 
56 TEST_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 
79 TEST_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 
92 TEST_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 
113 TEST_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 
122 TEST_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 
131 TEST_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 
146 TEST_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 
158 TEST_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 
208 TEST_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 
223 TEST_F(RenameFunctionTest, RenameTemplateFunctions) {
224   std::string Before = R"(
225       namespace na {
226       template<typename T> T X();
227       }
228       namespace na { void f() { X<int>(); } }
229       namespace nb { void g() { na::X          <int>(); } }
230       )";
231   std::string Expected = R"(
232       namespace na {
233       template<typename T> T Y();
234       }
235       namespace na { void f() { nb::Y<int>(); } }
236       namespace nb { void g() { Y<int>(); } }
237       )";
238   std::string After = runClangRenameOnCode(Before, "na::X", "nb::Y");
239   CompareSnippets(Expected, After);
240 }
241 
242 TEST_F(RenameFunctionTest, RenameOutOfLineFunctionDecls) {
243   std::string Before = R"(
244       namespace na {
245         void X();
246       }
247       void na::X() {}
248       )";
249   std::string Expected = R"(
250       namespace na {
251         void Y();
252       }
253       void na::Y() {}
254       )";
255   std::string After = runClangRenameOnCode(Before, "na::X", "na::Y");
256   CompareSnippets(Expected, After);
257 }
258 
259 TEST_F(RenameFunctionTest, NewNamespaceWithoutLeadingDotDot) {
260   std::string Before = R"(
261       namespace old_ns {
262         void X();
263         void X() {}
264       }
265       // Assume that the reference is in another file.
266       void f() { old_ns::X(); }
267       namespace old_ns { void g() { X(); } }
268       namespace new_ns { void h() { ::old_ns::X(); } }
269       )";
270   std::string Expected = R"(
271       namespace old_ns {
272         void Y();
273         void Y() {}
274       }
275       // Assume that the reference is in another file.
276       void f() { new_ns::Y(); }
277       namespace old_ns { void g() { new_ns::Y(); } }
278       namespace new_ns { void h() { Y(); } }
279       )";
280   std::string After = runClangRenameOnCode(Before, "::old_ns::X", "new_ns::Y");
281   CompareSnippets(Expected, After);
282 }
283 
284 TEST_F(RenameFunctionTest, NewNamespaceWithLeadingDotDot) {
285   std::string Before = R"(
286       namespace old_ns {
287         void X();
288         void X() {}
289       }
290       // Assume that the reference is in another file.
291       void f() { old_ns::X(); }
292       namespace old_ns { void g() { X(); } }
293       namespace new_ns { void h() { ::old_ns::X(); } }
294       )";
295   std::string Expected = R"(
296       namespace old_ns {
297         void Y();
298         void Y() {}
299       }
300       // Assume that the reference is in another file.
301       void f() { ::new_ns::Y(); }
302       namespace old_ns { void g() { ::new_ns::Y(); } }
303       namespace new_ns { void h() { Y(); } }
304       )";
305   std::string After =
306       runClangRenameOnCode(Before, "::old_ns::X", "::new_ns::Y");
307   CompareSnippets(Expected, After);
308 }
309 
310 TEST_F(RenameFunctionTest, DontRenameSymbolsDefinedInAnonymousNamespace) {
311   std::string Before = R"(
312       namespace old_ns {
313       class X {};
314       namespace {
315         void X();
316         void X() {}
317         void f() { X(); }
318       }
319       }
320       )";
321   std::string Expected = R"(
322       namespace old_ns {
323       class Y {};
324       namespace {
325         void X();
326         void X() {}
327         void f() { X(); }
328       }
329       }
330       )";
331   std::string After =
332       runClangRenameOnCode(Before, "::old_ns::X", "::old_ns::Y");
333   CompareSnippets(Expected, After);
334 }
335 
336 TEST_F(RenameFunctionTest, NewNestedNamespace) {
337   std::string Before = R"(
338       namespace old_ns {
339         void X();
340         void X() {}
341       }
342       // Assume that the reference is in another file.
343       namespace old_ns {
344       void f() { X(); }
345       }
346       )";
347   std::string Expected = R"(
348       namespace old_ns {
349         void X();
350         void X() {}
351       }
352       // Assume that the reference is in another file.
353       namespace old_ns {
354       void f() { older_ns::X(); }
355       }
356       )";
357   std::string After =
358       runClangRenameOnCode(Before, "::old_ns::X", "::old_ns::older_ns::X");
359   CompareSnippets(Expected, After);
360 }
361 
362 TEST_F(RenameFunctionTest, MoveFromGlobalToNamespaceWithoutLeadingDotDot) {
363   std::string Before = R"(
364       void X();
365       void X() {}
366 
367       // Assume that the reference is in another file.
368       namespace some_ns {
369       void f() { X(); }
370       }
371       )";
372   std::string Expected = R"(
373       void X();
374       void X() {}
375 
376       // Assume that the reference is in another file.
377       namespace some_ns {
378       void f() { ns::X(); }
379       }
380       )";
381   std::string After =
382       runClangRenameOnCode(Before, "::X", "ns::X");
383   CompareSnippets(Expected, After);
384 }
385 
386 TEST_F(RenameFunctionTest, MoveFromGlobalToNamespaceWithLeadingDotDot) {
387   std::string Before = R"(
388       void Y() {}
389 
390       // Assume that the reference is in another file.
391       namespace some_ns {
392       void f() { Y(); }
393       }
394       )";
395   std::string Expected = R"(
396       void Y() {}
397 
398       // Assume that the reference is in another file.
399       namespace some_ns {
400       void f() { ::ns::Y(); }
401       }
402       )";
403   std::string After =
404       runClangRenameOnCode(Before, "::Y", "::ns::Y");
405   CompareSnippets(Expected, After);
406 }
407 
408 // FIXME: the rename of overloaded operator is not fully supported yet.
409 TEST_F(RenameFunctionTest, DISABLED_DoNotRenameOverloadedOperatorCalls) {
410   std::string Before = R"(
411       namespace old_ns {
412       class T { public: int x; };
413       bool operator==(const T& lhs, const T& rhs) {
414         return lhs.x == rhs.x;
415       }
416       }  // namespace old_ns
417 
418       // Assume that the reference is in another file.
419       bool f() {
420         auto eq = old_ns::operator==;
421         old_ns::T t1, t2;
422         old_ns::operator==(t1, t2);
423         return t1 == t2;
424       }
425       )";
426   std::string Expected = R"(
427       namespace old_ns {
428       class T { public: int x; };
429       bool operator==(const T& lhs, const T& rhs) {
430         return lhs.x == rhs.x;
431       }
432       }  // namespace old_ns
433 
434       // Assume that the reference is in another file.
435       bool f() {
436         auto eq = new_ns::operator==;
437         old_ns::T t1, t2;
438         new_ns::operator==(t1, t2);
439         return t1 == t2;
440       }
441       )";
442   std::string After =
443       runClangRenameOnCode(Before, "old_ns::operator==", "new_ns::operator==");
444   CompareSnippets(Expected, After);
445 }
446 
447 TEST_F(RenameFunctionTest, FunctionRefAsTemplate) {
448   std::string Before = R"(
449       void X();
450 
451       // Assume that the reference is in another file.
452       namespace some_ns {
453       template <void (*Func)(void)>
454       class TIterator {};
455 
456       template <void (*Func)(void)>
457       class T {
458       public:
459         typedef TIterator<Func> IterType;
460         using TI = TIterator<Func>;
461         void g() {
462           Func();
463           auto func = Func;
464           TIterator<Func> iter;
465         }
466       };
467 
468 
469       void f() { T<X> tx; tx.g(); }
470       }  // namespace some_ns
471       )";
472   std::string Expected = R"(
473       void X();
474 
475       // Assume that the reference is in another file.
476       namespace some_ns {
477       template <void (*Func)(void)>
478       class TIterator {};
479 
480       template <void (*Func)(void)>
481       class T {
482       public:
483         typedef TIterator<Func> IterType;
484         using TI = TIterator<Func>;
485         void g() {
486           Func();
487           auto func = Func;
488           TIterator<Func> iter;
489         }
490       };
491 
492 
493       void f() { T<ns::X> tx; tx.g(); }
494       }  // namespace some_ns
495       )";
496   std::string After = runClangRenameOnCode(Before, "::X", "ns::X");
497   CompareSnippets(Expected, After);
498 }
499 
500 TEST_F(RenameFunctionTest, RenameFunctionInUsingDecl) {
501   std::string Before = R"(
502       using base::ToNanoSeconds;
503       namespace old_ns {
504       using base::ToNanoSeconds;
505       void f() {
506         using base::ToNanoSeconds;
507       }
508       }
509       )";
510   std::string Expected = R"(
511       using base::ToInt64NanoSeconds;
512       namespace old_ns {
513       using base::ToInt64NanoSeconds;
514       void f() {
515         using base::ToInt64NanoSeconds;
516       }
517       }
518       )";
519   std::string After = runClangRenameOnCode(Before, "base::ToNanoSeconds",
520                                            "base::ToInt64NanoSeconds");
521   CompareSnippets(Expected, After);
522 }
523 
524 // FIXME: Fix the complex the case where the symbol being renamed is located in
525 // `std::function<decltype<renamed_symbol>>`.
526 TEST_F(ClangRenameTest, DISABLED_ReferencesInLambdaFunctionParameters) {
527   std::string Before = R"(
528       template <class T>
529       class function;
530       template <class R, class... ArgTypes>
531       class function<R(ArgTypes...)> {
532       public:
533         template <typename Functor>
534         function(Functor f) {}
535 
536         function() {}
537 
538         R operator()(ArgTypes...) const {}
539       };
540 
541       namespace ns {
542       void Old() {}
543       void f() {
544         function<decltype(Old)> func;
545       }
546       }  // namespace ns)";
547   std::string Expected = R"(
548       template <class T>
549       class function;
550       template <class R, class... ArgTypes>
551       class function<R(ArgTypes...)> {
552       public:
553         template <typename Functor>
554         function(Functor f) {}
555 
556         function() {}
557 
558         R operator()(ArgTypes...) const {}
559       };
560 
561       namespace ns {
562       void New() {}
563       void f() {
564         function<decltype(::new_ns::New)> func;
565       }
566       }  // namespace ns)";
567   std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
568   CompareSnippets(Expected, After);
569 }
570 
571 } // anonymous namespace
572 } // namespace test
573 } // namespace clang_rename
574 } // namesdpace clang
575