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