Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / unittests / Rename / RenameFunctionTest.cpp
blob1c9b112232ebc8ee88acdb4ffa7e4c704a989ba6
1 //===-- RenameFunctionTest.cpp - unit tests for renaming functions --------===//
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 //===----------------------------------------------------------------------===//
9 #include "ClangRenameTest.h"
11 namespace clang {
12 namespace clang_rename {
13 namespace test {
14 namespace {
16 class RenameFunctionTest : public ClangRenameTest {
17 public:
18 RenameFunctionTest() {
19 AppendToHeader(R"(
20 struct A {
21 static bool Foo();
22 static bool Spam();
24 struct B {
25 static void Same();
26 static bool Foo();
27 static int Eric(int x);
29 void Same(int x);
30 int Eric(int x);
31 namespace base {
32 void Same();
33 void ToNanoSeconds();
34 void ToInt64NanoSeconds();
35 })");
39 TEST_F(RenameFunctionTest, RefactorsAFoo) {
40 std::string Before = R"(
41 void f() {
42 A::Foo();
43 ::A::Foo();
44 })";
45 std::string Expected = R"(
46 void f() {
47 A::Bar();
48 ::A::Bar();
49 })";
51 std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar");
52 CompareSnippets(Expected, After);
55 TEST_F(RenameFunctionTest, RefactorsNonCallingAFoo) {
56 std::string Before = R"(
57 bool g(bool (*func)()) {
58 return func();
60 void f() {
61 auto *ref1 = A::Foo;
62 auto *ref2 = ::A::Foo;
63 g(A::Foo);
64 })";
65 std::string Expected = R"(
66 bool g(bool (*func)()) {
67 return func();
69 void f() {
70 auto *ref1 = A::Bar;
71 auto *ref2 = ::A::Bar;
72 g(A::Bar);
73 })";
74 std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar");
75 CompareSnippets(Expected, After);
78 TEST_F(RenameFunctionTest, RefactorsEric) {
79 std::string Before = R"(
80 void f() {
81 if (Eric(3)==4) ::Eric(2);
82 })";
83 std::string Expected = R"(
84 void f() {
85 if (Larry(3)==4) ::Larry(2);
86 })";
87 std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
88 CompareSnippets(Expected, After);
91 TEST_F(RenameFunctionTest, RefactorsNonCallingEric) {
92 std::string Before = R"(
93 int g(int (*func)(int)) {
94 return func(1);
96 void f() {
97 auto *ref = ::Eric;
98 g(Eric);
99 })";
100 std::string Expected = R"(
101 int g(int (*func)(int)) {
102 return func(1);
104 void f() {
105 auto *ref = ::Larry;
106 g(Larry);
107 })";
108 std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
109 CompareSnippets(Expected, After);
112 TEST_F(RenameFunctionTest, DoesNotRefactorBFoo) {
113 std::string Before = R"(
114 void f() {
115 B::Foo();
116 })";
117 std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar");
118 CompareSnippets(Before, After);
121 TEST_F(RenameFunctionTest, DoesNotRefactorBEric) {
122 std::string Before = R"(
123 void f() {
124 B::Eric(2);
125 })";
126 std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
127 CompareSnippets(Before, After);
130 TEST_F(RenameFunctionTest, DoesNotRefactorCEric) {
131 std::string Before = R"(
132 namespace C { int Eric(int x); }
133 void f() {
134 if (C::Eric(3)==4) ::C::Eric(2);
135 })";
136 std::string Expected = R"(
137 namespace C { int Eric(int x); }
138 void f() {
139 if (C::Eric(3)==4) ::C::Eric(2);
140 })";
141 std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
142 CompareSnippets(Expected, After);
145 TEST_F(RenameFunctionTest, DoesNotRefactorEricInNamespaceC) {
146 std::string Before = R"(
147 namespace C {
148 int Eric(int x);
149 void f() {
150 if (Eric(3)==4) Eric(2);
152 } // namespace C)";
153 std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
154 CompareSnippets(Before, After);
157 TEST_F(RenameFunctionTest, NamespaceQualified) {
158 std::string Before = R"(
159 void f() {
160 base::ToNanoSeconds();
161 ::base::ToNanoSeconds();
163 void g() {
164 using base::ToNanoSeconds;
165 base::ToNanoSeconds();
166 ::base::ToNanoSeconds();
167 ToNanoSeconds();
169 namespace foo {
170 namespace base {
171 void ToNanoSeconds();
172 void f() {
173 base::ToNanoSeconds();
176 void f() {
177 ::base::ToNanoSeconds();
179 })";
180 std::string Expected = R"(
181 void f() {
182 base::ToInt64NanoSeconds();
183 ::base::ToInt64NanoSeconds();
185 void g() {
186 using base::ToInt64NanoSeconds;
187 base::ToInt64NanoSeconds();
188 ::base::ToInt64NanoSeconds();
189 base::ToInt64NanoSeconds();
191 namespace foo {
192 namespace base {
193 void ToNanoSeconds();
194 void f() {
195 base::ToNanoSeconds();
198 void f() {
199 ::base::ToInt64NanoSeconds();
201 })";
202 std::string After = runClangRenameOnCode(Before, "base::ToNanoSeconds",
203 "base::ToInt64NanoSeconds");
204 CompareSnippets(Expected, After);
207 TEST_F(RenameFunctionTest, RenameFunctionDecls) {
208 std::string Before = R"(
209 namespace na {
210 void X();
211 void X() {}
212 })";
213 std::string Expected = R"(
214 namespace na {
215 void Y();
216 void Y() {}
217 })";
218 std::string After = runClangRenameOnCode(Before, "na::X", "na::Y");
219 CompareSnippets(Expected, After);
222 TEST_F(RenameFunctionTest, RenameTemplateFunctions) {
223 std::string Before = R"(
224 namespace na {
225 template<typename T> T X();
227 namespace na { void f() { X<int>(); } }
228 namespace nb { void g() { na::X <int>(); } }
230 std::string Expected = R"(
231 namespace na {
232 template<typename T> T Y();
234 namespace na { void f() { nb::Y<int>(); } }
235 namespace nb { void g() { Y<int>(); } }
237 std::string After = runClangRenameOnCode(Before, "na::X", "nb::Y");
238 CompareSnippets(Expected, After);
241 TEST_F(RenameFunctionTest, RenameOutOfLineFunctionDecls) {
242 std::string Before = R"(
243 namespace na {
244 void X();
246 void na::X() {}
248 std::string Expected = R"(
249 namespace na {
250 void Y();
252 void na::Y() {}
254 std::string After = runClangRenameOnCode(Before, "na::X", "na::Y");
255 CompareSnippets(Expected, After);
258 TEST_F(RenameFunctionTest, NewNamespaceWithoutLeadingDotDot) {
259 std::string Before = R"(
260 namespace old_ns {
261 void X();
262 void X() {}
264 // Assume that the reference is in another file.
265 void f() { old_ns::X(); }
266 namespace old_ns { void g() { X(); } }
267 namespace new_ns { void h() { ::old_ns::X(); } }
269 std::string Expected = R"(
270 namespace old_ns {
271 void Y();
272 void Y() {}
274 // Assume that the reference is in another file.
275 void f() { new_ns::Y(); }
276 namespace old_ns { void g() { new_ns::Y(); } }
277 namespace new_ns { void h() { Y(); } }
279 std::string After = runClangRenameOnCode(Before, "::old_ns::X", "new_ns::Y");
280 CompareSnippets(Expected, After);
283 TEST_F(RenameFunctionTest, NewNamespaceWithLeadingDotDot) {
284 std::string Before = R"(
285 namespace old_ns {
286 void X();
287 void X() {}
289 // Assume that the reference is in another file.
290 void f() { old_ns::X(); }
291 namespace old_ns { void g() { X(); } }
292 namespace new_ns { void h() { ::old_ns::X(); } }
294 std::string Expected = R"(
295 namespace old_ns {
296 void Y();
297 void Y() {}
299 // Assume that the reference is in another file.
300 void f() { ::new_ns::Y(); }
301 namespace old_ns { void g() { ::new_ns::Y(); } }
302 namespace new_ns { void h() { Y(); } }
304 std::string After =
305 runClangRenameOnCode(Before, "::old_ns::X", "::new_ns::Y");
306 CompareSnippets(Expected, After);
309 TEST_F(RenameFunctionTest, DontRenameSymbolsDefinedInAnonymousNamespace) {
310 std::string Before = R"(
311 namespace old_ns {
312 class X {};
313 namespace {
314 void X();
315 void X() {}
316 void f() { X(); }
320 std::string Expected = R"(
321 namespace old_ns {
322 class Y {};
323 namespace {
324 void X();
325 void X() {}
326 void f() { X(); }
330 std::string After =
331 runClangRenameOnCode(Before, "::old_ns::X", "::old_ns::Y");
332 CompareSnippets(Expected, After);
335 TEST_F(RenameFunctionTest, NewNestedNamespace) {
336 std::string Before = R"(
337 namespace old_ns {
338 void X();
339 void X() {}
341 // Assume that the reference is in another file.
342 namespace old_ns {
343 void f() { X(); }
346 std::string Expected = R"(
347 namespace old_ns {
348 void X();
349 void X() {}
351 // Assume that the reference is in another file.
352 namespace old_ns {
353 void f() { older_ns::X(); }
356 std::string After =
357 runClangRenameOnCode(Before, "::old_ns::X", "::old_ns::older_ns::X");
358 CompareSnippets(Expected, After);
361 TEST_F(RenameFunctionTest, MoveFromGlobalToNamespaceWithoutLeadingDotDot) {
362 std::string Before = R"(
363 void X();
364 void X() {}
366 // Assume that the reference is in another file.
367 namespace some_ns {
368 void f() { X(); }
371 std::string Expected = R"(
372 void X();
373 void X() {}
375 // Assume that the reference is in another file.
376 namespace some_ns {
377 void f() { ns::X(); }
380 std::string After =
381 runClangRenameOnCode(Before, "::X", "ns::X");
382 CompareSnippets(Expected, After);
385 TEST_F(RenameFunctionTest, MoveFromGlobalToNamespaceWithLeadingDotDot) {
386 std::string Before = R"(
387 void Y() {}
389 // Assume that the reference is in another file.
390 namespace some_ns {
391 void f() { Y(); }
394 std::string Expected = R"(
395 void Y() {}
397 // Assume that the reference is in another file.
398 namespace some_ns {
399 void f() { ::ns::Y(); }
402 std::string After =
403 runClangRenameOnCode(Before, "::Y", "::ns::Y");
404 CompareSnippets(Expected, After);
407 // FIXME: the rename of overloaded operator is not fully supported yet.
408 TEST_F(RenameFunctionTest, DISABLED_DoNotRenameOverloadedOperatorCalls) {
409 std::string Before = R"(
410 namespace old_ns {
411 class T { public: int x; };
412 bool operator==(const T& lhs, const T& rhs) {
413 return lhs.x == rhs.x;
415 } // namespace old_ns
417 // Assume that the reference is in another file.
418 bool f() {
419 auto eq = old_ns::operator==;
420 old_ns::T t1, t2;
421 old_ns::operator==(t1, t2);
422 return t1 == t2;
425 std::string Expected = R"(
426 namespace old_ns {
427 class T { public: int x; };
428 bool operator==(const T& lhs, const T& rhs) {
429 return lhs.x == rhs.x;
431 } // namespace old_ns
433 // Assume that the reference is in another file.
434 bool f() {
435 auto eq = new_ns::operator==;
436 old_ns::T t1, t2;
437 new_ns::operator==(t1, t2);
438 return t1 == t2;
441 std::string After =
442 runClangRenameOnCode(Before, "old_ns::operator==", "new_ns::operator==");
443 CompareSnippets(Expected, After);
446 TEST_F(RenameFunctionTest, FunctionRefAsTemplate) {
447 std::string Before = R"(
448 void X();
450 // Assume that the reference is in another file.
451 namespace some_ns {
452 template <void (*Func)(void)>
453 class TIterator {};
455 template <void (*Func)(void)>
456 class T {
457 public:
458 typedef TIterator<Func> IterType;
459 using TI = TIterator<Func>;
460 void g() {
461 Func();
462 auto func = Func;
463 TIterator<Func> iter;
468 void f() { T<X> tx; tx.g(); }
469 } // namespace some_ns
471 std::string Expected = R"(
472 void X();
474 // Assume that the reference is in another file.
475 namespace some_ns {
476 template <void (*Func)(void)>
477 class TIterator {};
479 template <void (*Func)(void)>
480 class T {
481 public:
482 typedef TIterator<Func> IterType;
483 using TI = TIterator<Func>;
484 void g() {
485 Func();
486 auto func = Func;
487 TIterator<Func> iter;
492 void f() { T<ns::X> tx; tx.g(); }
493 } // namespace some_ns
495 std::string After = runClangRenameOnCode(Before, "::X", "ns::X");
496 CompareSnippets(Expected, After);
499 TEST_F(RenameFunctionTest, RenameFunctionInUsingDecl) {
500 std::string Before = R"(
501 using base::ToNanoSeconds;
502 namespace old_ns {
503 using base::ToNanoSeconds;
504 void f() {
505 using base::ToNanoSeconds;
509 std::string Expected = R"(
510 using base::ToInt64NanoSeconds;
511 namespace old_ns {
512 using base::ToInt64NanoSeconds;
513 void f() {
514 using base::ToInt64NanoSeconds;
518 std::string After = runClangRenameOnCode(Before, "base::ToNanoSeconds",
519 "base::ToInt64NanoSeconds");
520 CompareSnippets(Expected, After);
523 // FIXME: Fix the complex the case where the symbol being renamed is located in
524 // `std::function<decltype<renamed_symbol>>`.
525 TEST_F(ClangRenameTest, DISABLED_ReferencesInLambdaFunctionParameters) {
526 std::string Before = R"(
527 template <class T>
528 class function;
529 template <class R, class... ArgTypes>
530 class function<R(ArgTypes...)> {
531 public:
532 template <typename Functor>
533 function(Functor f) {}
535 function() {}
537 R operator()(ArgTypes...) const {}
540 namespace ns {
541 void Old() {}
542 void f() {
543 function<decltype(Old)> func;
545 } // namespace ns)";
546 std::string Expected = R"(
547 template <class T>
548 class function;
549 template <class R, class... ArgTypes>
550 class function<R(ArgTypes...)> {
551 public:
552 template <typename Functor>
553 function(Functor f) {}
555 function() {}
557 R operator()(ArgTypes...) const {}
560 namespace ns {
561 void New() {}
562 void f() {
563 function<decltype(::new_ns::New)> func;
565 } // namespace ns)";
566 std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
567 CompareSnippets(Expected, After);
570 } // anonymous namespace
571 } // namespace test
572 } // namespace clang_rename
573 } // namesdpace clang