[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / clang-tools-extra / clangd / unittests / RenameTests.cpp
blob9cbf59684fbc1079c3d73509a5fb7c8699f26022
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},
1133 {R"cpp(
1134 void test() {
1135 // no crash
1136 using namespace std;
1137 int [[V^ar]];
1139 )cpp",
1140 nullptr, !HeaderFile},
1143 for (const auto& Case : Cases) {
1144 SCOPED_TRACE(Case.Code);
1145 Annotations T(Case.Code);
1146 TestTU TU = TestTU::withCode(T.code());
1147 TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
1148 if (Case.IsHeaderFile) {
1149 // We open the .h file as the main file.
1150 TU.Filename = "test.h";
1151 // Parsing the .h file as C++ include.
1152 TU.ExtraArgs.push_back("-xobjective-c++-header");
1154 auto AST = TU.build();
1155 llvm::StringRef NewName = Case.NewName;
1156 auto Results = rename({T.point(), NewName, AST, testPath(TU.Filename)});
1157 bool WantRename = true;
1158 if (T.ranges().empty())
1159 WantRename = false;
1160 if (!WantRename) {
1161 assert(Case.ErrorMessage && "Error message must be set!");
1162 EXPECT_FALSE(Results)
1163 << "expected rename returned an error: " << T.code();
1164 auto ActualMessage = llvm::toString(Results.takeError());
1165 EXPECT_THAT(ActualMessage, testing::HasSubstr(Case.ErrorMessage));
1166 } else {
1167 EXPECT_TRUE(bool(Results)) << "rename returned an error: "
1168 << llvm::toString(Results.takeError());
1169 EXPECT_EQ(Results->LocalChanges, T.ranges());
1174 MATCHER_P(newText, T, "") { return arg.newText == T; }
1176 TEST(RenameTest, IndexMergeMainFile) {
1177 Annotations Code("int ^x();");
1178 TestTU TU = TestTU::withCode(Code.code());
1179 TU.Filename = "main.cc";
1180 auto AST = TU.build();
1182 auto Main = testPath("main.cc");
1183 auto InMemFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
1184 InMemFS->addFile(testPath("main.cc"), 0,
1185 llvm::MemoryBuffer::getMemBuffer(Code.code()));
1186 InMemFS->addFile(testPath("other.cc"), 0,
1187 llvm::MemoryBuffer::getMemBuffer(Code.code()));
1189 auto Rename = [&](const SymbolIndex *Idx) {
1190 RenameInputs Inputs{Code.point(),
1191 "xPrime",
1192 AST,
1193 Main,
1194 Idx ? createOverlay(getVFSFromAST(AST), InMemFS)
1195 : nullptr,
1196 Idx,
1197 RenameOptions()};
1198 auto Results = rename(Inputs);
1199 EXPECT_TRUE(bool(Results)) << llvm::toString(Results.takeError());
1200 return std::move(*Results);
1203 // We do not expect to see duplicated edits from AST vs index.
1204 auto Results = Rename(TU.index().get());
1205 EXPECT_THAT(Results.GlobalChanges.keys(), ElementsAre(Main));
1206 EXPECT_THAT(Results.GlobalChanges[Main].asTextEdits(),
1207 ElementsAre(newText("xPrime")));
1209 // Sanity check: we do expect to see index results!
1210 TU.Filename = "other.cc";
1211 Results = Rename(TU.index().get());
1212 EXPECT_THAT(Results.GlobalChanges.keys(),
1213 UnorderedElementsAre(Main, testPath("other.cc")));
1215 #ifdef CLANGD_PATH_CASE_INSENSITIVE
1216 // On case-insensitive systems, no duplicates if AST vs index case differs.
1217 // https://github.com/clangd/clangd/issues/665
1218 TU.Filename = "MAIN.CC";
1219 Results = Rename(TU.index().get());
1220 EXPECT_THAT(Results.GlobalChanges.keys(), ElementsAre(Main));
1221 EXPECT_THAT(Results.GlobalChanges[Main].asTextEdits(),
1222 ElementsAre(newText("xPrime")));
1223 #endif
1226 TEST(RenameTest, MainFileReferencesOnly) {
1227 // filter out references not from main file.
1228 llvm::StringRef Test =
1229 R"cpp(
1230 void test() {
1231 int [[fo^o]] = 1;
1232 // rename references not from main file are not included.
1233 #include "foo.inc"
1234 })cpp";
1236 Annotations Code(Test);
1237 auto TU = TestTU::withCode(Code.code());
1238 TU.AdditionalFiles["foo.inc"] = R"cpp(
1239 #define Macro(X) X
1240 &Macro(foo);
1241 &foo;
1242 )cpp";
1243 auto AST = TU.build();
1244 llvm::StringRef NewName = "abcde";
1246 auto RenameResult =
1247 rename({Code.point(), NewName, AST, testPath(TU.Filename)});
1248 ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError() << Code.point();
1249 ASSERT_EQ(1u, RenameResult->GlobalChanges.size());
1250 EXPECT_EQ(applyEdits(std::move(RenameResult->GlobalChanges)).front().second,
1251 expectedResult(Code, NewName));
1254 TEST(RenameTest, NoRenameOnSymbolsFromSystemHeaders) {
1255 llvm::StringRef Test =
1256 R"cpp(
1257 #include <cstdlib>
1258 #include <system>
1260 SystemSym^bol abc;
1262 void foo() { at^oi("9000"); }
1263 )cpp";
1265 Annotations Code(Test);
1266 auto TU = TestTU::withCode(Code.code());
1267 TU.AdditionalFiles["system"] = R"cpp(
1268 class SystemSymbol {};
1269 )cpp";
1270 TU.AdditionalFiles["cstdlib"] = R"cpp(
1271 int atoi(const char *str);
1272 )cpp";
1273 TU.ExtraArgs = {"-isystem", testRoot()};
1274 auto AST = TU.build();
1275 llvm::StringRef NewName = "abcde";
1277 // Clangd will not allow renaming symbols from the system headers for
1278 // correctness.
1279 for (auto &Point : Code.points()) {
1280 auto Results = rename({Point, NewName, AST, testPath(TU.Filename)});
1281 EXPECT_FALSE(Results) << "expected rename returned an error: "
1282 << Code.code();
1283 auto ActualMessage = llvm::toString(Results.takeError());
1284 EXPECT_THAT(ActualMessage, testing::HasSubstr("not a supported kind"));
1288 TEST(RenameTest, ProtobufSymbolIsExcluded) {
1289 Annotations Code("Prot^obuf buf;");
1290 auto TU = TestTU::withCode(Code.code());
1291 TU.HeaderCode =
1292 R"cpp(// Generated by the protocol buffer compiler. DO NOT EDIT!
1293 class Protobuf {};
1294 )cpp";
1295 TU.HeaderFilename = "protobuf.pb.h";
1296 auto AST = TU.build();
1297 auto Results = rename({Code.point(), "newName", AST, testPath(TU.Filename)});
1298 EXPECT_FALSE(Results);
1299 EXPECT_THAT(llvm::toString(Results.takeError()),
1300 testing::HasSubstr("not a supported kind"));
1303 TEST(RenameTest, PrepareRename) {
1304 Annotations FooH("void func();");
1305 Annotations FooCC(R"cpp(
1306 #include "foo.h"
1307 void [[fu^nc]]() {}
1308 )cpp");
1309 std::string FooHPath = testPath("foo.h");
1310 std::string FooCCPath = testPath("foo.cc");
1311 MockFS FS;
1312 FS.Files[FooHPath] = std::string(FooH.code());
1313 FS.Files[FooCCPath] = std::string(FooCC.code());
1315 auto ServerOpts = ClangdServer::optsForTest();
1316 ServerOpts.BuildDynamicSymbolIndex = true;
1318 trace::TestTracer Tracer;
1319 MockCompilationDatabase CDB;
1320 ClangdServer Server(CDB, FS, ServerOpts);
1321 runAddDocument(Server, FooHPath, FooH.code());
1322 runAddDocument(Server, FooCCPath, FooCC.code());
1324 auto Results = runPrepareRename(Server, FooCCPath, FooCC.point(),
1325 /*NewName=*/std::nullopt, {});
1326 // Verify that for multi-file rename, we only return main-file occurrences.
1327 ASSERT_TRUE(bool(Results)) << Results.takeError();
1328 // We don't know the result is complete in prepareRename (passing a nullptr
1329 // index internally), so GlobalChanges should be empty.
1330 EXPECT_TRUE(Results->GlobalChanges.empty());
1331 EXPECT_THAT(FooCC.ranges(),
1332 testing::UnorderedElementsAreArray(Results->LocalChanges));
1334 // Name validation.
1335 Results = runPrepareRename(Server, FooCCPath, FooCC.point(),
1336 /*NewName=*/std::string("int"), {});
1337 EXPECT_FALSE(Results);
1338 EXPECT_THAT(llvm::toString(Results.takeError()),
1339 testing::HasSubstr("keyword"));
1340 EXPECT_THAT(Tracer.takeMetric("rename_name_invalid", "Keywords"),
1341 ElementsAre(1));
1343 for (std::string BadIdent : {"foo!bar", "123foo", "😀@"}) {
1344 Results = runPrepareRename(Server, FooCCPath, FooCC.point(),
1345 /*NewName=*/BadIdent, {});
1346 EXPECT_FALSE(Results);
1347 EXPECT_THAT(llvm::toString(Results.takeError()),
1348 testing::HasSubstr("identifier"));
1349 EXPECT_THAT(Tracer.takeMetric("rename_name_invalid", "BadIdentifier"),
1350 ElementsAre(1));
1352 for (std::string GoodIdent : {"fooBar", "__foo$", "😀"}) {
1353 Results = runPrepareRename(Server, FooCCPath, FooCC.point(),
1354 /*NewName=*/GoodIdent, {});
1355 EXPECT_TRUE(bool(Results));
1359 TEST(CrossFileRenameTests, DirtyBuffer) {
1360 Annotations FooCode("class [[Foo]] {};");
1361 std::string FooPath = testPath("foo.cc");
1362 Annotations FooDirtyBuffer("class [[Foo]] {};\n// this is dirty buffer");
1363 Annotations BarCode("void [[Bar]]() {}");
1364 std::string BarPath = testPath("bar.cc");
1365 // Build the index, the index has "Foo" references from foo.cc and "Bar"
1366 // references from bar.cc.
1367 FileSymbols FSymbols(IndexContents::All);
1368 FSymbols.update(FooPath, nullptr, buildRefSlab(FooCode, "Foo", FooPath),
1369 nullptr, false);
1370 FSymbols.update(BarPath, nullptr, buildRefSlab(BarCode, "Bar", BarPath),
1371 nullptr, false);
1372 auto Index = FSymbols.buildIndex(IndexType::Light);
1374 Annotations MainCode("class [[Fo^o]] {};");
1375 auto MainFilePath = testPath("main.cc");
1376 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemFS =
1377 new llvm::vfs::InMemoryFileSystem;
1378 InMemFS->addFile(FooPath, 0,
1379 llvm::MemoryBuffer::getMemBuffer(FooDirtyBuffer.code()));
1381 // Run rename on Foo, there is a dirty buffer for foo.cc, rename should
1382 // respect the dirty buffer.
1383 TestTU TU = TestTU::withCode(MainCode.code());
1384 auto AST = TU.build();
1385 llvm::StringRef NewName = "newName";
1386 auto Results =
1387 rename({MainCode.point(), NewName, AST, MainFilePath,
1388 createOverlay(getVFSFromAST(AST), InMemFS), Index.get()});
1389 ASSERT_TRUE(bool(Results)) << Results.takeError();
1390 EXPECT_THAT(
1391 applyEdits(std::move(Results->GlobalChanges)),
1392 UnorderedElementsAre(
1393 Pair(Eq(FooPath), Eq(expectedResult(FooDirtyBuffer, NewName))),
1394 Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName)))));
1396 // Run rename on Bar, there is no dirty buffer for the affected file bar.cc,
1397 // so we should read file content from VFS.
1398 MainCode = Annotations("void [[Bar]]() { [[B^ar]](); }");
1399 TU = TestTU::withCode(MainCode.code());
1400 // Set a file "bar.cc" on disk.
1401 TU.AdditionalFiles["bar.cc"] = std::string(BarCode.code());
1402 AST = TU.build();
1403 Results = rename({MainCode.point(), NewName, AST, MainFilePath,
1404 createOverlay(getVFSFromAST(AST), InMemFS), Index.get()});
1405 ASSERT_TRUE(bool(Results)) << Results.takeError();
1406 EXPECT_THAT(
1407 applyEdits(std::move(Results->GlobalChanges)),
1408 UnorderedElementsAre(
1409 Pair(Eq(BarPath), Eq(expectedResult(BarCode, NewName))),
1410 Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName)))));
1412 // Run rename on a pagination index which couldn't return all refs in one
1413 // request, we reject rename on this case.
1414 class PaginationIndex : public SymbolIndex {
1415 bool refs(const RefsRequest &Req,
1416 llvm::function_ref<void(const Ref &)> Callback) const override {
1417 return true; // has more references
1420 bool fuzzyFind(
1421 const FuzzyFindRequest &Req,
1422 llvm::function_ref<void(const Symbol &)> Callback) const override {
1423 return false;
1425 void
1426 lookup(const LookupRequest &Req,
1427 llvm::function_ref<void(const Symbol &)> Callback) const override {}
1429 void relations(const RelationsRequest &Req,
1430 llvm::function_ref<void(const SymbolID &, const Symbol &)>
1431 Callback) const override {}
1433 llvm::unique_function<IndexContents(llvm::StringRef) const>
1434 indexedFiles() const override {
1435 return [](llvm::StringRef) { return IndexContents::None; };
1438 size_t estimateMemoryUsage() const override { return 0; }
1439 } PIndex;
1440 Results = rename({MainCode.point(), NewName, AST, MainFilePath,
1441 createOverlay(getVFSFromAST(AST), InMemFS), &PIndex});
1442 EXPECT_FALSE(Results);
1443 EXPECT_THAT(llvm::toString(Results.takeError()),
1444 testing::HasSubstr("too many occurrences"));
1447 TEST(CrossFileRenameTests, DeduplicateRefsFromIndex) {
1448 auto MainCode = Annotations("int [[^x]] = 2;");
1449 auto MainFilePath = testPath("main.cc");
1450 auto BarCode = Annotations("int [[x]];");
1451 auto BarPath = testPath("bar.cc");
1452 auto TU = TestTU::withCode(MainCode.code());
1453 // Set a file "bar.cc" on disk.
1454 TU.AdditionalFiles["bar.cc"] = std::string(BarCode.code());
1455 auto AST = TU.build();
1456 std::string BarPathURI = URI::create(BarPath).toString();
1457 Ref XRefInBarCC = refWithRange(BarCode.range(), BarPathURI);
1458 // The index will return duplicated refs, our code should be robost to handle
1459 // it.
1460 class DuplicatedXRefIndex : public SymbolIndex {
1461 public:
1462 DuplicatedXRefIndex(const Ref &ReturnedRef) : ReturnedRef(ReturnedRef) {}
1463 bool refs(const RefsRequest &Req,
1464 llvm::function_ref<void(const Ref &)> Callback) const override {
1465 // Return two duplicated refs.
1466 Callback(ReturnedRef);
1467 Callback(ReturnedRef);
1468 return false;
1471 bool fuzzyFind(const FuzzyFindRequest &,
1472 llvm::function_ref<void(const Symbol &)>) const override {
1473 return false;
1475 void lookup(const LookupRequest &,
1476 llvm::function_ref<void(const Symbol &)>) const override {}
1478 void relations(const RelationsRequest &,
1479 llvm::function_ref<void(const SymbolID &, const Symbol &)>)
1480 const override {}
1482 llvm::unique_function<IndexContents(llvm::StringRef) const>
1483 indexedFiles() const override {
1484 return [](llvm::StringRef) { return IndexContents::None; };
1487 size_t estimateMemoryUsage() const override { return 0; }
1488 Ref ReturnedRef;
1489 } DIndex(XRefInBarCC);
1490 llvm::StringRef NewName = "newName";
1491 auto Results = rename({MainCode.point(), NewName, AST, MainFilePath,
1492 getVFSFromAST(AST), &DIndex});
1493 ASSERT_TRUE(bool(Results)) << Results.takeError();
1494 EXPECT_THAT(
1495 applyEdits(std::move(Results->GlobalChanges)),
1496 UnorderedElementsAre(
1497 Pair(Eq(BarPath), Eq(expectedResult(BarCode, NewName))),
1498 Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName)))));
1501 TEST(CrossFileRenameTests, WithUpToDateIndex) {
1502 MockCompilationDatabase CDB;
1503 CDB.ExtraClangFlags = {"-xobjective-c++"};
1504 // rename is runnning on all "^" points in FooH, and "[[]]" ranges are the
1505 // expected rename occurrences.
1506 struct Case {
1507 llvm::StringRef FooH;
1508 llvm::StringRef FooCC;
1509 } Cases[] = {
1511 // classes.
1512 R"cpp(
1513 class [[Fo^o]] {
1514 [[Foo]]();
1515 ~[[Foo]]();
1517 )cpp",
1518 R"cpp(
1519 #include "foo.h"
1520 [[Foo]]::[[Foo]]() {}
1521 [[Foo]]::~[[Foo]]() {}
1523 void func() {
1524 [[Foo]] foo;
1526 )cpp",
1529 // class templates.
1530 R"cpp(
1531 template <typename T>
1532 class [[Foo]] {};
1533 // FIXME: explicit template specializations are not supported due the
1534 // clangd index limitations.
1535 template <>
1536 class Foo<double> {};
1537 )cpp",
1538 R"cpp(
1539 #include "foo.h"
1540 void func() {
1541 [[F^oo]]<int> foo;
1543 )cpp",
1546 // class methods.
1547 R"cpp(
1548 class Foo {
1549 void [[f^oo]]();
1551 )cpp",
1552 R"cpp(
1553 #include "foo.h"
1554 void Foo::[[foo]]() {}
1556 void func(Foo* p) {
1557 p->[[foo]]();
1559 )cpp",
1562 // virtual methods.
1563 R"cpp(
1564 class Base {
1565 virtual void [[foo]]();
1567 class Derived1 : public Base {
1568 void [[f^oo]]() override;
1570 class NotDerived {
1571 void foo() {};
1573 )cpp",
1574 R"cpp(
1575 #include "foo.h"
1576 void Base::[[foo]]() {}
1577 void Derived1::[[foo]]() {}
1579 class Derived2 : public Derived1 {
1580 void [[foo]]() override {};
1583 void func(Base* b, Derived1* d1,
1584 Derived2* d2, NotDerived* nd) {
1585 b->[[foo]]();
1586 d1->[[foo]]();
1587 d2->[[foo]]();
1588 nd->foo();
1590 )cpp",
1592 {// virtual templated method
1593 R"cpp(
1594 template <typename> class Foo { virtual void [[m]](); };
1595 class Bar : Foo<int> { void [[^m]]() override; };
1596 )cpp",
1597 R"cpp(
1598 #include "foo.h"
1600 template<typename T> void Foo<T>::[[m]]() {}
1601 // FIXME: not renamed as the index doesn't see this as an override of
1602 // the canonical Foo<T>::m().
1603 // https://github.com/clangd/clangd/issues/1325
1604 class Baz : Foo<float> { void m() override; };
1605 )cpp"},
1607 // rename on constructor and destructor.
1608 R"cpp(
1609 class [[Foo]] {
1610 [[^Foo]]();
1611 ~[[Foo^]]();
1613 )cpp",
1614 R"cpp(
1615 #include "foo.h"
1616 [[Foo]]::[[Foo]]() {}
1617 [[Foo]]::~[[Foo]]() {}
1619 void func() {
1620 [[Foo]] foo;
1622 )cpp",
1625 // functions.
1626 R"cpp(
1627 void [[f^oo]]();
1628 )cpp",
1629 R"cpp(
1630 #include "foo.h"
1631 void [[foo]]() {}
1633 void func() {
1634 [[foo]]();
1636 )cpp",
1639 // typedefs.
1640 R"cpp(
1641 typedef int [[IN^T]];
1642 [[INT]] foo();
1643 )cpp",
1644 R"cpp(
1645 #include "foo.h"
1646 [[INT]] foo() {}
1647 )cpp",
1650 // usings.
1651 R"cpp(
1652 using [[I^NT]] = int;
1653 [[INT]] foo();
1654 )cpp",
1655 R"cpp(
1656 #include "foo.h"
1657 [[INT]] foo() {}
1658 )cpp",
1661 // variables.
1662 R"cpp(
1663 static const int [[VA^R]] = 123;
1664 )cpp",
1665 R"cpp(
1666 #include "foo.h"
1667 int s = [[VAR]];
1668 )cpp",
1671 // scope enums.
1672 R"cpp(
1673 enum class [[K^ind]] { ABC };
1674 )cpp",
1675 R"cpp(
1676 #include "foo.h"
1677 [[Kind]] ff() {
1678 return [[Kind]]::ABC;
1680 )cpp",
1683 // enum constants.
1684 R"cpp(
1685 enum class Kind { [[A^BC]] };
1686 )cpp",
1687 R"cpp(
1688 #include "foo.h"
1689 Kind ff() {
1690 return Kind::[[ABC]];
1692 )cpp",
1695 // Implicit references in macro expansions.
1696 R"cpp(
1697 class [[Fo^o]] {};
1698 #define FooFoo Foo
1699 #define FOO Foo
1700 )cpp",
1701 R"cpp(
1702 #include "foo.h"
1703 void bar() {
1704 [[Foo]] x;
1705 FOO y;
1706 FooFoo z;
1708 )cpp",
1711 // Objective-C classes.
1712 R"cpp(
1713 @interface [[Fo^o]]
1714 @end
1715 )cpp",
1716 R"cpp(
1717 #include "foo.h"
1718 @implementation [[Foo]]
1719 @end
1721 void func([[Foo]] *f) {}
1722 )cpp",
1726 trace::TestTracer Tracer;
1727 for (const auto &T : Cases) {
1728 SCOPED_TRACE(T.FooH);
1729 Annotations FooH(T.FooH);
1730 Annotations FooCC(T.FooCC);
1731 std::string FooHPath = testPath("foo.h");
1732 std::string FooCCPath = testPath("foo.cc");
1734 MockFS FS;
1735 FS.Files[FooHPath] = std::string(FooH.code());
1736 FS.Files[FooCCPath] = std::string(FooCC.code());
1738 auto ServerOpts = ClangdServer::optsForTest();
1739 ServerOpts.BuildDynamicSymbolIndex = true;
1740 ClangdServer Server(CDB, FS, ServerOpts);
1742 // Add all files to clangd server to make sure the dynamic index has been
1743 // built.
1744 runAddDocument(Server, FooHPath, FooH.code());
1745 runAddDocument(Server, FooCCPath, FooCC.code());
1747 llvm::StringRef NewName = "NewName";
1748 for (const auto &RenamePos : FooH.points()) {
1749 EXPECT_THAT(Tracer.takeMetric("rename_files"), SizeIs(0));
1750 auto FileEditsList =
1751 llvm::cantFail(runRename(Server, FooHPath, RenamePos, NewName, {}));
1752 EXPECT_THAT(Tracer.takeMetric("rename_files"), ElementsAre(2));
1753 EXPECT_THAT(
1754 applyEdits(std::move(FileEditsList.GlobalChanges)),
1755 UnorderedElementsAre(
1756 Pair(Eq(FooHPath), Eq(expectedResult(T.FooH, NewName))),
1757 Pair(Eq(FooCCPath), Eq(expectedResult(T.FooCC, NewName)))));
1762 TEST(CrossFileRenameTests, CrossFileOnLocalSymbol) {
1763 // cross-file rename should work for function-local symbols, even there is no
1764 // index provided.
1765 Annotations Code("void f(int [[abc]]) { [[a^bc]] = 3; }");
1766 auto TU = TestTU::withCode(Code.code());
1767 auto Path = testPath(TU.Filename);
1768 auto AST = TU.build();
1769 llvm::StringRef NewName = "newName";
1770 auto Results = rename({Code.point(), NewName, AST, Path});
1771 ASSERT_TRUE(bool(Results)) << Results.takeError();
1772 EXPECT_THAT(
1773 applyEdits(std::move(Results->GlobalChanges)),
1774 UnorderedElementsAre(Pair(Eq(Path), Eq(expectedResult(Code, NewName)))));
1777 TEST(CrossFileRenameTests, BuildRenameEdits) {
1778 Annotations Code("[[😂]]");
1779 auto LSPRange = Code.range();
1780 llvm::StringRef FilePath = "/test/TestTU.cpp";
1781 llvm::StringRef NewName = "abc";
1782 auto Edit = buildRenameEdit(FilePath, Code.code(), {LSPRange}, NewName);
1783 ASSERT_TRUE(bool(Edit)) << Edit.takeError();
1784 ASSERT_EQ(1UL, Edit->Replacements.size());
1785 EXPECT_EQ(FilePath, Edit->Replacements.begin()->getFilePath());
1786 EXPECT_EQ(4UL, Edit->Replacements.begin()->getLength());
1788 // Test invalid range.
1789 LSPRange.end = {10, 0}; // out of range
1790 Edit = buildRenameEdit(FilePath, Code.code(), {LSPRange}, NewName);
1791 EXPECT_FALSE(Edit);
1792 EXPECT_THAT(llvm::toString(Edit.takeError()),
1793 testing::HasSubstr("fail to convert"));
1795 // Normal ascii characters.
1796 Annotations T(R"cpp(
1797 [[range]]
1798 [[range]]
1799 [[range]]
1800 )cpp");
1801 Edit = buildRenameEdit(FilePath, T.code(), T.ranges(), NewName);
1802 ASSERT_TRUE(bool(Edit)) << Edit.takeError();
1803 EXPECT_EQ(applyEdits(FileEdits{{T.code(), std::move(*Edit)}}).front().second,
1804 expectedResult(T, NewName));
1807 TEST(CrossFileRenameTests, adjustRenameRanges) {
1808 // Ranges in IndexedCode indicate the indexed occurrences;
1809 // ranges in DraftCode indicate the expected mapped result, empty indicates
1810 // we expect no matched result found.
1811 struct {
1812 llvm::StringRef IndexedCode;
1813 llvm::StringRef DraftCode;
1814 } Tests[] = {
1816 // both line and column are changed, not a near miss.
1817 R"cpp(
1818 int [[x]] = 0;
1819 )cpp",
1820 R"cpp(
1821 // insert a line.
1822 double x = 0;
1823 )cpp",
1826 // subset.
1827 R"cpp(
1828 int [[x]] = 0;
1829 )cpp",
1830 R"cpp(
1831 int [[x]] = 0;
1832 {int x = 0; }
1833 )cpp",
1836 // shift columns.
1837 R"cpp(int [[x]] = 0; void foo(int x);)cpp",
1838 R"cpp(double [[x]] = 0; void foo(double x);)cpp",
1841 // shift lines.
1842 R"cpp(
1843 int [[x]] = 0;
1844 void foo(int x);
1845 )cpp",
1846 R"cpp(
1847 // insert a line.
1848 int [[x]] = 0;
1849 void foo(int x);
1850 )cpp",
1853 LangOptions LangOpts;
1854 LangOpts.CPlusPlus = true;
1855 for (const auto &T : Tests) {
1856 SCOPED_TRACE(T.DraftCode);
1857 Annotations Draft(T.DraftCode);
1858 auto ActualRanges = adjustRenameRanges(
1859 Draft.code(), "x", Annotations(T.IndexedCode).ranges(), LangOpts);
1860 if (!ActualRanges)
1861 EXPECT_THAT(Draft.ranges(), testing::IsEmpty());
1862 else
1863 EXPECT_THAT(Draft.ranges(),
1864 testing::UnorderedElementsAreArray(*ActualRanges));
1868 TEST(RangePatchingHeuristic, GetMappedRanges) {
1869 // ^ in LexedCode marks the ranges we expect to be mapped; no ^ indicates
1870 // there are no mapped ranges.
1871 struct {
1872 llvm::StringRef IndexedCode;
1873 llvm::StringRef LexedCode;
1874 } Tests[] = {
1876 // no lexed ranges.
1877 "[[]]",
1881 // both line and column are changed, not a near miss.
1882 R"([[]])",
1884 [[]]
1888 // subset.
1889 "[[]]",
1890 "^[[]] [[]]"
1893 // shift columns.
1894 "[[]] [[]]",
1895 " ^[[]] ^[[]] [[]]"
1899 [[]]
1901 [[]] [[]]
1904 // insert a line
1905 ^[[]]
1907 ^[[]] ^[[]]
1912 [[]]
1914 [[]] [[]]
1917 // insert a line
1918 ^[[]]
1919 ^[[]] ^[[]] // column is shifted.
1924 [[]]
1926 [[]] [[]]
1929 // insert a line
1930 [[]]
1932 [[]] [[]] // not mapped (both line and column are changed).
1937 [[]]
1938 [[]]
1940 [[]]
1941 [[]]
1946 // insert a new line
1947 ^[[]]
1948 ^[[]]
1949 [[]] // additional range
1950 ^[[]]
1951 ^[[]]
1952 [[]] // additional range
1956 // non-distinct result (two best results), not a near miss
1958 [[]]
1959 [[]]
1960 [[]]
1963 [[]]
1964 [[]]
1965 [[]]
1966 [[]]
1970 for (const auto &T : Tests) {
1971 SCOPED_TRACE(T.IndexedCode);
1972 auto Lexed = Annotations(T.LexedCode);
1973 auto LexedRanges = Lexed.ranges();
1974 std::vector<Range> ExpectedMatches;
1975 for (auto P : Lexed.points()) {
1976 auto Match = llvm::find_if(LexedRanges, [&P](const Range& R) {
1977 return R.start == P;
1979 ASSERT_NE(Match, LexedRanges.end());
1980 ExpectedMatches.push_back(*Match);
1983 auto Mapped =
1984 getMappedRanges(Annotations(T.IndexedCode).ranges(), LexedRanges);
1985 if (!Mapped)
1986 EXPECT_THAT(ExpectedMatches, IsEmpty());
1987 else
1988 EXPECT_THAT(ExpectedMatches, UnorderedElementsAreArray(*Mapped));
1992 TEST(CrossFileRenameTests, adjustmentCost) {
1993 struct {
1994 llvm::StringRef RangeCode;
1995 size_t ExpectedCost;
1996 } Tests[] = {
1999 $idx[[]]$lex[[]] // diff: 0
2005 $idx[[]]
2006 $lex[[]] // line diff: +1
2007 $idx[[]]
2008 $lex[[]] // line diff: +1
2009 $idx[[]]
2010 $lex[[]] // line diff: +1
2012 $idx[[]]
2014 $lex[[]] // line diff: +2
2016 1 + 1
2020 $idx[[]]
2021 $lex[[]] // line diff: +1
2022 $idx[[]]
2024 $lex[[]] // line diff: +2
2025 $idx[[]]
2028 $lex[[]] // line diff: +3
2030 1 + 1 + 1
2034 $idx[[]]
2037 $lex[[]] // line diff: +3
2038 $idx[[]]
2040 $lex[[]] // line diff: +2
2041 $idx[[]]
2042 $lex[[]] // line diff: +1
2044 3 + 1 + 1
2048 $idx[[]]
2049 $lex[[]] // line diff: +1
2050 $lex[[]] // line diff: -2
2052 $idx[[]]
2053 $idx[[]]
2056 $lex[[]] // line diff: +3
2058 1 + 3 + 5
2062 $idx[[]] $lex[[]] // column diff: +1
2063 $idx[[]]$lex[[]] // diff: 0
2069 $idx[[]]
2070 $lex[[]] // diff: +1
2071 $idx[[]] $lex[[]] // column diff: +1
2072 $idx[[]]$lex[[]] // diff: 0
2074 1 + 1 + 1
2078 $idx[[]] $lex[[]] // column diff: +1
2084 // column diffs: +1, +2, +3
2085 $idx[[]] $lex[[]] $idx[[]] $lex[[]] $idx[[]] $lex[[]]
2087 1 + 1 + 1,
2090 for (const auto &T : Tests) {
2091 SCOPED_TRACE(T.RangeCode);
2092 Annotations C(T.RangeCode);
2093 std::vector<size_t> MappedIndex;
2094 for (size_t I = 0; I < C.ranges("lex").size(); ++I)
2095 MappedIndex.push_back(I);
2096 EXPECT_EQ(renameRangeAdjustmentCost(C.ranges("idx"), C.ranges("lex"),
2097 MappedIndex),
2098 T.ExpectedCost);
2102 } // namespace
2103 } // namespace clangd
2104 } // namespace clang