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, 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 240 TEST_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 265 TEST_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 291 TEST_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 317 TEST_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 343 TEST_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 367 TEST_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. 390 TEST_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 428 TEST_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 481 TEST_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>>`. 507 TEST_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 556