[AMDGPU][AsmParser][NFC] Translate parsed MIMG instructions to MCInsts automatically.
[llvm-project.git] / clang-tools-extra / clangd / unittests / RenameTests.cpp
blob2414ff6b64c3f26ddc81ab801eff0d4a0038702c
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 //===----------------------------------------------------------------------===//
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"
24 namespace clang {
25 namespace clangd {
26 namespace {
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;
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;
45 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> getVFSFromAST(ParsedAST &AST) {
46 return &AST.getSourceManager().getFileManager().getVirtualFileSystem();
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;
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));
75 return std::make_unique<RefSlab>(std::move(Builder).build());
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;
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;
102 Result += Code.substr(NextChar);
103 return Result;
106 TEST(RenameTest, WithinFileRename) {
107 // For each "^" this test moves cursor to its location and applies renaming
108 // while checking that all identifiers in [[]] ranges are also renamed.
109 llvm::StringRef Tests[] = {
110 // Function.
111 R"cpp(
112 void [[foo^]]() {
113 [[fo^o]]();
115 )cpp",
117 // Type.
118 R"cpp(
119 struct [[foo^]] {};
120 [[foo]] test() {
121 [[f^oo]] x;
122 return x;
124 )cpp",
126 // Local variable.
127 R"cpp(
128 void bar() {
129 if (auto [[^foo]] = 5) {
130 [[foo]] = 3;
133 )cpp",
135 // Class, its constructor and destructor.
136 R"cpp(
137 class [[F^oo]] {
138 [[F^oo]]();
139 ~[[F^oo]]();
140 [[F^oo]] *foo(int x);
142 [[F^oo]] *Ptr;
144 [[F^oo]]::[[Fo^o]]() {}
145 [[F^oo]]::~[[Fo^o]]() {}
146 [[F^oo]] *[[F^oo]]::foo(int x) { return Ptr; }
147 )cpp",
149 // Template class, its constructor and destructor.
150 R"cpp(
151 template <typename T>
152 class [[F^oo]] {
153 [[F^oo]]();
154 ~[[F^oo]]();
155 void f([[F^oo]] x);
158 template<typename T>
159 [[F^oo]]<T>::[[Fo^o]]() {}
161 template<typename T>
162 [[F^oo]]<T>::~[[Fo^o]]() {}
163 )cpp",
165 // Template class constructor.
166 R"cpp(
167 class [[F^oo]] {
168 template<typename T>
169 [[Fo^o]]();
171 template<typename T>
172 [[F^oo]](T t);
175 template<typename T>
176 [[F^oo]]::[[Fo^o]]() {}
177 )cpp",
179 // Class in template argument.
180 R"cpp(
181 class [[F^oo]] {};
182 template <typename T> void func();
183 template <typename T> class Baz {};
184 int main() {
185 func<[[F^oo]]>();
186 Baz<[[F^oo]]> obj;
187 return 0;
189 )cpp",
191 // Forward class declaration without definition.
192 R"cpp(
193 class [[F^oo]];
194 [[F^oo]] *f();
195 )cpp",
197 // Member function.
198 R"cpp(
199 struct X {
200 void [[F^oo]]() {}
201 void Baz() { [[F^oo]](); }
203 )cpp",
205 // Templated method instantiation.
206 R"cpp(
207 template<typename T>
208 class Foo {
209 public:
210 static T [[f^oo]]() {}
213 void bar() {
214 Foo<int>::[[f^oo]]();
216 )cpp",
217 R"cpp(
218 template<typename T>
219 class Foo {
220 public:
221 T [[f^oo]]() {}
224 void bar() {
225 Foo<int>().[[f^oo]]();
227 )cpp",
229 // Template class (partial) specializations.
230 R"cpp(
231 template <typename T>
232 class [[F^oo]] {};
234 template<>
235 class [[F^oo]]<bool> {};
236 template <typename T>
237 class [[F^oo]]<T*> {};
239 void test() {
240 [[F^oo]]<int> x;
241 [[F^oo]]<bool> y;
242 [[F^oo]]<int*> z;
244 )cpp",
246 // Incomplete class specializations
247 R"cpp(
248 template <typename T>
249 class [[Fo^o]] {};
250 void func([[F^oo]]<int>);
251 )cpp",
253 // Template class instantiations.
254 R"cpp(
255 template <typename T>
256 class [[F^oo]] {
257 public:
258 T foo(T arg, T& ref, T* ptr) {
259 T value;
260 int number = 42;
261 value = (T)number;
262 value = static_cast<T>(number);
263 return value;
265 static void foo(T value) {}
266 T member;
269 template <typename T>
270 void func() {
271 [[F^oo]]<T> obj;
272 obj.member = T();
273 [[Foo]]<T>::foo();
276 void test() {
277 [[F^oo]]<int> i;
278 i.member = 0;
279 [[F^oo]]<int>::foo(0);
281 [[F^oo]]<bool> b;
282 b.member = false;
283 [[F^oo]]<bool>::foo(false);
285 )cpp",
287 // Template class methods.
288 R"cpp(
289 template <typename T>
290 class A {
291 public:
292 void [[f^oo]]() {}
295 void func() {
296 A<int>().[[f^oo]]();
297 A<double>().[[f^oo]]();
298 A<float>().[[f^oo]]();
300 )cpp",
302 // Templated class specialization.
303 R"cpp(
304 template<typename T, typename U=bool>
305 class [[Foo^]];
307 template<typename T, typename U>
308 class [[Foo^]] {};
310 template<typename T=int, typename U>
311 class [[Foo^]];
312 )cpp",
313 R"cpp(
314 template<typename T=float, typename U=int>
315 class [[Foo^]];
317 template<typename T, typename U>
318 class [[Foo^]] {};
319 )cpp",
321 // Function template specialization.
322 R"cpp(
323 template<typename T=int, typename U=bool>
324 U [[foo^]]();
326 template<typename T, typename U>
327 U [[foo^]]() {};
328 )cpp",
329 R"cpp(
330 template<typename T, typename U>
331 U [[foo^]]() {};
333 template<typename T=int, typename U=bool>
334 U [[foo^]]();
335 )cpp",
336 R"cpp(
337 template<typename T=int, typename U=bool>
338 U [[foo^]]();
340 template<typename T, typename U>
341 U [[foo^]]();
342 )cpp",
343 R"cpp(
344 template <typename T>
345 void [[f^oo]](T t);
347 template <>
348 void [[f^oo]](int a);
350 void test() {
351 [[f^oo]]<double>(1);
353 )cpp",
355 // Variable template.
356 R"cpp(
357 template <typename T, int U>
358 bool [[F^oo]] = true;
360 // Explicit template specialization
361 template <>
362 bool [[F^oo]]<int, 0> = false;
364 // Partial template specialization
365 template <typename T>
366 bool [[F^oo]]<T, 1> = false;
368 void foo() {
369 // Ref to the explicit template specialization
370 [[F^oo]]<int, 0>;
371 // Ref to the primary template.
372 [[F^oo]]<double, 2>;
374 )cpp",
376 // Complicated class type.
377 R"cpp(
378 // Forward declaration.
379 class [[Fo^o]];
380 class Baz {
381 virtual int getValue() const = 0;
384 class [[F^oo]] : public Baz {
385 public:
386 [[F^oo]](int value = 0) : x(value) {}
388 [[F^oo]] &operator++(int);
390 bool operator<([[Foo]] const &rhs);
391 int getValue() const;
392 private:
393 int x;
396 void func() {
397 [[F^oo]] *Pointer = 0;
398 [[F^oo]] Variable = [[Foo]](10);
399 for ([[F^oo]] it; it < Variable; it++);
400 const [[F^oo]] *C = new [[Foo]]();
401 const_cast<[[F^oo]] *>(C)->getValue();
402 [[F^oo]] foo;
403 const Baz &BazReference = foo;
404 const Baz *BazPointer = &foo;
405 reinterpret_cast<const [[^Foo]] *>(BazPointer)->getValue();
406 static_cast<const [[^Foo]] &>(BazReference).getValue();
407 static_cast<const [[^Foo]] *>(BazPointer)->getValue();
409 )cpp",
411 // Static class member.
412 R"cpp(
413 struct Foo {
414 static Foo *[[Static^Member]];
417 Foo* Foo::[[Static^Member]] = nullptr;
419 void foo() {
420 Foo* Pointer = Foo::[[Static^Member]];
422 )cpp",
424 // Reference in lambda parameters.
425 R"cpp(
426 template <class T>
427 class function;
428 template <class R, class... ArgTypes>
429 class function<R(ArgTypes...)> {
430 public:
431 template <typename Functor>
432 function(Functor f) {}
434 function() {}
436 R operator()(ArgTypes...) const {}
439 namespace ns {
440 class [[Old]] {};
441 void f() {
442 function<void([[Old]])> func;
444 } // namespace ns
445 )cpp",
447 // Destructor explicit call.
448 R"cpp(
449 class [[F^oo]] {
450 public:
451 ~[[^Foo]]();
454 [[Foo^]]::~[[^Foo]]() {}
456 int main() {
457 [[Fo^o]] f;
458 f.~/*something*/[[^Foo]]();
459 f.~[[^Foo]]();
461 )cpp",
463 // Derived destructor explicit call.
464 R"cpp(
465 class [[Bas^e]] {};
466 class Derived : public [[Bas^e]] {};
468 int main() {
469 [[Bas^e]] *foo = new Derived();
470 foo->[[^Base]]::~[[^Base]]();
472 )cpp",
474 // CXXConstructor initializer list.
475 R"cpp(
476 class Baz {};
477 class Qux {
478 Baz [[F^oo]];
479 public:
480 Qux();
482 Qux::Qux() : [[F^oo]]() {}
483 )cpp",
485 // DeclRefExpr.
486 R"cpp(
487 class C {
488 public:
489 static int [[F^oo]];
492 int foo(int x);
493 #define MACRO(a) foo(a)
495 void func() {
496 C::[[F^oo]] = 1;
497 MACRO(C::[[Foo]]);
498 int y = C::[[F^oo]];
500 )cpp",
502 // Macros.
503 R"cpp(
504 // no rename inside macro body.
505 #define M1 foo
506 #define M2(x) x
507 int [[fo^o]]();
508 void boo(int);
510 void qoo() {
511 [[f^oo]]();
512 boo([[f^oo]]());
513 M1();
514 boo(M1());
515 M2([[f^oo]]());
516 M2(M1()); // foo is inside the nested macro body.
518 )cpp",
520 // MemberExpr in macros
521 R"cpp(
522 class Baz {
523 public:
524 int [[F^oo]];
526 int qux(int x);
527 #define MACRO(a) qux(a)
529 int main() {
530 Baz baz;
531 baz.[[F^oo]] = 1;
532 MACRO(baz.[[F^oo]]);
533 int y = baz.[[F^oo]];
535 )cpp",
537 // Fields in classes & partial and full specialiations.
538 R"cpp(
539 template<typename T>
540 struct Foo {
541 T [[Vari^able]] = 42;
544 void foo() {
545 Foo<int> f;
546 f.[[Varia^ble]] = 9000;
548 )cpp",
549 R"cpp(
550 template<typename T, typename U>
551 struct Foo {
552 T Variable[42];
553 U Another;
555 void bar() {}
558 template<typename T>
559 struct Foo<T, bool> {
560 T [[Var^iable]];
561 void bar() { ++[[Var^iable]]; }
564 void foo() {
565 Foo<unsigned, bool> f;
566 f.[[Var^iable]] = 9000;
568 )cpp",
569 R"cpp(
570 template<typename T, typename U>
571 struct Foo {
572 T Variable[42];
573 U Another;
575 void bar() {}
578 template<typename T>
579 struct Foo<T, bool> {
580 T Variable;
581 void bar() { ++Variable; }
584 template<>
585 struct Foo<unsigned, bool> {
586 unsigned [[Var^iable]];
587 void bar() { ++[[Var^iable]]; }
590 void foo() {
591 Foo<unsigned, bool> f;
592 f.[[Var^iable]] = 9000;
594 )cpp",
595 // Static fields.
596 R"cpp(
597 struct Foo {
598 static int [[Var^iable]];
601 int Foo::[[Var^iable]] = 42;
603 void foo() {
604 int LocalInt = Foo::[[Var^iable]];
606 )cpp",
607 R"cpp(
608 template<typename T>
609 struct Foo {
610 static T [[Var^iable]];
613 template <>
614 int Foo<int>::[[Var^iable]] = 42;
616 template <>
617 bool Foo<bool>::[[Var^iable]] = true;
619 void foo() {
620 int LocalInt = Foo<int>::[[Var^iable]];
621 bool LocalBool = Foo<bool>::[[Var^iable]];
623 )cpp",
625 // Template parameters.
626 R"cpp(
627 template <typename [[^T]]>
628 class Foo {
629 [[T^]] foo([[T^]] arg, [[T^]]& ref, [[^T]]* ptr) {
630 [[T]] value;
631 int number = 42;
632 value = ([[T^]])number;
633 value = static_cast<[[^T]]>(number);
634 return value;
636 static void foo([[T^]] value) {}
637 [[T^]] member;
639 )cpp",
641 // Typedef.
642 R"cpp(
643 namespace ns {
644 class basic_string {};
645 typedef basic_string [[s^tring]];
646 } // namespace ns
648 ns::[[s^tring]] foo();
649 )cpp",
651 // Variable.
652 R"cpp(
653 namespace A {
654 int [[F^oo]];
656 int Foo;
657 int Qux = Foo;
658 int Baz = A::[[^Foo]];
659 void fun() {
660 struct {
661 int Foo;
662 } b = {100};
663 int Foo = 100;
664 Baz = Foo;
666 extern int Foo;
667 Baz = Foo;
668 Foo = A::[[F^oo]] + Baz;
669 A::[[Fo^o]] = b.Foo;
671 Foo = b.Foo;
673 )cpp",
675 // Namespace alias.
676 R"cpp(
677 namespace a { namespace b { void foo(); } }
678 namespace [[^x]] = a::b;
679 void bar() {
680 [[x^]]::foo();
682 )cpp",
684 // Enum.
685 R"cpp(
686 enum [[C^olor]] { Red, Green, Blue };
687 void foo() {
688 [[C^olor]] c;
689 c = [[C^olor]]::Blue;
691 )cpp",
693 // Scoped enum.
694 R"cpp(
695 enum class [[K^ind]] { ABC };
696 void ff() {
697 [[K^ind]] s;
698 s = [[K^ind]]::ABC;
700 )cpp",
702 // Template class in template argument list.
703 R"cpp(
704 template<typename T>
705 class [[Fo^o]] {};
706 template <template<typename> class Z> struct Bar { };
707 template <> struct Bar<[[F^oo]]> {};
708 )cpp",
710 // Designated initializer.
711 R"cpp(
712 struct Bar {
713 int [[Fo^o]];
715 Bar bar { .[[^Foo]] = 42 };
716 )cpp",
718 // Nested designated initializer.
719 R"cpp(
720 struct Baz {
721 int Field;
723 struct Bar {
724 Baz [[Fo^o]];
726 // FIXME: v selecting here results in renaming Field.
727 Bar bar { .[[Foo]].Field = 42 };
728 )cpp",
729 R"cpp(
730 struct Baz {
731 int [[Fiel^d]];
733 struct Bar {
734 Baz Foo;
736 Bar bar { .Foo.[[^Field]] = 42 };
737 )cpp",
739 // Templated alias.
740 R"cpp(
741 template <typename T>
742 class X { T t; };
744 template <typename T>
745 using [[Fo^o]] = X<T>;
747 void bar() {
748 [[Fo^o]]<int> Bar;
750 )cpp",
752 // Alias.
753 R"cpp(
754 class X {};
755 using [[F^oo]] = X;
757 void bar() {
758 [[Fo^o]] Bar;
760 )cpp",
762 // Alias within a namespace.
763 R"cpp(
764 namespace x { class X {}; }
765 namespace ns {
766 using [[Fo^o]] = x::X;
769 void bar() {
770 ns::[[Fo^o]] Bar;
772 )cpp",
774 // Alias within macros.
775 R"cpp(
776 namespace x { class Old {}; }
777 namespace ns {
778 #define REF(alias) alias alias_var;
780 #define ALIAS(old) \
781 using old##Alias = x::old; \
782 REF(old##Alias);
784 ALIAS(Old);
786 [[Old^Alias]] old_alias;
789 void bar() {
790 ns::[[Old^Alias]] Bar;
792 )cpp",
794 // User defined conversion.
795 R"cpp(
796 class [[F^oo]] {
797 public:
798 [[F^oo]]() {}
801 class Baz {
802 public:
803 operator [[F^oo]]() {
804 return [[F^oo]]();
808 int main() {
809 Baz boo;
810 [[F^oo]] foo = static_cast<[[F^oo]]>(boo);
812 )cpp",
814 // ObjC, should not crash.
815 R"cpp(
816 @interface ObjC {
817 char [[da^ta]];
818 } @end
819 )cpp",
821 // Issue 170: Rename symbol introduced by UsingDecl
822 R"cpp(
823 namespace ns { void [[f^oo]](); }
825 using ns::[[f^oo]];
827 void f() {
828 [[f^oo]]();
829 auto p = &[[f^oo]];
831 )cpp",
833 // Issue 170: using decl that imports multiple overloads
834 // -> Only the overload under the cursor is renamed
835 R"cpp(
836 namespace ns { int [[^foo]](int); char foo(char); }
837 using ns::[[foo]];
838 void f() {
839 [[^foo]](42);
840 foo('x');
842 )cpp",
844 // ObjC class with a category.
845 R"cpp(
846 @interface [[Fo^o]]
847 @end
848 @implementation [[F^oo]]
849 @end
850 @interface [[Fo^o]] (Category)
851 @end
852 @implementation [[F^oo]] (Category)
853 @end
855 void func([[Fo^o]] *f) {}
856 )cpp",
858 llvm::StringRef NewName = "NewName";
859 for (llvm::StringRef T : Tests) {
860 SCOPED_TRACE(T);
861 Annotations Code(T);
862 auto TU = TestTU::withCode(Code.code());
863 TU.ExtraArgs.push_back("-xobjective-c++");
864 auto AST = TU.build();
865 auto Index = TU.index();
866 for (const auto &RenamePos : Code.points()) {
867 auto RenameResult =
868 rename({RenamePos, NewName, AST, testPath(TU.Filename),
869 getVFSFromAST(AST), Index.get()});
870 ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError();
871 ASSERT_EQ(1u, RenameResult->GlobalChanges.size());
872 EXPECT_EQ(
873 applyEdits(std::move(RenameResult->GlobalChanges)).front().second,
874 expectedResult(Code, NewName));
879 TEST(RenameTest, Renameable) {
880 struct Case {
881 const char *Code;
882 const char* ErrorMessage; // null if no error
883 bool IsHeaderFile;
884 llvm::StringRef NewName = "MockName";
886 const bool HeaderFile = true;
887 Case Cases[] = {
888 {R"cpp(// allow -- function-local
889 void f(int [[Lo^cal]]) {
890 [[Local]] = 2;
892 )cpp",
893 nullptr, HeaderFile},
895 {R"cpp(// disallow -- symbol in anonymous namespace in header is not indexable.
896 namespace {
897 class Unin^dexable {};
899 )cpp",
900 "not eligible for indexing", HeaderFile},
902 {R"cpp(// disallow -- namespace symbol isn't supported
903 namespace n^s {}
904 )cpp",
905 "not a supported kind", HeaderFile},
907 {R"cpp(// disallow - category rename.
908 @interface Foo
909 @end
910 @interface Foo (Cate^gory)
911 @end
912 )cpp",
913 "Cannot rename symbol: there is no symbol at the given location",
914 HeaderFile},
917 R"cpp(
918 #define MACRO 1
919 int s = MAC^RO;
920 )cpp",
921 "not a supported kind", HeaderFile},
924 R"cpp(
925 struct X { X operator++(int); };
926 void f(X x) {x+^+;})cpp",
927 "no symbol", HeaderFile},
929 {R"cpp(// disallow rename on non-normal identifiers.
930 @interface Foo {}
931 -(int) fo^o:(int)x; // Token is an identifier, but declaration name isn't a simple identifier.
932 @end
933 )cpp",
934 "not a supported kind", HeaderFile},
935 {R"cpp(
936 void foo(int);
937 void foo(char);
938 template <typename T> void f(T t) {
939 fo^o(t);
940 })cpp",
941 "multiple symbols", !HeaderFile},
943 {R"cpp(// disallow rename on unrelated token.
944 cl^ass Foo {};
945 )cpp",
946 "no symbol", !HeaderFile},
948 {R"cpp(// disallow rename on unrelated token.
949 temp^late<typename T>
950 class Foo {};
951 )cpp",
952 "no symbol", !HeaderFile},
954 {R"cpp(
955 namespace {
956 int Conflict;
957 int Va^r;
959 )cpp",
960 "conflict", !HeaderFile, "Conflict"},
962 {R"cpp(
963 int Conflict;
964 int Va^r;
965 )cpp",
966 "conflict", !HeaderFile, "Conflict"},
968 {R"cpp(
969 class Foo {
970 int Conflict;
971 int Va^r;
973 )cpp",
974 "conflict", !HeaderFile, "Conflict"},
976 {R"cpp(
977 enum E {
978 Conflict,
979 Fo^o,
981 )cpp",
982 "conflict", !HeaderFile, "Conflict"},
984 {R"cpp(
985 int Conflict;
986 enum E { // transparent context.
987 F^oo,
989 )cpp",
990 "conflict", !HeaderFile, "Conflict"},
992 {R"cpp(
993 void func() {
994 bool Whatever;
995 int V^ar;
996 char Conflict;
998 )cpp",
999 "conflict", !HeaderFile, "Conflict"},
1001 {R"cpp(
1002 void func() {
1003 if (int Conflict = 42) {
1004 int V^ar;
1007 )cpp",
1008 "conflict", !HeaderFile, "Conflict"},
1010 {R"cpp(
1011 void func() {
1012 if (int Conflict = 42) {
1013 } else {
1014 bool V^ar;
1017 )cpp",
1018 "conflict", !HeaderFile, "Conflict"},
1020 {R"cpp(
1021 void func() {
1022 if (int V^ar = 42) {
1023 } else {
1024 bool Conflict;
1027 )cpp",
1028 "conflict", !HeaderFile, "Conflict"},
1030 {R"cpp(
1031 void func() {
1032 while (int V^ar = 10) {
1033 bool Conflict = true;
1036 )cpp",
1037 "conflict", !HeaderFile, "Conflict"},
1039 {R"cpp(
1040 void func() {
1041 for (int Something = 9000, Anything = 14, Conflict = 42; Anything > 9;
1042 ++Something) {
1043 int V^ar;
1046 )cpp",
1047 "conflict", !HeaderFile, "Conflict"},
1049 {R"cpp(
1050 void func() {
1051 for (int V^ar = 14, Conflict = 42;;) {
1054 )cpp",
1055 "conflict", !HeaderFile, "Conflict"},
1057 {R"cpp(
1058 void func(int Conflict) {
1059 bool V^ar;
1061 )cpp",
1062 "conflict", !HeaderFile, "Conflict"},
1064 {R"cpp(
1065 void func(int Var);
1067 void func(int V^ar) {
1068 bool Conflict;
1070 )cpp",
1071 "conflict", !HeaderFile, "Conflict"},
1073 {R"cpp(// No conflict: only forward declaration's argument is renamed.
1074 void func(int [[V^ar]]);
1076 void func(int Var) {
1077 bool Conflict;
1079 )cpp",
1080 nullptr, !HeaderFile, "Conflict"},
1082 {R"cpp(
1083 void func(int V^ar, int Conflict) {
1085 )cpp",
1086 "conflict", !HeaderFile, "Conflict"},
1088 {R"cpp(
1089 void func(int);
1090 void [[o^therFunc]](double);
1091 )cpp",
1092 nullptr, !HeaderFile, "func"},
1093 {R"cpp(
1094 struct S {
1095 void func(int);
1096 void [[o^therFunc]](double);
1098 )cpp",
1099 nullptr, !HeaderFile, "func"},
1101 {R"cpp(
1102 int V^ar;
1103 )cpp",
1104 "\"const\" is a keyword", !HeaderFile, "const"},
1106 {R"cpp(// Trying to rename into the same name, SameName == SameName.
1107 void func() {
1108 int S^ameName;
1110 )cpp",
1111 "new name is the same", !HeaderFile, "SameName"},
1112 {R"cpp(// Ensure it doesn't associate base specifier with base name.
1113 struct A {};
1114 struct B : priv^ate A {};
1115 )cpp",
1116 "Cannot rename symbol: there is no symbol at the given location", false},
1117 {R"cpp(// Ensure it doesn't associate base specifier with base name.
1118 /*error-ok*/
1119 struct A {
1120 A() : inva^lid(0) {}
1122 )cpp",
1123 "no symbol", false},
1125 {R"cpp(// FIXME we probably want to rename both overloads here,
1126 // but renaming currently assumes there's only a
1127 // single canonical declaration.
1128 namespace ns { int foo(int); char foo(char); }
1129 using ns::^foo;
1130 )cpp",
1131 "there are multiple symbols at the given location", !HeaderFile},
1134 for (const auto& Case : Cases) {
1135 SCOPED_TRACE(Case.Code);
1136 Annotations T(Case.Code);
1137 TestTU TU = TestTU::withCode(T.code());
1138 TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
1139 if (Case.IsHeaderFile) {
1140 // We open the .h file as the main file.
1141 TU.Filename = "test.h";
1142 // Parsing the .h file as C++ include.
1143 TU.ExtraArgs.push_back("-xobjective-c++-header");
1145 auto AST = TU.build();
1146 llvm::StringRef NewName = Case.NewName;
1147 auto Results = rename({T.point(), NewName, AST, testPath(TU.Filename)});
1148 bool WantRename = true;
1149 if (T.ranges().empty())
1150 WantRename = false;
1151 if (!WantRename) {
1152 assert(Case.ErrorMessage && "Error message must be set!");
1153 EXPECT_FALSE(Results)
1154 << "expected rename returned an error: " << T.code();
1155 auto ActualMessage = llvm::toString(Results.takeError());
1156 EXPECT_THAT(ActualMessage, testing::HasSubstr(Case.ErrorMessage));
1157 } else {
1158 EXPECT_TRUE(bool(Results)) << "rename returned an error: "
1159 << llvm::toString(Results.takeError());
1160 EXPECT_EQ(Results->LocalChanges, T.ranges());
1165 MATCHER_P(newText, T, "") { return arg.newText == T; }
1167 TEST(RenameTest, IndexMergeMainFile) {
1168 Annotations Code("int ^x();");
1169 TestTU TU = TestTU::withCode(Code.code());
1170 TU.Filename = "main.cc";
1171 auto AST = TU.build();
1173 auto Main = testPath("main.cc");
1174 auto InMemFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
1175 InMemFS->addFile(testPath("main.cc"), 0,
1176 llvm::MemoryBuffer::getMemBuffer(Code.code()));
1177 InMemFS->addFile(testPath("other.cc"), 0,
1178 llvm::MemoryBuffer::getMemBuffer(Code.code()));
1180 auto Rename = [&](const SymbolIndex *Idx) {
1181 RenameInputs Inputs{Code.point(),
1182 "xPrime",
1183 AST,
1184 Main,
1185 Idx ? createOverlay(getVFSFromAST(AST), InMemFS)
1186 : nullptr,
1187 Idx,
1188 RenameOptions()};
1189 auto Results = rename(Inputs);
1190 EXPECT_TRUE(bool(Results)) << llvm::toString(Results.takeError());
1191 return std::move(*Results);
1194 // We do not expect to see duplicated edits from AST vs index.
1195 auto Results = Rename(TU.index().get());
1196 EXPECT_THAT(Results.GlobalChanges.keys(), ElementsAre(Main));
1197 EXPECT_THAT(Results.GlobalChanges[Main].asTextEdits(),
1198 ElementsAre(newText("xPrime")));
1200 // Sanity check: we do expect to see index results!
1201 TU.Filename = "other.cc";
1202 Results = Rename(TU.index().get());
1203 EXPECT_THAT(Results.GlobalChanges.keys(),
1204 UnorderedElementsAre(Main, testPath("other.cc")));
1206 #ifdef CLANGD_PATH_CASE_INSENSITIVE
1207 // On case-insensitive systems, no duplicates if AST vs index case differs.
1208 // https://github.com/clangd/clangd/issues/665
1209 TU.Filename = "MAIN.CC";
1210 Results = Rename(TU.index().get());
1211 EXPECT_THAT(Results.GlobalChanges.keys(), ElementsAre(Main));
1212 EXPECT_THAT(Results.GlobalChanges[Main].asTextEdits(),
1213 ElementsAre(newText("xPrime")));
1214 #endif
1217 TEST(RenameTest, MainFileReferencesOnly) {
1218 // filter out references not from main file.
1219 llvm::StringRef Test =
1220 R"cpp(
1221 void test() {
1222 int [[fo^o]] = 1;
1223 // rename references not from main file are not included.
1224 #include "foo.inc"
1225 })cpp";
1227 Annotations Code(Test);
1228 auto TU = TestTU::withCode(Code.code());
1229 TU.AdditionalFiles["foo.inc"] = R"cpp(
1230 #define Macro(X) X
1231 &Macro(foo);
1232 &foo;
1233 )cpp";
1234 auto AST = TU.build();
1235 llvm::StringRef NewName = "abcde";
1237 auto RenameResult =
1238 rename({Code.point(), NewName, AST, testPath(TU.Filename)});
1239 ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError() << Code.point();
1240 ASSERT_EQ(1u, RenameResult->GlobalChanges.size());
1241 EXPECT_EQ(applyEdits(std::move(RenameResult->GlobalChanges)).front().second,
1242 expectedResult(Code, NewName));
1245 TEST(RenameTest, NoRenameOnSymbolsFromSystemHeaders) {
1246 llvm::StringRef Test =
1247 R"cpp(
1248 #include <cstdlib>
1249 #include <system>
1251 SystemSym^bol abc;
1253 void foo() { at^oi("9000"); }
1254 )cpp";
1256 Annotations Code(Test);
1257 auto TU = TestTU::withCode(Code.code());
1258 TU.AdditionalFiles["system"] = R"cpp(
1259 class SystemSymbol {};
1260 )cpp";
1261 TU.AdditionalFiles["cstdlib"] = R"cpp(
1262 int atoi(const char *str);
1263 )cpp";
1264 TU.ExtraArgs = {"-isystem", testRoot()};
1265 auto AST = TU.build();
1266 llvm::StringRef NewName = "abcde";
1268 // Clangd will not allow renaming symbols from the system headers for
1269 // correctness.
1270 for (auto &Point : Code.points()) {
1271 auto Results = rename({Point, NewName, AST, testPath(TU.Filename)});
1272 EXPECT_FALSE(Results) << "expected rename returned an error: "
1273 << Code.code();
1274 auto ActualMessage = llvm::toString(Results.takeError());
1275 EXPECT_THAT(ActualMessage, testing::HasSubstr("not a supported kind"));
1279 TEST(RenameTest, ProtobufSymbolIsExcluded) {
1280 Annotations Code("Prot^obuf buf;");
1281 auto TU = TestTU::withCode(Code.code());
1282 TU.HeaderCode =
1283 R"cpp(// Generated by the protocol buffer compiler. DO NOT EDIT!
1284 class Protobuf {};
1285 )cpp";
1286 TU.HeaderFilename = "protobuf.pb.h";
1287 auto AST = TU.build();
1288 auto Results = rename({Code.point(), "newName", AST, testPath(TU.Filename)});
1289 EXPECT_FALSE(Results);
1290 EXPECT_THAT(llvm::toString(Results.takeError()),
1291 testing::HasSubstr("not a supported kind"));
1294 TEST(RenameTest, PrepareRename) {
1295 Annotations FooH("void func();");
1296 Annotations FooCC(R"cpp(
1297 #include "foo.h"
1298 void [[fu^nc]]() {}
1299 )cpp");
1300 std::string FooHPath = testPath("foo.h");
1301 std::string FooCCPath = testPath("foo.cc");
1302 MockFS FS;
1303 FS.Files[FooHPath] = std::string(FooH.code());
1304 FS.Files[FooCCPath] = std::string(FooCC.code());
1306 auto ServerOpts = ClangdServer::optsForTest();
1307 ServerOpts.BuildDynamicSymbolIndex = true;
1309 trace::TestTracer Tracer;
1310 MockCompilationDatabase CDB;
1311 ClangdServer Server(CDB, FS, ServerOpts);
1312 runAddDocument(Server, FooHPath, FooH.code());
1313 runAddDocument(Server, FooCCPath, FooCC.code());
1315 auto Results = runPrepareRename(Server, FooCCPath, FooCC.point(),
1316 /*NewName=*/std::nullopt, {});
1317 // Verify that for multi-file rename, we only return main-file occurrences.
1318 ASSERT_TRUE(bool(Results)) << Results.takeError();
1319 // We don't know the result is complete in prepareRename (passing a nullptr
1320 // index internally), so GlobalChanges should be empty.
1321 EXPECT_TRUE(Results->GlobalChanges.empty());
1322 EXPECT_THAT(FooCC.ranges(),
1323 testing::UnorderedElementsAreArray(Results->LocalChanges));
1325 // Name validation.
1326 Results = runPrepareRename(Server, FooCCPath, FooCC.point(),
1327 /*NewName=*/std::string("int"), {});
1328 EXPECT_FALSE(Results);
1329 EXPECT_THAT(llvm::toString(Results.takeError()),
1330 testing::HasSubstr("keyword"));
1331 EXPECT_THAT(Tracer.takeMetric("rename_name_invalid", "Keywords"),
1332 ElementsAre(1));
1334 for (std::string BadIdent : {"foo!bar", "123foo", "😀@"}) {
1335 Results = runPrepareRename(Server, FooCCPath, FooCC.point(),
1336 /*NewName=*/BadIdent, {});
1337 EXPECT_FALSE(Results);
1338 EXPECT_THAT(llvm::toString(Results.takeError()),
1339 testing::HasSubstr("identifier"));
1340 EXPECT_THAT(Tracer.takeMetric("rename_name_invalid", "BadIdentifier"),
1341 ElementsAre(1));
1343 for (std::string GoodIdent : {"fooBar", "__foo$", "😀"}) {
1344 Results = runPrepareRename(Server, FooCCPath, FooCC.point(),
1345 /*NewName=*/GoodIdent, {});
1346 EXPECT_TRUE(bool(Results));
1350 TEST(CrossFileRenameTests, DirtyBuffer) {
1351 Annotations FooCode("class [[Foo]] {};");
1352 std::string FooPath = testPath("foo.cc");
1353 Annotations FooDirtyBuffer("class [[Foo]] {};\n// this is dirty buffer");
1354 Annotations BarCode("void [[Bar]]() {}");
1355 std::string BarPath = testPath("bar.cc");
1356 // Build the index, the index has "Foo" references from foo.cc and "Bar"
1357 // references from bar.cc.
1358 FileSymbols FSymbols(IndexContents::All);
1359 FSymbols.update(FooPath, nullptr, buildRefSlab(FooCode, "Foo", FooPath),
1360 nullptr, false);
1361 FSymbols.update(BarPath, nullptr, buildRefSlab(BarCode, "Bar", BarPath),
1362 nullptr, false);
1363 auto Index = FSymbols.buildIndex(IndexType::Light);
1365 Annotations MainCode("class [[Fo^o]] {};");
1366 auto MainFilePath = testPath("main.cc");
1367 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemFS =
1368 new llvm::vfs::InMemoryFileSystem;
1369 InMemFS->addFile(FooPath, 0,
1370 llvm::MemoryBuffer::getMemBuffer(FooDirtyBuffer.code()));
1372 // Run rename on Foo, there is a dirty buffer for foo.cc, rename should
1373 // respect the dirty buffer.
1374 TestTU TU = TestTU::withCode(MainCode.code());
1375 auto AST = TU.build();
1376 llvm::StringRef NewName = "newName";
1377 auto Results =
1378 rename({MainCode.point(), NewName, AST, MainFilePath,
1379 createOverlay(getVFSFromAST(AST), InMemFS), Index.get()});
1380 ASSERT_TRUE(bool(Results)) << Results.takeError();
1381 EXPECT_THAT(
1382 applyEdits(std::move(Results->GlobalChanges)),
1383 UnorderedElementsAre(
1384 Pair(Eq(FooPath), Eq(expectedResult(FooDirtyBuffer, NewName))),
1385 Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName)))));
1387 // Run rename on Bar, there is no dirty buffer for the affected file bar.cc,
1388 // so we should read file content from VFS.
1389 MainCode = Annotations("void [[Bar]]() { [[B^ar]](); }");
1390 TU = TestTU::withCode(MainCode.code());
1391 // Set a file "bar.cc" on disk.
1392 TU.AdditionalFiles["bar.cc"] = std::string(BarCode.code());
1393 AST = TU.build();
1394 Results = rename({MainCode.point(), NewName, AST, MainFilePath,
1395 createOverlay(getVFSFromAST(AST), InMemFS), Index.get()});
1396 ASSERT_TRUE(bool(Results)) << Results.takeError();
1397 EXPECT_THAT(
1398 applyEdits(std::move(Results->GlobalChanges)),
1399 UnorderedElementsAre(
1400 Pair(Eq(BarPath), Eq(expectedResult(BarCode, NewName))),
1401 Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName)))));
1403 // Run rename on a pagination index which couldn't return all refs in one
1404 // request, we reject rename on this case.
1405 class PaginationIndex : public SymbolIndex {
1406 bool refs(const RefsRequest &Req,
1407 llvm::function_ref<void(const Ref &)> Callback) const override {
1408 return true; // has more references
1411 bool fuzzyFind(
1412 const FuzzyFindRequest &Req,
1413 llvm::function_ref<void(const Symbol &)> Callback) const override {
1414 return false;
1416 void
1417 lookup(const LookupRequest &Req,
1418 llvm::function_ref<void(const Symbol &)> Callback) const override {}
1420 void relations(const RelationsRequest &Req,
1421 llvm::function_ref<void(const SymbolID &, const Symbol &)>
1422 Callback) const override {}
1424 llvm::unique_function<IndexContents(llvm::StringRef) const>
1425 indexedFiles() const override {
1426 return [](llvm::StringRef) { return IndexContents::None; };
1429 size_t estimateMemoryUsage() const override { return 0; }
1430 } PIndex;
1431 Results = rename({MainCode.point(), NewName, AST, MainFilePath,
1432 createOverlay(getVFSFromAST(AST), InMemFS), &PIndex});
1433 EXPECT_FALSE(Results);
1434 EXPECT_THAT(llvm::toString(Results.takeError()),
1435 testing::HasSubstr("too many occurrences"));
1438 TEST(CrossFileRenameTests, DeduplicateRefsFromIndex) {
1439 auto MainCode = Annotations("int [[^x]] = 2;");
1440 auto MainFilePath = testPath("main.cc");
1441 auto BarCode = Annotations("int [[x]];");
1442 auto BarPath = testPath("bar.cc");
1443 auto TU = TestTU::withCode(MainCode.code());
1444 // Set a file "bar.cc" on disk.
1445 TU.AdditionalFiles["bar.cc"] = std::string(BarCode.code());
1446 auto AST = TU.build();
1447 std::string BarPathURI = URI::create(BarPath).toString();
1448 Ref XRefInBarCC = refWithRange(BarCode.range(), BarPathURI);
1449 // The index will return duplicated refs, our code should be robost to handle
1450 // it.
1451 class DuplicatedXRefIndex : public SymbolIndex {
1452 public:
1453 DuplicatedXRefIndex(const Ref &ReturnedRef) : ReturnedRef(ReturnedRef) {}
1454 bool refs(const RefsRequest &Req,
1455 llvm::function_ref<void(const Ref &)> Callback) const override {
1456 // Return two duplicated refs.
1457 Callback(ReturnedRef);
1458 Callback(ReturnedRef);
1459 return false;
1462 bool fuzzyFind(const FuzzyFindRequest &,
1463 llvm::function_ref<void(const Symbol &)>) const override {
1464 return false;
1466 void lookup(const LookupRequest &,
1467 llvm::function_ref<void(const Symbol &)>) const override {}
1469 void relations(const RelationsRequest &,
1470 llvm::function_ref<void(const SymbolID &, const Symbol &)>)
1471 const override {}
1473 llvm::unique_function<IndexContents(llvm::StringRef) const>
1474 indexedFiles() const override {
1475 return [](llvm::StringRef) { return IndexContents::None; };
1478 size_t estimateMemoryUsage() const override { return 0; }
1479 Ref ReturnedRef;
1480 } DIndex(XRefInBarCC);
1481 llvm::StringRef NewName = "newName";
1482 auto Results = rename({MainCode.point(), NewName, AST, MainFilePath,
1483 getVFSFromAST(AST), &DIndex});
1484 ASSERT_TRUE(bool(Results)) << Results.takeError();
1485 EXPECT_THAT(
1486 applyEdits(std::move(Results->GlobalChanges)),
1487 UnorderedElementsAre(
1488 Pair(Eq(BarPath), Eq(expectedResult(BarCode, NewName))),
1489 Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName)))));
1492 TEST(CrossFileRenameTests, WithUpToDateIndex) {
1493 MockCompilationDatabase CDB;
1494 CDB.ExtraClangFlags = {"-xobjective-c++"};
1495 // rename is runnning on all "^" points in FooH, and "[[]]" ranges are the
1496 // expected rename occurrences.
1497 struct Case {
1498 llvm::StringRef FooH;
1499 llvm::StringRef FooCC;
1500 } Cases[] = {
1502 // classes.
1503 R"cpp(
1504 class [[Fo^o]] {
1505 [[Foo]]();
1506 ~[[Foo]]();
1508 )cpp",
1509 R"cpp(
1510 #include "foo.h"
1511 [[Foo]]::[[Foo]]() {}
1512 [[Foo]]::~[[Foo]]() {}
1514 void func() {
1515 [[Foo]] foo;
1517 )cpp",
1520 // class templates.
1521 R"cpp(
1522 template <typename T>
1523 class [[Foo]] {};
1524 // FIXME: explicit template specializations are not supported due the
1525 // clangd index limitations.
1526 template <>
1527 class Foo<double> {};
1528 )cpp",
1529 R"cpp(
1530 #include "foo.h"
1531 void func() {
1532 [[F^oo]]<int> foo;
1534 )cpp",
1537 // class methods.
1538 R"cpp(
1539 class Foo {
1540 void [[f^oo]]();
1542 )cpp",
1543 R"cpp(
1544 #include "foo.h"
1545 void Foo::[[foo]]() {}
1547 void func(Foo* p) {
1548 p->[[foo]]();
1550 )cpp",
1553 // virtual methods.
1554 R"cpp(
1555 class Base {
1556 virtual void [[foo]]();
1558 class Derived1 : public Base {
1559 void [[f^oo]]() override;
1561 class NotDerived {
1562 void foo() {};
1564 )cpp",
1565 R"cpp(
1566 #include "foo.h"
1567 void Base::[[foo]]() {}
1568 void Derived1::[[foo]]() {}
1570 class Derived2 : public Derived1 {
1571 void [[foo]]() override {};
1574 void func(Base* b, Derived1* d1,
1575 Derived2* d2, NotDerived* nd) {
1576 b->[[foo]]();
1577 d1->[[foo]]();
1578 d2->[[foo]]();
1579 nd->foo();
1581 )cpp",
1583 {// virtual templated method
1584 R"cpp(
1585 template <typename> class Foo { virtual void [[m]](); };
1586 class Bar : Foo<int> { void [[^m]]() override; };
1587 )cpp",
1588 R"cpp(
1589 #include "foo.h"
1591 template<typename T> void Foo<T>::[[m]]() {}
1592 // FIXME: not renamed as the index doesn't see this as an override of
1593 // the canonical Foo<T>::m().
1594 // https://github.com/clangd/clangd/issues/1325
1595 class Baz : Foo<float> { void m() override; };
1596 )cpp"},
1598 // rename on constructor and destructor.
1599 R"cpp(
1600 class [[Foo]] {
1601 [[^Foo]]();
1602 ~[[Foo^]]();
1604 )cpp",
1605 R"cpp(
1606 #include "foo.h"
1607 [[Foo]]::[[Foo]]() {}
1608 [[Foo]]::~[[Foo]]() {}
1610 void func() {
1611 [[Foo]] foo;
1613 )cpp",
1616 // functions.
1617 R"cpp(
1618 void [[f^oo]]();
1619 )cpp",
1620 R"cpp(
1621 #include "foo.h"
1622 void [[foo]]() {}
1624 void func() {
1625 [[foo]]();
1627 )cpp",
1630 // typedefs.
1631 R"cpp(
1632 typedef int [[IN^T]];
1633 [[INT]] foo();
1634 )cpp",
1635 R"cpp(
1636 #include "foo.h"
1637 [[INT]] foo() {}
1638 )cpp",
1641 // usings.
1642 R"cpp(
1643 using [[I^NT]] = int;
1644 [[INT]] foo();
1645 )cpp",
1646 R"cpp(
1647 #include "foo.h"
1648 [[INT]] foo() {}
1649 )cpp",
1652 // variables.
1653 R"cpp(
1654 static const int [[VA^R]] = 123;
1655 )cpp",
1656 R"cpp(
1657 #include "foo.h"
1658 int s = [[VAR]];
1659 )cpp",
1662 // scope enums.
1663 R"cpp(
1664 enum class [[K^ind]] { ABC };
1665 )cpp",
1666 R"cpp(
1667 #include "foo.h"
1668 [[Kind]] ff() {
1669 return [[Kind]]::ABC;
1671 )cpp",
1674 // enum constants.
1675 R"cpp(
1676 enum class Kind { [[A^BC]] };
1677 )cpp",
1678 R"cpp(
1679 #include "foo.h"
1680 Kind ff() {
1681 return Kind::[[ABC]];
1683 )cpp",
1686 // Implicit references in macro expansions.
1687 R"cpp(
1688 class [[Fo^o]] {};
1689 #define FooFoo Foo
1690 #define FOO Foo
1691 )cpp",
1692 R"cpp(
1693 #include "foo.h"
1694 void bar() {
1695 [[Foo]] x;
1696 FOO y;
1697 FooFoo z;
1699 )cpp",
1702 // Objective-C classes.
1703 R"cpp(
1704 @interface [[Fo^o]]
1705 @end
1706 )cpp",
1707 R"cpp(
1708 #include "foo.h"
1709 @implementation [[Foo]]
1710 @end
1712 void func([[Foo]] *f) {}
1713 )cpp",
1717 trace::TestTracer Tracer;
1718 for (const auto &T : Cases) {
1719 SCOPED_TRACE(T.FooH);
1720 Annotations FooH(T.FooH);
1721 Annotations FooCC(T.FooCC);
1722 std::string FooHPath = testPath("foo.h");
1723 std::string FooCCPath = testPath("foo.cc");
1725 MockFS FS;
1726 FS.Files[FooHPath] = std::string(FooH.code());
1727 FS.Files[FooCCPath] = std::string(FooCC.code());
1729 auto ServerOpts = ClangdServer::optsForTest();
1730 ServerOpts.BuildDynamicSymbolIndex = true;
1731 ClangdServer Server(CDB, FS, ServerOpts);
1733 // Add all files to clangd server to make sure the dynamic index has been
1734 // built.
1735 runAddDocument(Server, FooHPath, FooH.code());
1736 runAddDocument(Server, FooCCPath, FooCC.code());
1738 llvm::StringRef NewName = "NewName";
1739 for (const auto &RenamePos : FooH.points()) {
1740 EXPECT_THAT(Tracer.takeMetric("rename_files"), SizeIs(0));
1741 auto FileEditsList =
1742 llvm::cantFail(runRename(Server, FooHPath, RenamePos, NewName, {}));
1743 EXPECT_THAT(Tracer.takeMetric("rename_files"), ElementsAre(2));
1744 EXPECT_THAT(
1745 applyEdits(std::move(FileEditsList.GlobalChanges)),
1746 UnorderedElementsAre(
1747 Pair(Eq(FooHPath), Eq(expectedResult(T.FooH, NewName))),
1748 Pair(Eq(FooCCPath), Eq(expectedResult(T.FooCC, NewName)))));
1753 TEST(CrossFileRenameTests, CrossFileOnLocalSymbol) {
1754 // cross-file rename should work for function-local symbols, even there is no
1755 // index provided.
1756 Annotations Code("void f(int [[abc]]) { [[a^bc]] = 3; }");
1757 auto TU = TestTU::withCode(Code.code());
1758 auto Path = testPath(TU.Filename);
1759 auto AST = TU.build();
1760 llvm::StringRef NewName = "newName";
1761 auto Results = rename({Code.point(), NewName, AST, Path});
1762 ASSERT_TRUE(bool(Results)) << Results.takeError();
1763 EXPECT_THAT(
1764 applyEdits(std::move(Results->GlobalChanges)),
1765 UnorderedElementsAre(Pair(Eq(Path), Eq(expectedResult(Code, NewName)))));
1768 TEST(CrossFileRenameTests, BuildRenameEdits) {
1769 Annotations Code("[[😂]]");
1770 auto LSPRange = Code.range();
1771 llvm::StringRef FilePath = "/test/TestTU.cpp";
1772 llvm::StringRef NewName = "abc";
1773 auto Edit = buildRenameEdit(FilePath, Code.code(), {LSPRange}, NewName);
1774 ASSERT_TRUE(bool(Edit)) << Edit.takeError();
1775 ASSERT_EQ(1UL, Edit->Replacements.size());
1776 EXPECT_EQ(FilePath, Edit->Replacements.begin()->getFilePath());
1777 EXPECT_EQ(4UL, Edit->Replacements.begin()->getLength());
1779 // Test invalid range.
1780 LSPRange.end = {10, 0}; // out of range
1781 Edit = buildRenameEdit(FilePath, Code.code(), {LSPRange}, NewName);
1782 EXPECT_FALSE(Edit);
1783 EXPECT_THAT(llvm::toString(Edit.takeError()),
1784 testing::HasSubstr("fail to convert"));
1786 // Normal ascii characters.
1787 Annotations T(R"cpp(
1788 [[range]]
1789 [[range]]
1790 [[range]]
1791 )cpp");
1792 Edit = buildRenameEdit(FilePath, T.code(), T.ranges(), NewName);
1793 ASSERT_TRUE(bool(Edit)) << Edit.takeError();
1794 EXPECT_EQ(applyEdits(FileEdits{{T.code(), std::move(*Edit)}}).front().second,
1795 expectedResult(T, NewName));
1798 TEST(CrossFileRenameTests, adjustRenameRanges) {
1799 // Ranges in IndexedCode indicate the indexed occurrences;
1800 // ranges in DraftCode indicate the expected mapped result, empty indicates
1801 // we expect no matched result found.
1802 struct {
1803 llvm::StringRef IndexedCode;
1804 llvm::StringRef DraftCode;
1805 } Tests[] = {
1807 // both line and column are changed, not a near miss.
1808 R"cpp(
1809 int [[x]] = 0;
1810 )cpp",
1811 R"cpp(
1812 // insert a line.
1813 double x = 0;
1814 )cpp",
1817 // subset.
1818 R"cpp(
1819 int [[x]] = 0;
1820 )cpp",
1821 R"cpp(
1822 int [[x]] = 0;
1823 {int x = 0; }
1824 )cpp",
1827 // shift columns.
1828 R"cpp(int [[x]] = 0; void foo(int x);)cpp",
1829 R"cpp(double [[x]] = 0; void foo(double x);)cpp",
1832 // shift lines.
1833 R"cpp(
1834 int [[x]] = 0;
1835 void foo(int x);
1836 )cpp",
1837 R"cpp(
1838 // insert a line.
1839 int [[x]] = 0;
1840 void foo(int x);
1841 )cpp",
1844 LangOptions LangOpts;
1845 LangOpts.CPlusPlus = true;
1846 for (const auto &T : Tests) {
1847 SCOPED_TRACE(T.DraftCode);
1848 Annotations Draft(T.DraftCode);
1849 auto ActualRanges = adjustRenameRanges(
1850 Draft.code(), "x", Annotations(T.IndexedCode).ranges(), LangOpts);
1851 if (!ActualRanges)
1852 EXPECT_THAT(Draft.ranges(), testing::IsEmpty());
1853 else
1854 EXPECT_THAT(Draft.ranges(),
1855 testing::UnorderedElementsAreArray(*ActualRanges));
1859 TEST(RangePatchingHeuristic, GetMappedRanges) {
1860 // ^ in LexedCode marks the ranges we expect to be mapped; no ^ indicates
1861 // there are no mapped ranges.
1862 struct {
1863 llvm::StringRef IndexedCode;
1864 llvm::StringRef LexedCode;
1865 } Tests[] = {
1867 // no lexed ranges.
1868 "[[]]",
1872 // both line and column are changed, not a near miss.
1873 R"([[]])",
1875 [[]]
1879 // subset.
1880 "[[]]",
1881 "^[[]] [[]]"
1884 // shift columns.
1885 "[[]] [[]]",
1886 " ^[[]] ^[[]] [[]]"
1890 [[]]
1892 [[]] [[]]
1895 // insert a line
1896 ^[[]]
1898 ^[[]] ^[[]]
1903 [[]]
1905 [[]] [[]]
1908 // insert a line
1909 ^[[]]
1910 ^[[]] ^[[]] // column is shifted.
1915 [[]]
1917 [[]] [[]]
1920 // insert a line
1921 [[]]
1923 [[]] [[]] // not mapped (both line and column are changed).
1928 [[]]
1929 [[]]
1931 [[]]
1932 [[]]
1937 // insert a new line
1938 ^[[]]
1939 ^[[]]
1940 [[]] // additional range
1941 ^[[]]
1942 ^[[]]
1943 [[]] // additional range
1947 // non-distinct result (two best results), not a near miss
1949 [[]]
1950 [[]]
1951 [[]]
1954 [[]]
1955 [[]]
1956 [[]]
1957 [[]]
1961 for (const auto &T : Tests) {
1962 SCOPED_TRACE(T.IndexedCode);
1963 auto Lexed = Annotations(T.LexedCode);
1964 auto LexedRanges = Lexed.ranges();
1965 std::vector<Range> ExpectedMatches;
1966 for (auto P : Lexed.points()) {
1967 auto Match = llvm::find_if(LexedRanges, [&P](const Range& R) {
1968 return R.start == P;
1970 ASSERT_NE(Match, LexedRanges.end());
1971 ExpectedMatches.push_back(*Match);
1974 auto Mapped =
1975 getMappedRanges(Annotations(T.IndexedCode).ranges(), LexedRanges);
1976 if (!Mapped)
1977 EXPECT_THAT(ExpectedMatches, IsEmpty());
1978 else
1979 EXPECT_THAT(ExpectedMatches, UnorderedElementsAreArray(*Mapped));
1983 TEST(CrossFileRenameTests, adjustmentCost) {
1984 struct {
1985 llvm::StringRef RangeCode;
1986 size_t ExpectedCost;
1987 } Tests[] = {
1990 $idx[[]]$lex[[]] // diff: 0
1996 $idx[[]]
1997 $lex[[]] // line diff: +1
1998 $idx[[]]
1999 $lex[[]] // line diff: +1
2000 $idx[[]]
2001 $lex[[]] // line diff: +1
2003 $idx[[]]
2005 $lex[[]] // line diff: +2
2007 1 + 1
2011 $idx[[]]
2012 $lex[[]] // line diff: +1
2013 $idx[[]]
2015 $lex[[]] // line diff: +2
2016 $idx[[]]
2019 $lex[[]] // line diff: +3
2021 1 + 1 + 1
2025 $idx[[]]
2028 $lex[[]] // line diff: +3
2029 $idx[[]]
2031 $lex[[]] // line diff: +2
2032 $idx[[]]
2033 $lex[[]] // line diff: +1
2035 3 + 1 + 1
2039 $idx[[]]
2040 $lex[[]] // line diff: +1
2041 $lex[[]] // line diff: -2
2043 $idx[[]]
2044 $idx[[]]
2047 $lex[[]] // line diff: +3
2049 1 + 3 + 5
2053 $idx[[]] $lex[[]] // column diff: +1
2054 $idx[[]]$lex[[]] // diff: 0
2060 $idx[[]]
2061 $lex[[]] // diff: +1
2062 $idx[[]] $lex[[]] // column diff: +1
2063 $idx[[]]$lex[[]] // diff: 0
2065 1 + 1 + 1
2069 $idx[[]] $lex[[]] // column diff: +1
2075 // column diffs: +1, +2, +3
2076 $idx[[]] $lex[[]] $idx[[]] $lex[[]] $idx[[]] $lex[[]]
2078 1 + 1 + 1,
2081 for (const auto &T : Tests) {
2082 SCOPED_TRACE(T.RangeCode);
2083 Annotations C(T.RangeCode);
2084 std::vector<size_t> MappedIndex;
2085 for (size_t I = 0; I < C.ranges("lex").size(); ++I)
2086 MappedIndex.push_back(I);
2087 EXPECT_EQ(renameRangeAdjustmentCost(C.ranges("idx"), C.ranges("lex"),
2088 MappedIndex),
2089 T.ExpectedCost);
2093 } // namespace
2094 } // namespace clangd
2095 } // namespace clang