1 //===-- RenameTests.cpp -----------------------------------------*- C++ -*-===// 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 //===----------------------------------------------------------------------===// 8 9 #include "Annotations.h" 10 #include "ClangdServer.h" 11 #include "SyncAPI.h" 12 #include "TestFS.h" 13 #include "TestTU.h" 14 #include "index/Ref.h" 15 #include "refactor/Rename.h" 16 #include "support/TestTracer.h" 17 #include "clang/Tooling/Core/Replacement.h" 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/Support/MemoryBuffer.h" 20 #include <algorithm> 21 #include "gmock/gmock.h" 22 #include "gtest/gtest.h" 23 24 namespace clang { 25 namespace clangd { 26 namespace { 27 28 using testing::ElementsAre; 29 using testing::Eq; 30 using testing::IsEmpty; 31 using testing::Pair; 32 using testing::SizeIs; 33 using testing::UnorderedElementsAre; 34 using testing::UnorderedElementsAreArray; 35 36 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> 37 createOverlay(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> Base, 38 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> Overlay) { 39 auto OFS = 40 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(std::move(Base)); 41 OFS->pushOverlay(std::move(Overlay)); 42 return OFS; 43 } 44 45 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> getVFSFromAST(ParsedAST &AST) { 46 return &AST.getSourceManager().getFileManager().getVirtualFileSystem(); 47 } 48 49 // Convert a Range to a Ref. 50 Ref refWithRange(const clangd::Range &Range, const std::string &URI) { 51 Ref Result; 52 Result.Kind = RefKind::Reference | RefKind::Spelled; 53 Result.Location.Start.setLine(Range.start.line); 54 Result.Location.Start.setColumn(Range.start.character); 55 Result.Location.End.setLine(Range.end.line); 56 Result.Location.End.setColumn(Range.end.character); 57 Result.Location.FileURI = URI.c_str(); 58 return Result; 59 } 60 61 // Build a RefSlab from all marked ranges in the annotation. The ranges are 62 // assumed to associate with the given SymbolName. 63 std::unique_ptr<RefSlab> buildRefSlab(const Annotations &Code, 64 llvm::StringRef SymbolName, 65 llvm::StringRef Path) { 66 RefSlab::Builder Builder; 67 TestTU TU; 68 TU.HeaderCode = std::string(Code.code()); 69 auto Symbols = TU.headerSymbols(); 70 const auto &SymbolID = findSymbol(Symbols, SymbolName).ID; 71 std::string PathURI = URI::create(Path).toString(); 72 for (const auto &Range : Code.ranges()) 73 Builder.insert(SymbolID, refWithRange(Range, PathURI)); 74 75 return std::make_unique<RefSlab>(std::move(Builder).build()); 76 } 77 78 std::vector< 79 std::pair</*FilePath*/ std::string, /*CodeAfterRename*/ std::string>> 80 applyEdits(FileEdits FE) { 81 std::vector<std::pair<std::string, std::string>> Results; 82 for (auto &It : FE) 83 Results.emplace_back( 84 It.first().str(), 85 llvm::cantFail(tooling::applyAllReplacements( 86 It.getValue().InitialCode, It.getValue().Replacements))); 87 return Results; 88 } 89 90 // Generates an expected rename result by replacing all ranges in the given 91 // annotation with the NewName. 92 std::string expectedResult(Annotations Test, llvm::StringRef NewName) { 93 std::string Result; 94 unsigned NextChar = 0; 95 llvm::StringRef Code = Test.code(); 96 for (const auto &R : Test.llvm::Annotations::ranges()) { 97 assert(R.Begin <= R.End && NextChar <= R.Begin); 98 Result += Code.substr(NextChar, R.Begin - NextChar); 99 Result += NewName; 100 NextChar = R.End; 101 } 102 Result += Code.substr(NextChar); 103 return Result; 104 } 105 106 std::vector<SymbolRange> symbolRanges(llvm::ArrayRef<Range> Ranges) { 107 std::vector<SymbolRange> Result; 108 for (const auto &R : Ranges) 109 Result.emplace_back(R); 110 return Result; 111 } 112 113 TEST(RenameTest, WithinFileRename) { 114 // For each "^" this test moves cursor to its location and applies renaming 115 // while checking that all identifiers in [[]] ranges are also renamed. 116 llvm::StringRef Tests[] = { 117 // Function. 118 R"cpp( 119 void [[foo^]]() { 120 [[fo^o]](); 121 } 122 )cpp", 123 124 // Type. 125 R"cpp( 126 struct [[foo^]] {}; 127 [[foo]] test() { 128 [[f^oo]] x; 129 return x; 130 } 131 )cpp", 132 133 // Local variable. 134 R"cpp( 135 void bar() { 136 if (auto [[^foo]] = 5) { 137 [[foo]] = 3; 138 } 139 } 140 )cpp", 141 142 // Class, its constructor and destructor. 143 R"cpp( 144 class [[F^oo]] { 145 [[F^oo]](); 146 ~[[F^oo]](); 147 [[F^oo]] *foo(int x); 148 149 [[F^oo]] *Ptr; 150 }; 151 [[F^oo]]::[[Fo^o]]() {} 152 [[F^oo]]::~[[Fo^o]]() {} 153 [[F^oo]] *[[F^oo]]::foo(int x) { return Ptr; } 154 )cpp", 155 156 // Template class, its constructor and destructor. 157 R"cpp( 158 template <typename T> 159 class [[F^oo]] { 160 [[F^oo]](); 161 ~[[F^oo]](); 162 void f([[F^oo]] x); 163 }; 164 165 template<typename T> 166 [[F^oo]]<T>::[[Fo^o]]() {} 167 168 template<typename T> 169 [[F^oo]]<T>::~[[Fo^o]]() {} 170 )cpp", 171 172 // Template class constructor. 173 R"cpp( 174 class [[F^oo]] { 175 template<typename T> 176 [[Fo^o]](); 177 178 template<typename T> 179 [[F^oo]](T t); 180 }; 181 182 template<typename T> 183 [[F^oo]]::[[Fo^o]]() {} 184 )cpp", 185 186 // Class in template argument. 187 R"cpp( 188 class [[F^oo]] {}; 189 template <typename T> void func(); 190 template <typename T> class Baz {}; 191 int main() { 192 func<[[F^oo]]>(); 193 Baz<[[F^oo]]> obj; 194 return 0; 195 } 196 )cpp", 197 198 // Forward class declaration without definition. 199 R"cpp( 200 class [[F^oo]]; 201 [[F^oo]] *f(); 202 )cpp", 203 204 // Member function. 205 R"cpp( 206 struct X { 207 void [[F^oo]]() {} 208 void Baz() { [[F^oo]](); } 209 }; 210 )cpp", 211 212 // Templated method instantiation. 213 R"cpp( 214 template<typename T> 215 class Foo { 216 public: 217 static T [[f^oo]]() {} 218 }; 219 220 void bar() { 221 Foo<int>::[[f^oo]](); 222 } 223 )cpp", 224 R"cpp( 225 template<typename T> 226 class Foo { 227 public: 228 T [[f^oo]]() {} 229 }; 230 231 void bar() { 232 Foo<int>().[[f^oo]](); 233 } 234 )cpp", 235 236 // Template class (partial) specializations. 237 R"cpp( 238 template <typename T> 239 class [[F^oo]] {}; 240 241 template<> 242 class [[F^oo]]<bool> {}; 243 template <typename T> 244 class [[F^oo]]<T*> {}; 245 246 void test() { 247 [[F^oo]]<int> x; 248 [[F^oo]]<bool> y; 249 [[F^oo]]<int*> z; 250 } 251 )cpp", 252 253 // Incomplete class specializations 254 R"cpp( 255 template <typename T> 256 class [[Fo^o]] {}; 257 void func([[F^oo]]<int>); 258 )cpp", 259 260 // Template class instantiations. 261 R"cpp( 262 template <typename T> 263 class [[F^oo]] { 264 public: 265 T foo(T arg, T& ref, T* ptr) { 266 T value; 267 int number = 42; 268 value = (T)number; 269 value = static_cast<T>(number); 270 return value; 271 } 272 static void foo(T value) {} 273 T member; 274 }; 275 276 template <typename T> 277 void func() { 278 [[F^oo]]<T> obj; 279 obj.member = T(); 280 [[Foo]]<T>::foo(); 281 } 282 283 void test() { 284 [[F^oo]]<int> i; 285 i.member = 0; 286 [[F^oo]]<int>::foo(0); 287 288 [[F^oo]]<bool> b; 289 b.member = false; 290 [[F^oo]]<bool>::foo(false); 291 } 292 )cpp", 293 294 // Template class methods. 295 R"cpp( 296 template <typename T> 297 class A { 298 public: 299 void [[f^oo]]() {} 300 }; 301 302 void func() { 303 A<int>().[[f^oo]](); 304 A<double>().[[f^oo]](); 305 A<float>().[[f^oo]](); 306 } 307 )cpp", 308 309 // Templated class specialization. 310 R"cpp( 311 template<typename T, typename U=bool> 312 class [[Foo^]]; 313 314 template<typename T, typename U> 315 class [[Foo^]] {}; 316 317 template<typename T=int, typename U> 318 class [[Foo^]]; 319 )cpp", 320 R"cpp( 321 template<typename T=float, typename U=int> 322 class [[Foo^]]; 323 324 template<typename T, typename U> 325 class [[Foo^]] {}; 326 )cpp", 327 328 // Function template specialization. 329 R"cpp( 330 template<typename T=int, typename U=bool> 331 U [[foo^]](); 332 333 template<typename T, typename U> 334 U [[foo^]]() {}; 335 )cpp", 336 R"cpp( 337 template<typename T, typename U> 338 U [[foo^]]() {}; 339 340 template<typename T=int, typename U=bool> 341 U [[foo^]](); 342 )cpp", 343 R"cpp( 344 template<typename T=int, typename U=bool> 345 U [[foo^]](); 346 347 template<typename T, typename U> 348 U [[foo^]](); 349 )cpp", 350 R"cpp( 351 template <typename T> 352 void [[f^oo]](T t); 353 354 template <> 355 void [[f^oo]](int a); 356 357 void test() { 358 [[f^oo]]<double>(1); 359 } 360 )cpp", 361 362 // Variable template. 363 R"cpp( 364 template <typename T, int U> 365 bool [[F^oo]] = true; 366 367 // Explicit template specialization 368 template <> 369 bool [[F^oo]]<int, 0> = false; 370 371 // Partial template specialization 372 template <typename T> 373 bool [[F^oo]]<T, 1> = false; 374 375 void foo() { 376 // Ref to the explicit template specialization 377 [[F^oo]]<int, 0>; 378 // Ref to the primary template. 379 [[F^oo]]<double, 2>; 380 } 381 )cpp", 382 383 // Complicated class type. 384 R"cpp( 385 // Forward declaration. 386 class [[Fo^o]]; 387 class Baz { 388 virtual int getValue() const = 0; 389 }; 390 391 class [[F^oo]] : public Baz { 392 public: 393 [[F^oo]](int value = 0) : x(value) {} 394 395 [[F^oo]] &operator++(int); 396 397 bool operator<([[Foo]] const &rhs); 398 int getValue() const; 399 private: 400 int x; 401 }; 402 403 void func() { 404 [[F^oo]] *Pointer = 0; 405 [[F^oo]] Variable = [[Foo]](10); 406 for ([[F^oo]] it; it < Variable; it++); 407 const [[F^oo]] *C = new [[Foo]](); 408 const_cast<[[F^oo]] *>(C)->getValue(); 409 [[F^oo]] foo; 410 const Baz &BazReference = foo; 411 const Baz *BazPointer = &foo; 412 reinterpret_cast<const [[^Foo]] *>(BazPointer)->getValue(); 413 static_cast<const [[^Foo]] &>(BazReference).getValue(); 414 static_cast<const [[^Foo]] *>(BazPointer)->getValue(); 415 } 416 )cpp", 417 418 // Static class member. 419 R"cpp( 420 struct Foo { 421 static Foo *[[Static^Member]]; 422 }; 423 424 Foo* Foo::[[Static^Member]] = nullptr; 425 426 void foo() { 427 Foo* Pointer = Foo::[[Static^Member]]; 428 } 429 )cpp", 430 431 // Reference in lambda parameters. 432 R"cpp( 433 template <class T> 434 class function; 435 template <class R, class... ArgTypes> 436 class function<R(ArgTypes...)> { 437 public: 438 template <typename Functor> 439 function(Functor f) {} 440 441 function() {} 442 443 R operator()(ArgTypes...) const {} 444 }; 445 446 namespace ns { 447 class [[Old]] {}; 448 void f() { 449 function<void([[Old]])> func; 450 } 451 } // namespace ns 452 )cpp", 453 454 // Destructor explicit call. 455 R"cpp( 456 class [[F^oo]] { 457 public: 458 ~[[^Foo]](); 459 }; 460 461 [[Foo^]]::~[[^Foo]]() {} 462 463 int main() { 464 [[Fo^o]] f; 465 f.~/*something*/[[^Foo]](); 466 f.~[[^Foo]](); 467 } 468 )cpp", 469 470 // Derived destructor explicit call. 471 R"cpp( 472 class [[Bas^e]] {}; 473 class Derived : public [[Bas^e]] {}; 474 475 int main() { 476 [[Bas^e]] *foo = new Derived(); 477 foo->[[^Base]]::~[[^Base]](); 478 } 479 )cpp", 480 481 // CXXConstructor initializer list. 482 R"cpp( 483 class Baz {}; 484 class Qux { 485 Baz [[F^oo]]; 486 public: 487 Qux(); 488 }; 489 Qux::Qux() : [[F^oo]]() {} 490 )cpp", 491 492 // DeclRefExpr. 493 R"cpp( 494 class C { 495 public: 496 static int [[F^oo]]; 497 }; 498 499 int foo(int x); 500 #define MACRO(a) foo(a) 501 502 void func() { 503 C::[[F^oo]] = 1; 504 MACRO(C::[[Foo]]); 505 int y = C::[[F^oo]]; 506 } 507 )cpp", 508 509 // Macros. 510 R"cpp( 511 // no rename inside macro body. 512 #define M1 foo 513 #define M2(x) x 514 int [[fo^o]](); 515 void boo(int); 516 517 void qoo() { 518 [[f^oo]](); 519 boo([[f^oo]]()); 520 M1(); 521 boo(M1()); 522 M2([[f^oo]]()); 523 M2(M1()); // foo is inside the nested macro body. 524 } 525 )cpp", 526 527 // MemberExpr in macros 528 R"cpp( 529 class Baz { 530 public: 531 int [[F^oo]]; 532 }; 533 int qux(int x); 534 #define MACRO(a) qux(a) 535 536 int main() { 537 Baz baz; 538 baz.[[F^oo]] = 1; 539 MACRO(baz.[[F^oo]]); 540 int y = baz.[[F^oo]]; 541 } 542 )cpp", 543 544 // Fields in classes & partial and full specialiations. 545 R"cpp( 546 template<typename T> 547 struct Foo { 548 T [[Vari^able]] = 42; 549 }; 550 551 void foo() { 552 Foo<int> f; 553 f.[[Varia^ble]] = 9000; 554 } 555 )cpp", 556 R"cpp( 557 template<typename T, typename U> 558 struct Foo { 559 T Variable[42]; 560 U Another; 561 562 void bar() {} 563 }; 564 565 template<typename T> 566 struct Foo<T, bool> { 567 T [[Var^iable]]; 568 void bar() { ++[[Var^iable]]; } 569 }; 570 571 void foo() { 572 Foo<unsigned, bool> f; 573 f.[[Var^iable]] = 9000; 574 } 575 )cpp", 576 R"cpp( 577 template<typename T, typename U> 578 struct Foo { 579 T Variable[42]; 580 U Another; 581 582 void bar() {} 583 }; 584 585 template<typename T> 586 struct Foo<T, bool> { 587 T Variable; 588 void bar() { ++Variable; } 589 }; 590 591 template<> 592 struct Foo<unsigned, bool> { 593 unsigned [[Var^iable]]; 594 void bar() { ++[[Var^iable]]; } 595 }; 596 597 void foo() { 598 Foo<unsigned, bool> f; 599 f.[[Var^iable]] = 9000; 600 } 601 )cpp", 602 // Static fields. 603 R"cpp( 604 struct Foo { 605 static int [[Var^iable]]; 606 }; 607 608 int Foo::[[Var^iable]] = 42; 609 610 void foo() { 611 int LocalInt = Foo::[[Var^iable]]; 612 } 613 )cpp", 614 R"cpp( 615 template<typename T> 616 struct Foo { 617 static T [[Var^iable]]; 618 }; 619 620 template <> 621 int Foo<int>::[[Var^iable]] = 42; 622 623 template <> 624 bool Foo<bool>::[[Var^iable]] = true; 625 626 void foo() { 627 int LocalInt = Foo<int>::[[Var^iable]]; 628 bool LocalBool = Foo<bool>::[[Var^iable]]; 629 } 630 )cpp", 631 632 // Template parameters. 633 R"cpp( 634 template <typename [[^T]]> 635 class Foo { 636 [[T^]] foo([[T^]] arg, [[T^]]& ref, [[^T]]* ptr) { 637 [[T]] value; 638 int number = 42; 639 value = ([[T^]])number; 640 value = static_cast<[[^T]]>(number); 641 return value; 642 } 643 static void foo([[T^]] value) {} 644 [[T^]] member; 645 }; 646 )cpp", 647 648 // Typedef. 649 R"cpp( 650 namespace ns { 651 class basic_string {}; 652 typedef basic_string [[s^tring]]; 653 } // namespace ns 654 655 ns::[[s^tring]] foo(); 656 )cpp", 657 658 // Variable. 659 R"cpp( 660 namespace A { 661 int [[F^oo]]; 662 } 663 int Foo; 664 int Qux = Foo; 665 int Baz = A::[[^Foo]]; 666 void fun() { 667 struct { 668 int Foo; 669 } b = {100}; 670 int Foo = 100; 671 Baz = Foo; 672 { 673 extern int Foo; 674 Baz = Foo; 675 Foo = A::[[F^oo]] + Baz; 676 A::[[Fo^o]] = b.Foo; 677 } 678 Foo = b.Foo; 679 } 680 )cpp", 681 682 // Namespace alias. 683 R"cpp( 684 namespace a { namespace b { void foo(); } } 685 namespace [[^x]] = a::b; 686 void bar() { 687 [[x^]]::foo(); 688 } 689 )cpp", 690 691 // Enum. 692 R"cpp( 693 enum [[C^olor]] { Red, Green, Blue }; 694 void foo() { 695 [[C^olor]] c; 696 c = [[C^olor]]::Blue; 697 } 698 )cpp", 699 700 // Scoped enum. 701 R"cpp( 702 enum class [[K^ind]] { ABC }; 703 void ff() { 704 [[K^ind]] s; 705 s = [[K^ind]]::ABC; 706 } 707 )cpp", 708 709 // Template class in template argument list. 710 R"cpp( 711 template<typename T> 712 class [[Fo^o]] {}; 713 template <template<typename> class Z> struct Bar { }; 714 template <> struct Bar<[[F^oo]]> {}; 715 )cpp", 716 717 // Designated initializer. 718 R"cpp( 719 struct Bar { 720 int [[Fo^o]]; 721 }; 722 Bar bar { .[[^Foo]] = 42 }; 723 )cpp", 724 725 // Nested designated initializer. 726 R"cpp( 727 struct Baz { 728 int Field; 729 }; 730 struct Bar { 731 Baz [[Fo^o]]; 732 }; 733 // FIXME: v selecting here results in renaming Field. 734 Bar bar { .[[Foo]].Field = 42 }; 735 )cpp", 736 R"cpp( 737 struct Baz { 738 int [[Fiel^d]]; 739 }; 740 struct Bar { 741 Baz Foo; 742 }; 743 Bar bar { .Foo.[[^Field]] = 42 }; 744 )cpp", 745 746 // Templated alias. 747 R"cpp( 748 template <typename T> 749 class X { T t; }; 750 751 template <typename T> 752 using [[Fo^o]] = X<T>; 753 754 void bar() { 755 [[Fo^o]]<int> Bar; 756 } 757 )cpp", 758 759 // Alias. 760 R"cpp( 761 class X {}; 762 using [[F^oo]] = X; 763 764 void bar() { 765 [[Fo^o]] Bar; 766 } 767 )cpp", 768 769 // Alias within a namespace. 770 R"cpp( 771 namespace x { class X {}; } 772 namespace ns { 773 using [[Fo^o]] = x::X; 774 } 775 776 void bar() { 777 ns::[[Fo^o]] Bar; 778 } 779 )cpp", 780 781 // Alias within macros. 782 R"cpp( 783 namespace x { class Old {}; } 784 namespace ns { 785 #define REF(alias) alias alias_var; 786 787 #define ALIAS(old) \ 788 using old##Alias = x::old; \ 789 REF(old##Alias); 790 791 ALIAS(Old); 792 793 [[Old^Alias]] old_alias; 794 } 795 796 void bar() { 797 ns::[[Old^Alias]] Bar; 798 } 799 )cpp", 800 801 // User defined conversion. 802 R"cpp( 803 class [[F^oo]] { 804 public: 805 [[F^oo]]() {} 806 }; 807 808 class Baz { 809 public: 810 operator [[F^oo]]() { 811 return [[F^oo]](); 812 } 813 }; 814 815 int main() { 816 Baz boo; 817 [[F^oo]] foo = static_cast<[[F^oo]]>(boo); 818 } 819 )cpp", 820 821 // ObjC, should not crash. 822 R"cpp( 823 @interface ObjC { 824 char [[da^ta]]; 825 } @end 826 )cpp", 827 828 // Issue 170: Rename symbol introduced by UsingDecl 829 R"cpp( 830 namespace ns { void [[f^oo]](); } 831 832 using ns::[[f^oo]]; 833 834 void f() { 835 [[f^oo]](); 836 auto p = &[[f^oo]]; 837 } 838 )cpp", 839 840 // Issue 170: using decl that imports multiple overloads 841 // -> Only the overload under the cursor is renamed 842 R"cpp( 843 namespace ns { int [[^foo]](int); char foo(char); } 844 using ns::[[foo]]; 845 void f() { 846 [[^foo]](42); 847 foo('x'); 848 } 849 )cpp", 850 851 // ObjC class with a category. 852 R"cpp( 853 @interface [[Fo^o]] 854 @end 855 @implementation [[F^oo]] 856 @end 857 @interface [[Fo^o]] (Category) 858 @end 859 @implementation [[F^oo]] (Category) 860 @end 861 862 void func([[Fo^o]] *f) {} 863 )cpp", 864 }; 865 llvm::StringRef NewName = "NewName"; 866 for (llvm::StringRef T : Tests) { 867 SCOPED_TRACE(T); 868 Annotations Code(T); 869 auto TU = TestTU::withCode(Code.code()); 870 TU.ExtraArgs.push_back("-xobjective-c++"); 871 auto AST = TU.build(); 872 auto Index = TU.index(); 873 for (const auto &RenamePos : Code.points()) { 874 auto RenameResult = 875 rename({RenamePos, NewName, AST, testPath(TU.Filename), 876 getVFSFromAST(AST), Index.get()}); 877 ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError(); 878 ASSERT_EQ(1u, RenameResult->GlobalChanges.size()); 879 EXPECT_EQ( 880 applyEdits(std::move(RenameResult->GlobalChanges)).front().second, 881 expectedResult(Code, NewName)); 882 } 883 } 884 } 885 886 TEST(RenameTest, ObjCWithinFileRename) { 887 struct TestCase { 888 /// Annotated source code that should be renamed. Every point (indicated by 889 /// `^`) will be used as a rename location. 890 llvm::StringRef Input; 891 /// The new name that should be given to the rename locaitons. 892 llvm::StringRef NewName; 893 /// The expected rename source code or `nullopt` if we expect rename to 894 /// fail. 895 std::optional<llvm::StringRef> Expected; 896 }; 897 TestCase Tests[] = {// Simple rename 898 { 899 // Input 900 R"cpp( 901 @interface Foo 902 - (int)performA^ction:(int)action w^ith:(int)value; 903 @end 904 @implementation Foo 905 - (int)performAc^tion:(int)action w^ith:(int)value { 906 return [self performAction:action with:value]; 907 } 908 @end 909 )cpp", 910 // New name 911 "performNewAction:by:", 912 // Expected 913 R"cpp( 914 @interface Foo 915 - (int)performNewAction:(int)action by:(int)value; 916 @end 917 @implementation Foo 918 - (int)performNewAction:(int)action by:(int)value { 919 return [self performNewAction:action by:value]; 920 } 921 @end 922 )cpp", 923 }, 924 // Rename selector with macro 925 { 926 // Input 927 R"cpp( 928 #define mySelector - (int)performAction:(int)action with:(int)value 929 @interface Foo 930 ^mySelector; 931 @end 932 @implementation Foo 933 mySelector { 934 return [self performAction:action with:value]; 935 } 936 @end 937 )cpp", 938 // New name 939 "performNewAction:by:", 940 // Expected error 941 std::nullopt, 942 }, 943 // Rename selector in macro definition 944 { 945 // Input 946 R"cpp( 947 #define mySelector - (int)perform^Action:(int)action with:(int)value 948 @interface Foo 949 mySelector; 950 @end 951 @implementation Foo 952 mySelector { 953 return [self performAction:action with:value]; 954 } 955 @end 956 )cpp", 957 // New name 958 "performNewAction:by:", 959 // Expected error 960 std::nullopt, 961 }, 962 // Don't rename `@selector` 963 // `@selector` is not tied to a single selector. Eg. there 964 // might be multiple 965 // classes in the codebase that implement that selector. 966 // It's thus more like 967 // a string literal and we shouldn't rename it. 968 { 969 // Input 970 R"cpp( 971 @interface Foo 972 - (void)performA^ction:(int)action with:(int)value; 973 @end 974 @implementation Foo 975 - (void)performAction:(int)action with:(int)value { 976 SEL mySelector = @selector(performAction:with:); 977 } 978 @end 979 )cpp", 980 // New name 981 "performNewAction:by:", 982 // Expected 983 R"cpp( 984 @interface Foo 985 - (void)performNewAction:(int)action by:(int)value; 986 @end 987 @implementation Foo 988 - (void)performNewAction:(int)action by:(int)value { 989 SEL mySelector = @selector(performAction:with:); 990 } 991 @end 992 )cpp", 993 }, 994 // Fail if rename initiated inside @selector 995 { 996 // Input 997 R"cpp( 998 @interface Foo 999 - (void)performAction:(int)action with:(int)value; 1000 @end 1001 @implementation Foo 1002 - (void)performAction:(int)action with:(int)value { 1003 SEL mySelector = @selector(perfo^rmAction:with:); 1004 } 1005 @end 1006 )cpp", 1007 // New name 1008 "performNewAction:by:", 1009 // Expected 1010 std::nullopt, 1011 }}; 1012 for (TestCase T : Tests) { 1013 SCOPED_TRACE(T.Input); 1014 Annotations Code(T.Input); 1015 auto TU = TestTU::withCode(Code.code()); 1016 TU.ExtraArgs.push_back("-xobjective-c"); 1017 auto AST = TU.build(); 1018 auto Index = TU.index(); 1019 for (const auto &RenamePos : Code.points()) { 1020 auto RenameResult = 1021 rename({RenamePos, T.NewName, AST, testPath(TU.Filename), 1022 getVFSFromAST(AST), Index.get()}); 1023 if (std::optional<StringRef> Expected = T.Expected) { 1024 ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError(); 1025 ASSERT_EQ(1u, RenameResult->GlobalChanges.size()); 1026 EXPECT_EQ( 1027 applyEdits(std::move(RenameResult->GlobalChanges)).front().second, 1028 *Expected); 1029 } else { 1030 ASSERT_FALSE(bool(RenameResult)); 1031 consumeError(RenameResult.takeError()); 1032 } 1033 } 1034 } 1035 } 1036 1037 TEST(RenameTest, Renameable) { 1038 struct Case { 1039 const char *Code; 1040 const char* ErrorMessage; // null if no error 1041 bool IsHeaderFile; 1042 llvm::StringRef NewName = "MockName"; 1043 }; 1044 const bool HeaderFile = true; 1045 Case Cases[] = { 1046 {R"cpp(// allow -- function-local 1047 void f(int [[Lo^cal]]) { 1048 [[Local]] = 2; 1049 } 1050 )cpp", 1051 nullptr, HeaderFile}, 1052 1053 {R"cpp(// disallow -- symbol in anonymous namespace in header is not indexable. 1054 namespace { 1055 class Unin^dexable {}; 1056 } 1057 )cpp", 1058 "not eligible for indexing", HeaderFile}, 1059 1060 {R"cpp(// disallow -- namespace symbol isn't supported 1061 namespace n^s {} 1062 )cpp", 1063 "not a supported kind", HeaderFile}, 1064 1065 {R"cpp(// disallow - category rename. 1066 @interface Foo 1067 @end 1068 @interface Foo (Cate^gory) 1069 @end 1070 )cpp", 1071 "Cannot rename symbol: there is no symbol at the given location", 1072 HeaderFile}, 1073 1074 { 1075 R"cpp( 1076 #define MACRO 1 1077 int s = MAC^RO; 1078 )cpp", 1079 "not a supported kind", HeaderFile}, 1080 1081 { 1082 R"cpp( 1083 struct X { X operator++(int); }; 1084 void f(X x) {x+^+;})cpp", 1085 "no symbol", HeaderFile}, 1086 1087 {R"cpp( 1088 @interface Foo {} 1089 - (int)[[fo^o]]:(int)x; 1090 @end 1091 )cpp", 1092 nullptr, HeaderFile, "newName:"}, 1093 {R"cpp(//disallow as : count must match 1094 @interface Foo {} 1095 - (int)fo^o:(int)x; 1096 @end 1097 )cpp", 1098 "invalid name: the chosen name \"MockName\" is not a valid identifier", 1099 HeaderFile}, 1100 {R"cpp( 1101 @interface Foo {} 1102 - (int)[[o^ne]]:(int)one two:(int)two; 1103 @end 1104 )cpp", 1105 nullptr, HeaderFile, "a:two:"}, 1106 {R"cpp( 1107 @interface Foo {} 1108 - (int)[[o^ne]]:(int)one [[two]]:(int)two; 1109 @end 1110 )cpp", 1111 nullptr, HeaderFile, "a:b:"}, 1112 {R"cpp( 1113 @interface Foo {} 1114 - (int)o^ne:(int)one [[two]]:(int)two; 1115 @end 1116 )cpp", 1117 nullptr, HeaderFile, "one:three:"}, 1118 1119 {R"cpp( 1120 void foo(int); 1121 void foo(char); 1122 template <typename T> void f(T t) { 1123 fo^o(t); 1124 })cpp", 1125 "multiple symbols", !HeaderFile}, 1126 1127 {R"cpp(// disallow rename on unrelated token. 1128 cl^ass Foo {}; 1129 )cpp", 1130 "no symbol", !HeaderFile}, 1131 1132 {R"cpp(// disallow rename on unrelated token. 1133 temp^late<typename T> 1134 class Foo {}; 1135 )cpp", 1136 "no symbol", !HeaderFile}, 1137 1138 {R"cpp( 1139 namespace { 1140 int Conflict; 1141 int Va^r; 1142 } 1143 )cpp", 1144 "conflict", !HeaderFile, "Conflict"}, 1145 1146 {R"cpp( 1147 int Conflict; 1148 int Va^r; 1149 )cpp", 1150 "conflict", !HeaderFile, "Conflict"}, 1151 1152 {R"cpp( 1153 class Foo { 1154 int Conflict; 1155 int Va^r; 1156 }; 1157 )cpp", 1158 "conflict", !HeaderFile, "Conflict"}, 1159 1160 {R"cpp( 1161 enum E { 1162 Conflict, 1163 Fo^o, 1164 }; 1165 )cpp", 1166 "conflict", !HeaderFile, "Conflict"}, 1167 1168 {R"cpp( 1169 int Conflict; 1170 enum E { // transparent context. 1171 F^oo, 1172 }; 1173 )cpp", 1174 "conflict", !HeaderFile, "Conflict"}, 1175 1176 {R"cpp( 1177 void func() { 1178 bool Whatever; 1179 int V^ar; 1180 char Conflict; 1181 } 1182 )cpp", 1183 "conflict", !HeaderFile, "Conflict"}, 1184 1185 {R"cpp( 1186 void func() { 1187 if (int Conflict = 42) { 1188 int V^ar; 1189 } 1190 } 1191 )cpp", 1192 "conflict", !HeaderFile, "Conflict"}, 1193 1194 {R"cpp( 1195 void func() { 1196 if (int Conflict = 42) { 1197 } else { 1198 bool V^ar; 1199 } 1200 } 1201 )cpp", 1202 "conflict", !HeaderFile, "Conflict"}, 1203 1204 {R"cpp( 1205 void func() { 1206 if (int V^ar = 42) { 1207 } else { 1208 bool Conflict; 1209 } 1210 } 1211 )cpp", 1212 "conflict", !HeaderFile, "Conflict"}, 1213 1214 {R"cpp( 1215 void func() { 1216 while (int V^ar = 10) { 1217 bool Conflict = true; 1218 } 1219 } 1220 )cpp", 1221 "conflict", !HeaderFile, "Conflict"}, 1222 1223 {R"cpp( 1224 void func() { 1225 for (int Something = 9000, Anything = 14, Conflict = 42; Anything > 9; 1226 ++Something) { 1227 int V^ar; 1228 } 1229 } 1230 )cpp", 1231 "conflict", !HeaderFile, "Conflict"}, 1232 1233 {R"cpp( 1234 void func() { 1235 for (int V^ar = 14, Conflict = 42;;) { 1236 } 1237 } 1238 )cpp", 1239 "conflict", !HeaderFile, "Conflict"}, 1240 1241 {R"cpp( 1242 void func(int Conflict) { 1243 bool V^ar; 1244 } 1245 )cpp", 1246 "conflict", !HeaderFile, "Conflict"}, 1247 1248 {R"cpp( 1249 void func(int Var); 1250 1251 void func(int V^ar) { 1252 bool Conflict; 1253 } 1254 )cpp", 1255 "conflict", !HeaderFile, "Conflict"}, 1256 1257 {R"cpp(// No conflict: only forward declaration's argument is renamed. 1258 void func(int [[V^ar]]); 1259 1260 void func(int Var) { 1261 bool Conflict; 1262 } 1263 )cpp", 1264 nullptr, !HeaderFile, "Conflict"}, 1265 1266 {R"cpp( 1267 void func(int V^ar, int Conflict) { 1268 } 1269 )cpp", 1270 "conflict", !HeaderFile, "Conflict"}, 1271 1272 {R"cpp( 1273 void func(int); 1274 void [[o^therFunc]](double); 1275 )cpp", 1276 nullptr, !HeaderFile, "func"}, 1277 {R"cpp( 1278 struct S { 1279 void func(int); 1280 void [[o^therFunc]](double); 1281 }; 1282 )cpp", 1283 nullptr, !HeaderFile, "func"}, 1284 1285 {R"cpp( 1286 int V^ar; 1287 )cpp", 1288 "\"const\" is a keyword", !HeaderFile, "const"}, 1289 1290 {R"cpp(// Trying to rename into the same name, SameName == SameName. 1291 void func() { 1292 int S^ameName; 1293 } 1294 )cpp", 1295 "new name is the same", !HeaderFile, "SameName"}, 1296 {R"cpp(// Ensure it doesn't associate base specifier with base name. 1297 struct A {}; 1298 struct B : priv^ate A {}; 1299 )cpp", 1300 "Cannot rename symbol: there is no symbol at the given location", false}, 1301 {R"cpp(// Ensure it doesn't associate base specifier with base name. 1302 /*error-ok*/ 1303 struct A { 1304 A() : inva^lid(0) {} 1305 }; 1306 )cpp", 1307 "no symbol", false}, 1308 1309 {R"cpp(// FIXME we probably want to rename both overloads here, 1310 // but renaming currently assumes there's only a 1311 // single canonical declaration. 1312 namespace ns { int foo(int); char foo(char); } 1313 using ns::^foo; 1314 )cpp", 1315 "there are multiple symbols at the given location", !HeaderFile}, 1316 1317 {R"cpp( 1318 void test() { 1319 // no crash 1320 using namespace std; 1321 int [[V^ar]]; 1322 } 1323 )cpp", 1324 nullptr, !HeaderFile}, 1325 }; 1326 1327 for (const auto& Case : Cases) { 1328 SCOPED_TRACE(Case.Code); 1329 Annotations T(Case.Code); 1330 TestTU TU = TestTU::withCode(T.code()); 1331 TU.ExtraArgs.push_back("-fno-delayed-template-parsing"); 1332 if (Case.IsHeaderFile) { 1333 // We open the .h file as the main file. 1334 TU.Filename = "test.h"; 1335 // Parsing the .h file as C++ include. 1336 TU.ExtraArgs.push_back("-xobjective-c++-header"); 1337 } 1338 auto AST = TU.build(); 1339 llvm::StringRef NewName = Case.NewName; 1340 auto Results = rename({T.point(), NewName, AST, testPath(TU.Filename)}); 1341 bool WantRename = true; 1342 if (T.ranges().empty()) 1343 WantRename = false; 1344 if (!WantRename) { 1345 assert(Case.ErrorMessage && "Error message must be set!"); 1346 EXPECT_FALSE(Results) 1347 << "expected rename returned an error: " << T.code(); 1348 auto ActualMessage = llvm::toString(Results.takeError()); 1349 EXPECT_THAT(ActualMessage, testing::HasSubstr(Case.ErrorMessage)); 1350 } else { 1351 EXPECT_TRUE(bool(Results)) << "rename returned an error: " 1352 << llvm::toString(Results.takeError()); 1353 EXPECT_EQ(Results->LocalChanges, T.ranges()); 1354 } 1355 } 1356 } 1357 1358 MATCHER_P(newText, T, "") { return arg.newText == T; } 1359 1360 TEST(RenameTest, IndexMergeMainFile) { 1361 Annotations Code("int ^x();"); 1362 TestTU TU = TestTU::withCode(Code.code()); 1363 TU.Filename = "main.cc"; 1364 auto AST = TU.build(); 1365 1366 auto Main = testPath("main.cc"); 1367 auto InMemFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); 1368 InMemFS->addFile(testPath("main.cc"), 0, 1369 llvm::MemoryBuffer::getMemBuffer(Code.code())); 1370 InMemFS->addFile(testPath("other.cc"), 0, 1371 llvm::MemoryBuffer::getMemBuffer(Code.code())); 1372 1373 auto Rename = [&](const SymbolIndex *Idx) { 1374 RenameInputs Inputs{Code.point(), 1375 "xPrime", 1376 AST, 1377 Main, 1378 Idx ? createOverlay(getVFSFromAST(AST), InMemFS) 1379 : nullptr, 1380 Idx, 1381 RenameOptions()}; 1382 auto Results = rename(Inputs); 1383 EXPECT_TRUE(bool(Results)) << llvm::toString(Results.takeError()); 1384 return std::move(*Results); 1385 }; 1386 1387 // We do not expect to see duplicated edits from AST vs index. 1388 auto Results = Rename(TU.index().get()); 1389 EXPECT_THAT(Results.GlobalChanges.keys(), ElementsAre(Main)); 1390 EXPECT_THAT(Results.GlobalChanges[Main].asTextEdits(), 1391 ElementsAre(newText("xPrime"))); 1392 1393 // Sanity check: we do expect to see index results! 1394 TU.Filename = "other.cc"; 1395 Results = Rename(TU.index().get()); 1396 EXPECT_THAT(Results.GlobalChanges.keys(), 1397 UnorderedElementsAre(Main, testPath("other.cc"))); 1398 1399 #ifdef CLANGD_PATH_CASE_INSENSITIVE 1400 // On case-insensitive systems, no duplicates if AST vs index case differs. 1401 // https://github.com/clangd/clangd/issues/665 1402 TU.Filename = "MAIN.CC"; 1403 Results = Rename(TU.index().get()); 1404 EXPECT_THAT(Results.GlobalChanges.keys(), ElementsAre(Main)); 1405 EXPECT_THAT(Results.GlobalChanges[Main].asTextEdits(), 1406 ElementsAre(newText("xPrime"))); 1407 #endif 1408 } 1409 1410 TEST(RenameTest, MainFileReferencesOnly) { 1411 // filter out references not from main file. 1412 llvm::StringRef Test = 1413 R"cpp( 1414 void test() { 1415 int [[fo^o]] = 1; 1416 // rename references not from main file are not included. 1417 #include "foo.inc" 1418 })cpp"; 1419 1420 Annotations Code(Test); 1421 auto TU = TestTU::withCode(Code.code()); 1422 TU.AdditionalFiles["foo.inc"] = R"cpp( 1423 #define Macro(X) X 1424 &Macro(foo); 1425 &foo; 1426 )cpp"; 1427 auto AST = TU.build(); 1428 llvm::StringRef NewName = "abcde"; 1429 1430 auto RenameResult = 1431 rename({Code.point(), NewName, AST, testPath(TU.Filename)}); 1432 ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError() << Code.point(); 1433 ASSERT_EQ(1u, RenameResult->GlobalChanges.size()); 1434 EXPECT_EQ(applyEdits(std::move(RenameResult->GlobalChanges)).front().second, 1435 expectedResult(Code, NewName)); 1436 } 1437 1438 TEST(RenameTest, NoRenameOnSymbolsFromSystemHeaders) { 1439 llvm::StringRef Test = 1440 R"cpp( 1441 #include <cstdlib> 1442 #include <system> 1443 1444 SystemSym^bol abc; 1445 1446 void foo() { at^oi("9000"); } 1447 )cpp"; 1448 1449 Annotations Code(Test); 1450 auto TU = TestTU::withCode(Code.code()); 1451 TU.AdditionalFiles["system"] = R"cpp( 1452 class SystemSymbol {}; 1453 )cpp"; 1454 TU.AdditionalFiles["cstdlib"] = R"cpp( 1455 int atoi(const char *str); 1456 )cpp"; 1457 TU.ExtraArgs = {"-isystem", testRoot()}; 1458 auto AST = TU.build(); 1459 llvm::StringRef NewName = "abcde"; 1460 1461 // Clangd will not allow renaming symbols from the system headers for 1462 // correctness. 1463 for (auto &Point : Code.points()) { 1464 auto Results = rename({Point, NewName, AST, testPath(TU.Filename)}); 1465 EXPECT_FALSE(Results) << "expected rename returned an error: " 1466 << Code.code(); 1467 auto ActualMessage = llvm::toString(Results.takeError()); 1468 EXPECT_THAT(ActualMessage, testing::HasSubstr("not a supported kind")); 1469 } 1470 } 1471 1472 TEST(RenameTest, ProtobufSymbolIsExcluded) { 1473 Annotations Code("Prot^obuf buf;"); 1474 auto TU = TestTU::withCode(Code.code()); 1475 TU.HeaderCode = 1476 R"cpp(// Generated by the protocol buffer compiler. DO NOT EDIT! 1477 class Protobuf {}; 1478 )cpp"; 1479 TU.HeaderFilename = "protobuf.pb.h"; 1480 auto AST = TU.build(); 1481 auto Results = rename({Code.point(), "newName", AST, testPath(TU.Filename)}); 1482 EXPECT_FALSE(Results); 1483 EXPECT_THAT(llvm::toString(Results.takeError()), 1484 testing::HasSubstr("not a supported kind")); 1485 } 1486 1487 TEST(RenameTest, PrepareRename) { 1488 Annotations FooH("void func();"); 1489 Annotations FooCC(R"cpp( 1490 #include "foo.h" 1491 void [[fu^nc]]() {} 1492 )cpp"); 1493 std::string FooHPath = testPath("foo.h"); 1494 std::string FooCCPath = testPath("foo.cc"); 1495 MockFS FS; 1496 FS.Files[FooHPath] = std::string(FooH.code()); 1497 FS.Files[FooCCPath] = std::string(FooCC.code()); 1498 1499 auto ServerOpts = ClangdServer::optsForTest(); 1500 ServerOpts.BuildDynamicSymbolIndex = true; 1501 1502 trace::TestTracer Tracer; 1503 MockCompilationDatabase CDB; 1504 ClangdServer Server(CDB, FS, ServerOpts); 1505 runAddDocument(Server, FooHPath, FooH.code()); 1506 runAddDocument(Server, FooCCPath, FooCC.code()); 1507 1508 auto Results = runPrepareRename(Server, FooCCPath, FooCC.point(), 1509 /*NewName=*/std::nullopt, {}); 1510 // Verify that for multi-file rename, we only return main-file occurrences. 1511 ASSERT_TRUE(bool(Results)) << Results.takeError(); 1512 // We don't know the result is complete in prepareRename (passing a nullptr 1513 // index internally), so GlobalChanges should be empty. 1514 EXPECT_TRUE(Results->GlobalChanges.empty()); 1515 EXPECT_THAT(FooCC.ranges(), 1516 testing::UnorderedElementsAreArray(Results->LocalChanges)); 1517 1518 // Name validation. 1519 Results = runPrepareRename(Server, FooCCPath, FooCC.point(), 1520 /*NewName=*/std::string("int"), {}); 1521 EXPECT_FALSE(Results); 1522 EXPECT_THAT(llvm::toString(Results.takeError()), 1523 testing::HasSubstr("keyword")); 1524 EXPECT_THAT(Tracer.takeMetric("rename_name_invalid", "Keywords"), 1525 ElementsAre(1)); 1526 1527 for (std::string BadIdent : {"foo!bar", "123foo", "@"}) { 1528 Results = runPrepareRename(Server, FooCCPath, FooCC.point(), 1529 /*NewName=*/BadIdent, {}); 1530 EXPECT_FALSE(Results); 1531 EXPECT_THAT(llvm::toString(Results.takeError()), 1532 testing::HasSubstr("identifier")); 1533 EXPECT_THAT(Tracer.takeMetric("rename_name_invalid", "BadIdentifier"), 1534 ElementsAre(1)); 1535 } 1536 for (std::string GoodIdent : {"fooBar", "__foo$", ""}) { 1537 Results = runPrepareRename(Server, FooCCPath, FooCC.point(), 1538 /*NewName=*/GoodIdent, {}); 1539 EXPECT_TRUE(bool(Results)); 1540 } 1541 } 1542 1543 TEST(CrossFileRenameTests, DirtyBuffer) { 1544 Annotations FooCode("class [[Foo]] {};"); 1545 std::string FooPath = testPath("foo.cc"); 1546 Annotations FooDirtyBuffer("class [[Foo]] {};\n// this is dirty buffer"); 1547 Annotations BarCode("void [[Bar]]() {}"); 1548 std::string BarPath = testPath("bar.cc"); 1549 // Build the index, the index has "Foo" references from foo.cc and "Bar" 1550 // references from bar.cc. 1551 FileSymbols FSymbols(IndexContents::All, true); 1552 FSymbols.update(FooPath, nullptr, buildRefSlab(FooCode, "Foo", FooPath), 1553 nullptr, false); 1554 FSymbols.update(BarPath, nullptr, buildRefSlab(BarCode, "Bar", BarPath), 1555 nullptr, false); 1556 auto Index = FSymbols.buildIndex(IndexType::Light); 1557 1558 Annotations MainCode("class [[Fo^o]] {};"); 1559 auto MainFilePath = testPath("main.cc"); 1560 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemFS = 1561 new llvm::vfs::InMemoryFileSystem; 1562 InMemFS->addFile(FooPath, 0, 1563 llvm::MemoryBuffer::getMemBuffer(FooDirtyBuffer.code())); 1564 1565 // Run rename on Foo, there is a dirty buffer for foo.cc, rename should 1566 // respect the dirty buffer. 1567 TestTU TU = TestTU::withCode(MainCode.code()); 1568 auto AST = TU.build(); 1569 llvm::StringRef NewName = "newName"; 1570 auto Results = 1571 rename({MainCode.point(), NewName, AST, MainFilePath, 1572 createOverlay(getVFSFromAST(AST), InMemFS), Index.get()}); 1573 ASSERT_TRUE(bool(Results)) << Results.takeError(); 1574 EXPECT_THAT( 1575 applyEdits(std::move(Results->GlobalChanges)), 1576 UnorderedElementsAre( 1577 Pair(Eq(FooPath), Eq(expectedResult(FooDirtyBuffer, NewName))), 1578 Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName))))); 1579 1580 // Run rename on Bar, there is no dirty buffer for the affected file bar.cc, 1581 // so we should read file content from VFS. 1582 MainCode = Annotations("void [[Bar]]() { [[B^ar]](); }"); 1583 TU = TestTU::withCode(MainCode.code()); 1584 // Set a file "bar.cc" on disk. 1585 TU.AdditionalFiles["bar.cc"] = std::string(BarCode.code()); 1586 AST = TU.build(); 1587 Results = rename({MainCode.point(), NewName, AST, MainFilePath, 1588 createOverlay(getVFSFromAST(AST), InMemFS), Index.get()}); 1589 ASSERT_TRUE(bool(Results)) << Results.takeError(); 1590 EXPECT_THAT( 1591 applyEdits(std::move(Results->GlobalChanges)), 1592 UnorderedElementsAre( 1593 Pair(Eq(BarPath), Eq(expectedResult(BarCode, NewName))), 1594 Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName))))); 1595 1596 // Run rename on a pagination index which couldn't return all refs in one 1597 // request, we reject rename on this case. 1598 class PaginationIndex : public SymbolIndex { 1599 bool refs(const RefsRequest &Req, 1600 llvm::function_ref<void(const Ref &)> Callback) const override { 1601 return true; // has more references 1602 } 1603 1604 bool containedRefs(const ContainedRefsRequest &Req, 1605 llvm::function_ref<void(const ContainedRefsResult &)> 1606 Callback) const override { 1607 return false; 1608 } 1609 1610 bool fuzzyFind( 1611 const FuzzyFindRequest &Req, 1612 llvm::function_ref<void(const Symbol &)> Callback) const override { 1613 return false; 1614 } 1615 void 1616 lookup(const LookupRequest &Req, 1617 llvm::function_ref<void(const Symbol &)> Callback) const override {} 1618 1619 void relations(const RelationsRequest &Req, 1620 llvm::function_ref<void(const SymbolID &, const Symbol &)> 1621 Callback) const override {} 1622 1623 llvm::unique_function<IndexContents(llvm::StringRef) const> 1624 indexedFiles() const override { 1625 return [](llvm::StringRef) { return IndexContents::None; }; 1626 } 1627 1628 size_t estimateMemoryUsage() const override { return 0; } 1629 } PIndex; 1630 Results = rename({MainCode.point(), NewName, AST, MainFilePath, 1631 createOverlay(getVFSFromAST(AST), InMemFS), &PIndex}); 1632 EXPECT_FALSE(Results); 1633 EXPECT_THAT(llvm::toString(Results.takeError()), 1634 testing::HasSubstr("too many occurrences")); 1635 } 1636 1637 TEST(CrossFileRenameTests, DeduplicateRefsFromIndex) { 1638 auto MainCode = Annotations("int [[^x]] = 2;"); 1639 auto MainFilePath = testPath("main.cc"); 1640 auto BarCode = Annotations("int [[x]];"); 1641 auto BarPath = testPath("bar.cc"); 1642 auto TU = TestTU::withCode(MainCode.code()); 1643 // Set a file "bar.cc" on disk. 1644 TU.AdditionalFiles["bar.cc"] = std::string(BarCode.code()); 1645 auto AST = TU.build(); 1646 std::string BarPathURI = URI::create(BarPath).toString(); 1647 Ref XRefInBarCC = refWithRange(BarCode.range(), BarPathURI); 1648 // The index will return duplicated refs, our code should be robost to handle 1649 // it. 1650 class DuplicatedXRefIndex : public SymbolIndex { 1651 public: 1652 DuplicatedXRefIndex(const Ref &ReturnedRef) : ReturnedRef(ReturnedRef) {} 1653 bool refs(const RefsRequest &Req, 1654 llvm::function_ref<void(const Ref &)> Callback) const override { 1655 // Return two duplicated refs. 1656 Callback(ReturnedRef); 1657 Callback(ReturnedRef); 1658 return false; 1659 } 1660 1661 bool containedRefs(const ContainedRefsRequest &Req, 1662 llvm::function_ref<void(const ContainedRefsResult &)> 1663 Callback) const override { 1664 return false; 1665 } 1666 1667 bool fuzzyFind(const FuzzyFindRequest &, 1668 llvm::function_ref<void(const Symbol &)>) const override { 1669 return false; 1670 } 1671 void lookup(const LookupRequest &, 1672 llvm::function_ref<void(const Symbol &)>) const override {} 1673 1674 void relations(const RelationsRequest &, 1675 llvm::function_ref<void(const SymbolID &, const Symbol &)>) 1676 const override {} 1677 1678 llvm::unique_function<IndexContents(llvm::StringRef) const> 1679 indexedFiles() const override { 1680 return [](llvm::StringRef) { return IndexContents::None; }; 1681 } 1682 1683 size_t estimateMemoryUsage() const override { return 0; } 1684 Ref ReturnedRef; 1685 } DIndex(XRefInBarCC); 1686 llvm::StringRef NewName = "newName"; 1687 auto Results = rename({MainCode.point(), NewName, AST, MainFilePath, 1688 getVFSFromAST(AST), &DIndex}); 1689 ASSERT_TRUE(bool(Results)) << Results.takeError(); 1690 EXPECT_THAT( 1691 applyEdits(std::move(Results->GlobalChanges)), 1692 UnorderedElementsAre( 1693 Pair(Eq(BarPath), Eq(expectedResult(BarCode, NewName))), 1694 Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName))))); 1695 } 1696 1697 TEST(CrossFileRenameTests, WithUpToDateIndex) { 1698 MockCompilationDatabase CDB; 1699 CDB.ExtraClangFlags = {"-xobjective-c++"}; 1700 // rename is runnning on all "^" points in FooH, and "[[]]" ranges are the 1701 // expected rename occurrences. 1702 struct Case { 1703 llvm::StringRef FooH; 1704 llvm::StringRef FooCC; 1705 } Cases[] = { 1706 { 1707 // classes. 1708 R"cpp( 1709 class [[Fo^o]] { 1710 [[Foo]](); 1711 ~[[Foo]](); 1712 }; 1713 )cpp", 1714 R"cpp( 1715 #include "foo.h" 1716 [[Foo]]::[[Foo]]() {} 1717 [[Foo]]::~[[Foo]]() {} 1718 1719 void func() { 1720 [[Foo]] foo; 1721 } 1722 )cpp", 1723 }, 1724 { 1725 // class templates. 1726 R"cpp( 1727 template <typename T> 1728 class [[Foo]] {}; 1729 // FIXME: explicit template specializations are not supported due the 1730 // clangd index limitations. 1731 template <> 1732 class Foo<double> {}; 1733 )cpp", 1734 R"cpp( 1735 #include "foo.h" 1736 void func() { 1737 [[F^oo]]<int> foo; 1738 } 1739 )cpp", 1740 }, 1741 { 1742 // class methods. 1743 R"cpp( 1744 class Foo { 1745 void [[f^oo]](); 1746 }; 1747 )cpp", 1748 R"cpp( 1749 #include "foo.h" 1750 void Foo::[[foo]]() {} 1751 1752 void func(Foo* p) { 1753 p->[[foo]](); 1754 } 1755 )cpp", 1756 }, 1757 { 1758 // virtual methods. 1759 R"cpp( 1760 class Base { 1761 virtual void [[foo]](); 1762 }; 1763 class Derived1 : public Base { 1764 void [[f^oo]]() override; 1765 }; 1766 class NotDerived { 1767 void foo() {}; 1768 } 1769 )cpp", 1770 R"cpp( 1771 #include "foo.h" 1772 void Base::[[foo]]() {} 1773 void Derived1::[[foo]]() {} 1774 1775 class Derived2 : public Derived1 { 1776 void [[foo]]() override {}; 1777 }; 1778 1779 void func(Base* b, Derived1* d1, 1780 Derived2* d2, NotDerived* nd) { 1781 b->[[foo]](); 1782 d1->[[foo]](); 1783 d2->[[foo]](); 1784 nd->foo(); 1785 } 1786 )cpp", 1787 }, 1788 {// virtual templated method 1789 R"cpp( 1790 template <typename> class Foo { virtual void [[m]](); }; 1791 class Bar : Foo<int> { void [[^m]]() override; }; 1792 )cpp", 1793 R"cpp( 1794 #include "foo.h" 1795 1796 template<typename T> void Foo<T>::[[m]]() {} 1797 // FIXME: not renamed as the index doesn't see this as an override of 1798 // the canonical Foo<T>::m(). 1799 // https://github.com/clangd/clangd/issues/1325 1800 class Baz : Foo<float> { void m() override; }; 1801 )cpp"}, 1802 { 1803 // rename on constructor and destructor. 1804 R"cpp( 1805 class [[Foo]] { 1806 [[^Foo]](); 1807 ~[[Foo^]](); 1808 }; 1809 )cpp", 1810 R"cpp( 1811 #include "foo.h" 1812 [[Foo]]::[[Foo]]() {} 1813 [[Foo]]::~[[Foo]]() {} 1814 1815 void func() { 1816 [[Foo]] foo; 1817 } 1818 )cpp", 1819 }, 1820 { 1821 // functions. 1822 R"cpp( 1823 void [[f^oo]](); 1824 )cpp", 1825 R"cpp( 1826 #include "foo.h" 1827 void [[foo]]() {} 1828 1829 void func() { 1830 [[foo]](); 1831 } 1832 )cpp", 1833 }, 1834 { 1835 // typedefs. 1836 R"cpp( 1837 typedef int [[IN^T]]; 1838 [[INT]] foo(); 1839 )cpp", 1840 R"cpp( 1841 #include "foo.h" 1842 [[INT]] foo() {} 1843 )cpp", 1844 }, 1845 { 1846 // usings. 1847 R"cpp( 1848 using [[I^NT]] = int; 1849 [[INT]] foo(); 1850 )cpp", 1851 R"cpp( 1852 #include "foo.h" 1853 [[INT]] foo() {} 1854 )cpp", 1855 }, 1856 { 1857 // variables. 1858 R"cpp( 1859 static const int [[VA^R]] = 123; 1860 )cpp", 1861 R"cpp( 1862 #include "foo.h" 1863 int s = [[VAR]]; 1864 )cpp", 1865 }, 1866 { 1867 // scope enums. 1868 R"cpp( 1869 enum class [[K^ind]] { ABC }; 1870 )cpp", 1871 R"cpp( 1872 #include "foo.h" 1873 [[Kind]] ff() { 1874 return [[Kind]]::ABC; 1875 } 1876 )cpp", 1877 }, 1878 { 1879 // enum constants. 1880 R"cpp( 1881 enum class Kind { [[A^BC]] }; 1882 )cpp", 1883 R"cpp( 1884 #include "foo.h" 1885 Kind ff() { 1886 return Kind::[[ABC]]; 1887 } 1888 )cpp", 1889 }, 1890 { 1891 // Implicit references in macro expansions. 1892 R"cpp( 1893 class [[Fo^o]] {}; 1894 #define FooFoo Foo 1895 #define FOO Foo 1896 )cpp", 1897 R"cpp( 1898 #include "foo.h" 1899 void bar() { 1900 [[Foo]] x; 1901 FOO y; 1902 FooFoo z; 1903 } 1904 )cpp", 1905 }, 1906 { 1907 // Objective-C classes. 1908 R"cpp( 1909 @interface [[Fo^o]] 1910 @end 1911 )cpp", 1912 R"cpp( 1913 #include "foo.h" 1914 @implementation [[Foo]] 1915 @end 1916 1917 void func([[Foo]] *f) {} 1918 )cpp", 1919 }, 1920 }; 1921 1922 trace::TestTracer Tracer; 1923 for (const auto &T : Cases) { 1924 SCOPED_TRACE(T.FooH); 1925 Annotations FooH(T.FooH); 1926 Annotations FooCC(T.FooCC); 1927 std::string FooHPath = testPath("foo.h"); 1928 std::string FooCCPath = testPath("foo.cc"); 1929 1930 MockFS FS; 1931 FS.Files[FooHPath] = std::string(FooH.code()); 1932 FS.Files[FooCCPath] = std::string(FooCC.code()); 1933 1934 auto ServerOpts = ClangdServer::optsForTest(); 1935 ServerOpts.BuildDynamicSymbolIndex = true; 1936 ClangdServer Server(CDB, FS, ServerOpts); 1937 1938 // Add all files to clangd server to make sure the dynamic index has been 1939 // built. 1940 runAddDocument(Server, FooHPath, FooH.code()); 1941 runAddDocument(Server, FooCCPath, FooCC.code()); 1942 1943 llvm::StringRef NewName = "NewName"; 1944 for (const auto &RenamePos : FooH.points()) { 1945 EXPECT_THAT(Tracer.takeMetric("rename_files"), SizeIs(0)); 1946 auto FileEditsList = 1947 llvm::cantFail(runRename(Server, FooHPath, RenamePos, NewName, {})); 1948 EXPECT_THAT(Tracer.takeMetric("rename_files"), ElementsAre(2)); 1949 EXPECT_THAT( 1950 applyEdits(std::move(FileEditsList.GlobalChanges)), 1951 UnorderedElementsAre( 1952 Pair(Eq(FooHPath), Eq(expectedResult(T.FooH, NewName))), 1953 Pair(Eq(FooCCPath), Eq(expectedResult(T.FooCC, NewName))))); 1954 } 1955 } 1956 } 1957 1958 TEST(CrossFileRenameTests, ObjC) { 1959 MockCompilationDatabase CDB; 1960 CDB.ExtraClangFlags = {"-xobjective-c"}; 1961 // rename is runnning on all "^" points in FooH. 1962 struct Case { 1963 llvm::StringRef FooH; 1964 llvm::StringRef FooM; 1965 llvm::StringRef NewName; 1966 llvm::StringRef ExpectedFooH; 1967 llvm::StringRef ExpectedFooM; 1968 }; 1969 Case Cases[] = {// --- Zero arg selector 1970 { 1971 // Input 1972 R"cpp( 1973 @interface Foo 1974 - (int)performA^ction; 1975 @end 1976 )cpp", 1977 R"cpp( 1978 @implementation Foo 1979 - (int)performAction { 1980 [self performAction]; 1981 } 1982 @end 1983 )cpp", 1984 // New name 1985 "performNewAction", 1986 // Expected 1987 R"cpp( 1988 @interface Foo 1989 - (int)performNewAction; 1990 @end 1991 )cpp", 1992 R"cpp( 1993 @implementation Foo 1994 - (int)performNewAction { 1995 [self performNewAction]; 1996 } 1997 @end 1998 )cpp", 1999 }, 2000 // --- Single arg selector 2001 { 2002 // Input 2003 R"cpp( 2004 @interface Foo 2005 - (int)performA^ction:(int)action; 2006 @end 2007 )cpp", 2008 R"cpp( 2009 @implementation Foo 2010 - (int)performAction:(int)action { 2011 [self performAction:action]; 2012 } 2013 @end 2014 )cpp", 2015 // New name 2016 "performNewAction:", 2017 // Expected 2018 R"cpp( 2019 @interface Foo 2020 - (int)performNewAction:(int)action; 2021 @end 2022 )cpp", 2023 R"cpp( 2024 @implementation Foo 2025 - (int)performNewAction:(int)action { 2026 [self performNewAction:action]; 2027 } 2028 @end 2029 )cpp", 2030 }, 2031 // --- Multi arg selector 2032 { 2033 // Input 2034 R"cpp( 2035 @interface Foo 2036 - (int)performA^ction:(int)action with:(int)value; 2037 @end 2038 )cpp", 2039 R"cpp( 2040 @implementation Foo 2041 - (int)performAction:(int)action with:(int)value { 2042 [self performAction:action with:value]; 2043 } 2044 @end 2045 )cpp", 2046 // New name 2047 "performNewAction:by:", 2048 // Expected 2049 R"cpp( 2050 @interface Foo 2051 - (int)performNewAction:(int)action by:(int)value; 2052 @end 2053 )cpp", 2054 R"cpp( 2055 @implementation Foo 2056 - (int)performNewAction:(int)action by:(int)value { 2057 [self performNewAction:action by:value]; 2058 } 2059 @end 2060 )cpp", 2061 }}; 2062 2063 trace::TestTracer Tracer; 2064 for (const auto &T : Cases) { 2065 SCOPED_TRACE(T.FooH); 2066 Annotations FooH(T.FooH); 2067 Annotations FooM(T.FooM); 2068 std::string FooHPath = testPath("foo.h"); 2069 std::string FooMPath = testPath("foo.m"); 2070 2071 MockFS FS; 2072 FS.Files[FooHPath] = std::string(FooH.code()); 2073 FS.Files[FooMPath] = std::string(FooM.code()); 2074 2075 auto ServerOpts = ClangdServer::optsForTest(); 2076 ServerOpts.BuildDynamicSymbolIndex = true; 2077 ClangdServer Server(CDB, FS, ServerOpts); 2078 2079 // Add all files to clangd server to make sure the dynamic index has been 2080 // built. 2081 runAddDocument(Server, FooHPath, FooH.code()); 2082 runAddDocument(Server, FooMPath, FooM.code()); 2083 2084 for (const auto &RenamePos : FooH.points()) { 2085 EXPECT_THAT(Tracer.takeMetric("rename_files"), SizeIs(0)); 2086 auto FileEditsList = 2087 llvm::cantFail(runRename(Server, FooHPath, RenamePos, T.NewName, {})); 2088 EXPECT_THAT(Tracer.takeMetric("rename_files"), ElementsAre(2)); 2089 EXPECT_THAT(applyEdits(std::move(FileEditsList.GlobalChanges)), 2090 UnorderedElementsAre(Pair(Eq(FooHPath), Eq(T.ExpectedFooH)), 2091 Pair(Eq(FooMPath), Eq(T.ExpectedFooM)))); 2092 } 2093 } 2094 } 2095 2096 TEST(CrossFileRenameTests, CrossFileOnLocalSymbol) { 2097 // cross-file rename should work for function-local symbols, even there is no 2098 // index provided. 2099 Annotations Code("void f(int [[abc]]) { [[a^bc]] = 3; }"); 2100 auto TU = TestTU::withCode(Code.code()); 2101 auto Path = testPath(TU.Filename); 2102 auto AST = TU.build(); 2103 llvm::StringRef NewName = "newName"; 2104 auto Results = rename({Code.point(), NewName, AST, Path}); 2105 ASSERT_TRUE(bool(Results)) << Results.takeError(); 2106 EXPECT_THAT( 2107 applyEdits(std::move(Results->GlobalChanges)), 2108 UnorderedElementsAre(Pair(Eq(Path), Eq(expectedResult(Code, NewName))))); 2109 } 2110 2111 TEST(CrossFileRenameTests, BuildRenameEdits) { 2112 Annotations Code("[[]]"); 2113 auto LSPRange = Code.range(); 2114 llvm::StringRef FilePath = "/test/TestTU.cpp"; 2115 llvm::SmallVector<llvm::StringRef, 2> NewNames = {"abc"}; 2116 auto Edit = buildRenameEdit(FilePath, Code.code(), {LSPRange}, NewNames); 2117 ASSERT_TRUE(bool(Edit)) << Edit.takeError(); 2118 ASSERT_EQ(1UL, Edit->Replacements.size()); 2119 EXPECT_EQ(FilePath, Edit->Replacements.begin()->getFilePath()); 2120 EXPECT_EQ(4UL, Edit->Replacements.begin()->getLength()); 2121 2122 // Test invalid range. 2123 LSPRange.end = {10, 0}; // out of range 2124 Edit = buildRenameEdit(FilePath, Code.code(), {LSPRange}, NewNames); 2125 EXPECT_FALSE(Edit); 2126 EXPECT_THAT(llvm::toString(Edit.takeError()), 2127 testing::HasSubstr("fail to convert")); 2128 2129 // Normal ascii characters. 2130 Annotations T(R"cpp( 2131 [[range]] 2132 [[range]] 2133 [[range]] 2134 )cpp"); 2135 Edit = 2136 buildRenameEdit(FilePath, T.code(), symbolRanges(T.ranges()), NewNames); 2137 ASSERT_TRUE(bool(Edit)) << Edit.takeError(); 2138 EXPECT_EQ(applyEdits(FileEdits{{T.code(), std::move(*Edit)}}).front().second, 2139 expectedResult(T, NewNames[0])); 2140 } 2141 2142 TEST(CrossFileRenameTests, adjustRenameRanges) { 2143 // Ranges in IndexedCode indicate the indexed occurrences; 2144 // ranges in DraftCode indicate the expected mapped result, empty indicates 2145 // we expect no matched result found. 2146 struct { 2147 llvm::StringRef IndexedCode; 2148 llvm::StringRef DraftCode; 2149 } Tests[] = { 2150 { 2151 // both line and column are changed, not a near miss. 2152 R"cpp( 2153 int [[x]] = 0; 2154 )cpp", 2155 R"cpp( 2156 // insert a line. 2157 double x = 0; 2158 )cpp", 2159 }, 2160 { 2161 // subset. 2162 R"cpp( 2163 int [[x]] = 0; 2164 )cpp", 2165 R"cpp( 2166 int [[x]] = 0; 2167 {int x = 0; } 2168 )cpp", 2169 }, 2170 { 2171 // shift columns. 2172 R"cpp(int [[x]] = 0; void foo(int x);)cpp", 2173 R"cpp(double [[x]] = 0; void foo(double x);)cpp", 2174 }, 2175 { 2176 // shift lines. 2177 R"cpp( 2178 int [[x]] = 0; 2179 void foo(int x); 2180 )cpp", 2181 R"cpp( 2182 // insert a line. 2183 int [[x]] = 0; 2184 void foo(int x); 2185 )cpp", 2186 }, 2187 }; 2188 LangOptions LangOpts; 2189 LangOpts.CPlusPlus = true; 2190 for (const auto &T : Tests) { 2191 SCOPED_TRACE(T.DraftCode); 2192 Annotations Draft(T.DraftCode); 2193 auto ActualRanges = adjustRenameRanges(Draft.code(), "x", 2194 Annotations(T.IndexedCode).ranges(), 2195 LangOpts, std::nullopt); 2196 if (!ActualRanges) 2197 EXPECT_THAT(Draft.ranges(), testing::IsEmpty()); 2198 else 2199 EXPECT_THAT(Draft.ranges(), 2200 testing::UnorderedElementsAreArray(*ActualRanges)); 2201 } 2202 } 2203 2204 TEST(RangePatchingHeuristic, GetMappedRanges) { 2205 // ^ in LexedCode marks the ranges we expect to be mapped; no ^ indicates 2206 // there are no mapped ranges. 2207 struct { 2208 llvm::StringRef IndexedCode; 2209 llvm::StringRef LexedCode; 2210 } Tests[] = { 2211 { 2212 // no lexed ranges. 2213 "[[]]", 2214 "", 2215 }, 2216 { 2217 // both line and column are changed, not a near miss. 2218 R"([[]])", 2219 R"( 2220 [[]] 2221 )", 2222 }, 2223 { 2224 // subset. 2225 "[[]]", 2226 "^[[]] [[]]" 2227 }, 2228 { 2229 // shift columns. 2230 "[[]] [[]]", 2231 " ^[[]] ^[[]] [[]]" 2232 }, 2233 { 2234 R"( 2235 [[]] 2236 2237 [[]] [[]] 2238 )", 2239 R"( 2240 // insert a line 2241 ^[[]] 2242 2243 ^[[]] ^[[]] 2244 )", 2245 }, 2246 { 2247 R"( 2248 [[]] 2249 2250 [[]] [[]] 2251 )", 2252 R"( 2253 // insert a line 2254 ^[[]] 2255 ^[[]] ^[[]] // column is shifted. 2256 )", 2257 }, 2258 { 2259 R"( 2260 [[]] 2261 2262 [[]] [[]] 2263 )", 2264 R"( 2265 // insert a line 2266 [[]] 2267 2268 [[]] [[]] // not mapped (both line and column are changed). 2269 )", 2270 }, 2271 { 2272 R"( 2273 [[]] 2274 [[]] 2275 2276 [[]] 2277 [[]] 2278 2279 } 2280 )", 2281 R"( 2282 // insert a new line 2283 ^[[]] 2284 ^[[]] 2285 [[]] // additional range 2286 ^[[]] 2287 ^[[]] 2288 [[]] // additional range 2289 )", 2290 }, 2291 { 2292 // non-distinct result (two best results), not a near miss 2293 R"( 2294 [[]] 2295 [[]] 2296 [[]] 2297 )", 2298 R"( 2299 [[]] 2300 [[]] 2301 [[]] 2302 [[]] 2303 )", 2304 } 2305 }; 2306 for (const auto &T : Tests) { 2307 SCOPED_TRACE(T.IndexedCode); 2308 auto Lexed = Annotations(T.LexedCode); 2309 auto LexedRanges = symbolRanges(Lexed.ranges()); 2310 std::vector<SymbolRange> ExpectedMatches; 2311 for (auto P : Lexed.points()) { 2312 auto Match = llvm::find_if(LexedRanges, [&P](const SymbolRange &R) { 2313 return R.range().start == P; 2314 }); 2315 ASSERT_NE(Match, LexedRanges.end()); 2316 ExpectedMatches.push_back(*Match); 2317 } 2318 2319 auto Mapped = 2320 getMappedRanges(Annotations(T.IndexedCode).ranges(), LexedRanges); 2321 if (!Mapped) 2322 EXPECT_THAT(ExpectedMatches, IsEmpty()); 2323 else 2324 EXPECT_THAT(ExpectedMatches, UnorderedElementsAreArray(*Mapped)); 2325 } 2326 } 2327 2328 TEST(CrossFileRenameTests, adjustmentCost) { 2329 struct { 2330 llvm::StringRef RangeCode; 2331 size_t ExpectedCost; 2332 } Tests[] = { 2333 { 2334 R"( 2335 $idx[[]]$lex[[]] // diff: 0 2336 )", 2337 0, 2338 }, 2339 { 2340 R"( 2341 $idx[[]] 2342 $lex[[]] // line diff: +1 2343 $idx[[]] 2344 $lex[[]] // line diff: +1 2345 $idx[[]] 2346 $lex[[]] // line diff: +1 2347 2348 $idx[[]] 2349 2350 $lex[[]] // line diff: +2 2351 )", 2352 1 + 1 2353 }, 2354 { 2355 R"( 2356 $idx[[]] 2357 $lex[[]] // line diff: +1 2358 $idx[[]] 2359 2360 $lex[[]] // line diff: +2 2361 $idx[[]] 2362 2363 2364 $lex[[]] // line diff: +3 2365 )", 2366 1 + 1 + 1 2367 }, 2368 { 2369 R"( 2370 $idx[[]] 2371 2372 2373 $lex[[]] // line diff: +3 2374 $idx[[]] 2375 2376 $lex[[]] // line diff: +2 2377 $idx[[]] 2378 $lex[[]] // line diff: +1 2379 )", 2380 3 + 1 + 1 2381 }, 2382 { 2383 R"( 2384 $idx[[]] 2385 $lex[[]] // line diff: +1 2386 $lex[[]] // line diff: -2 2387 2388 $idx[[]] 2389 $idx[[]] 2390 2391 2392 $lex[[]] // line diff: +3 2393 )", 2394 1 + 3 + 5 2395 }, 2396 { 2397 R"( 2398 $idx[[]] $lex[[]] // column diff: +1 2399 $idx[[]]$lex[[]] // diff: 0 2400 )", 2401 1 2402 }, 2403 { 2404 R"( 2405 $idx[[]] 2406 $lex[[]] // diff: +1 2407 $idx[[]] $lex[[]] // column diff: +1 2408 $idx[[]]$lex[[]] // diff: 0 2409 )", 2410 1 + 1 + 1 2411 }, 2412 { 2413 R"( 2414 $idx[[]] $lex[[]] // column diff: +1 2415 )", 2416 1 2417 }, 2418 { 2419 R"( 2420 // column diffs: +1, +2, +3 2421 $idx[[]] $lex[[]] $idx[[]] $lex[[]] $idx[[]] $lex[[]] 2422 )", 2423 1 + 1 + 1, 2424 }, 2425 }; 2426 for (const auto &T : Tests) { 2427 SCOPED_TRACE(T.RangeCode); 2428 Annotations C(T.RangeCode); 2429 std::vector<size_t> MappedIndex; 2430 for (size_t I = 0; I < C.ranges("lex").size(); ++I) 2431 MappedIndex.push_back(I); 2432 EXPECT_EQ(renameRangeAdjustmentCost( 2433 C.ranges("idx"), symbolRanges(C.ranges("lex")), MappedIndex), 2434 T.ExpectedCost); 2435 } 2436 } 2437 2438 } // namespace 2439 } // namespace clangd 2440 } // namespace clang 2441