1 //===-- RenameTests.cpp -----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Annotations.h"
10 #include "ClangdServer.h"
11 #include "SyncAPI.h"
12 #include "TestFS.h"
13 #include "TestTU.h"
14 #include "index/Ref.h"
15 #include "refactor/Rename.h"
16 #include "clang/Tooling/Core/Replacement.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/Support/MemoryBuffer.h"
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21 #include <algorithm>
22 
23 namespace clang {
24 namespace clangd {
25 namespace {
26 
27 using testing::Eq;
28 using testing::Pair;
29 using testing::IsEmpty;
30 using testing::UnorderedElementsAre;
31 using testing::UnorderedElementsAreArray;
32 
33 // Convert a Range to a Ref.
refWithRange(const clangd::Range & Range,const std::string & URI)34 Ref refWithRange(const clangd::Range &Range, const std::string &URI) {
35   Ref Result;
36   Result.Kind = RefKind::Reference;
37   Result.Location.Start.setLine(Range.start.line);
38   Result.Location.Start.setColumn(Range.start.character);
39   Result.Location.End.setLine(Range.end.line);
40   Result.Location.End.setColumn(Range.end.character);
41   Result.Location.FileURI = URI.c_str();
42   return Result;
43 }
44 
45 // Build a RefSlab from all marked ranges in the annotation. The ranges are
46 // assumed to associate with the given SymbolName.
buildRefSlab(const Annotations & Code,llvm::StringRef SymbolName,llvm::StringRef Path)47 std::unique_ptr<RefSlab> buildRefSlab(const Annotations &Code,
48                                       llvm::StringRef SymbolName,
49                                       llvm::StringRef Path) {
50   RefSlab::Builder Builder;
51   TestTU TU;
52   TU.HeaderCode = Code.code();
53   auto Symbols = TU.headerSymbols();
54   const auto &SymbolID = findSymbol(Symbols, SymbolName).ID;
55   std::string PathURI = URI::create(Path).toString();
56   for (const auto &Range : Code.ranges())
57     Builder.insert(SymbolID, refWithRange(Range, PathURI));
58 
59   return std::make_unique<RefSlab>(std::move(Builder).build());
60 }
61 
62 std::vector<
63     std::pair</*FilePath*/ std::string, /*CodeAfterRename*/ std::string>>
applyEdits(FileEdits FE)64 applyEdits(FileEdits FE) {
65   std::vector<std::pair<std::string, std::string>> Results;
66   for (auto &It : FE)
67     Results.emplace_back(
68         It.first().str(),
69         llvm::cantFail(tooling::applyAllReplacements(
70             It.getValue().InitialCode, It.getValue().Replacements)));
71   return Results;
72 }
73 
74 // Generates an expected rename result by replacing all ranges in the given
75 // annotation with the NewName.
expectedResult(Annotations Test,llvm::StringRef NewName)76 std::string expectedResult(Annotations Test, llvm::StringRef NewName) {
77   std::string Result;
78   unsigned NextChar = 0;
79   llvm::StringRef Code = Test.code();
80   for (const auto &R : Test.llvm::Annotations::ranges()) {
81     assert(R.Begin <= R.End && NextChar <= R.Begin);
82     Result += Code.substr(NextChar, R.Begin - NextChar);
83     Result += NewName;
84     NextChar = R.End;
85   }
86   Result += Code.substr(NextChar);
87   return Result;
88 }
89 
TEST(RenameTest,WithinFileRename)90 TEST(RenameTest, WithinFileRename) {
91   // rename is runnning on all "^" points, and "[[]]" ranges point to the
92   // identifier that is being renamed.
93   llvm::StringRef Tests[] = {
94       // Function.
95       R"cpp(
96         void [[foo^]]() {
97           [[fo^o]]();
98         }
99       )cpp",
100 
101       // Type.
102       R"cpp(
103         struct [[foo^]] {};
104         [[foo]] test() {
105            [[f^oo]] x;
106            return x;
107         }
108       )cpp",
109 
110       // Local variable.
111       R"cpp(
112         void bar() {
113           if (auto [[^foo]] = 5) {
114             [[foo]] = 3;
115           }
116         }
117       )cpp",
118 
119       // Rename class, including constructor/destructor.
120       R"cpp(
121         class [[F^oo]] {
122           [[F^oo]]();
123           ~[[Foo]]();
124           void foo(int x);
125         };
126         [[Foo]]::[[Fo^o]]() {}
127         void [[Foo]]::foo(int x) {}
128       )cpp",
129 
130       // Class in template argument.
131       R"cpp(
132         class [[F^oo]] {};
133         template <typename T> void func();
134         template <typename T> class Baz {};
135         int main() {
136           func<[[F^oo]]>();
137           Baz<[[F^oo]]> obj;
138           return 0;
139         }
140       )cpp",
141 
142       // Forward class declaration without definition.
143       R"cpp(
144         class [[F^oo]];
145         [[Foo]] *f();
146       )cpp",
147 
148       // Class methods overrides.
149       R"cpp(
150         struct A {
151          virtual void [[f^oo]]() {}
152         };
153         struct B : A {
154           void [[f^oo]]() override {}
155         };
156         struct C : B {
157           void [[f^oo]]() override {}
158         };
159 
160         void func() {
161           A().[[f^oo]]();
162           B().[[f^oo]]();
163           C().[[f^oo]]();
164         }
165       )cpp",
166 
167       // Template class (partial) specializations.
168       R"cpp(
169         template <typename T>
170         class [[F^oo]] {};
171 
172         template<>
173         class [[F^oo]]<bool> {};
174         template <typename T>
175         class [[F^oo]]<T*> {};
176 
177         void test() {
178           [[Foo]]<int> x;
179           [[Foo]]<bool> y;
180           [[Foo]]<int*> z;
181         }
182       )cpp",
183 
184       // Template class instantiations.
185       R"cpp(
186         template <typename T>
187         class [[F^oo]] {
188         public:
189           T foo(T arg, T& ref, T* ptr) {
190             T value;
191             int number = 42;
192             value = (T)number;
193             value = static_cast<T>(number);
194             return value;
195           }
196           static void foo(T value) {}
197           T member;
198         };
199 
200         template <typename T>
201         void func() {
202           [[F^oo]]<T> obj;
203           obj.member = T();
204           [[Foo]]<T>::foo();
205         }
206 
207         void test() {
208           [[F^oo]]<int> i;
209           i.member = 0;
210           [[F^oo]]<int>::foo(0);
211 
212           [[F^oo]]<bool> b;
213           b.member = false;
214           [[Foo]]<bool>::foo(false);
215         }
216       )cpp",
217 
218       // Template class methods.
219       R"cpp(
220         template <typename T>
221         class A {
222         public:
223           void [[f^oo]]() {}
224         };
225 
226         void func() {
227           A<int>().[[f^oo]]();
228           A<double>().[[f^oo]]();
229           A<float>().[[f^oo]]();
230         }
231       )cpp",
232 
233       // Complicated class type.
234       R"cpp(
235          // Forward declaration.
236         class [[Fo^o]];
237         class Baz {
238           virtual int getValue() const = 0;
239         };
240 
241         class [[F^oo]] : public Baz  {
242         public:
243           [[Foo]](int value = 0) : x(value) {}
244 
245           [[Foo]] &operator++(int);
246 
247           bool operator<([[Foo]] const &rhs);
248           int getValue() const;
249         private:
250           int x;
251         };
252 
253         void func() {
254           [[Foo]] *Pointer = 0;
255           [[Foo]] Variable = [[Foo]](10);
256           for ([[Foo]] it; it < Variable; it++);
257           const [[Foo]] *C = new [[Foo]]();
258           const_cast<[[Foo]] *>(C)->getValue();
259           [[Foo]] foo;
260           const Baz &BazReference = foo;
261           const Baz *BazPointer = &foo;
262           reinterpret_cast<const [[^Foo]] *>(BazPointer)->getValue();
263           static_cast<const [[^Foo]] &>(BazReference).getValue();
264           static_cast<const [[^Foo]] *>(BazPointer)->getValue();
265         }
266       )cpp",
267 
268       // CXXConstructor initializer list.
269       R"cpp(
270         class Baz {};
271         class Qux {
272           Baz [[F^oo]];
273         public:
274           Qux();
275         };
276         Qux::Qux() : [[F^oo]]() {}
277       )cpp",
278 
279       // DeclRefExpr.
280       R"cpp(
281         class C {
282         public:
283           static int [[F^oo]];
284         };
285 
286         int foo(int x);
287         #define MACRO(a) foo(a)
288 
289         void func() {
290           C::[[F^oo]] = 1;
291           MACRO(C::[[Foo]]);
292           int y = C::[[F^oo]];
293         }
294       )cpp",
295 
296       // Macros.
297       R"cpp(
298         // no rename inside macro body.
299         #define M1 foo
300         #define M2(x) x
301         int [[fo^o]]();
302         void boo(int);
303 
304         void qoo() {
305           [[foo]]();
306           boo([[foo]]());
307           M1();
308           boo(M1());
309           M2([[foo]]());
310           M2(M1()); // foo is inside the nested macro body.
311         }
312       )cpp",
313 
314       // MemberExpr in macros
315       R"cpp(
316         class Baz {
317         public:
318           int [[F^oo]];
319         };
320         int qux(int x);
321         #define MACRO(a) qux(a)
322 
323         int main() {
324           Baz baz;
325           baz.[[Foo]] = 1;
326           MACRO(baz.[[Foo]]);
327           int y = baz.[[Foo]];
328         }
329       )cpp",
330 
331       // Template parameters.
332       R"cpp(
333         template <typename [[^T]]>
334         class Foo {
335           [[T]] foo([[T]] arg, [[T]]& ref, [[^T]]* ptr) {
336             [[T]] value;
337             int number = 42;
338             value = ([[T]])number;
339             value = static_cast<[[^T]]>(number);
340             return value;
341           }
342           static void foo([[T]] value) {}
343           [[T]] member;
344         };
345       )cpp",
346 
347       // Typedef.
348       R"cpp(
349         namespace std {
350         class basic_string {};
351         typedef basic_string [[s^tring]];
352         } // namespace std
353 
354         std::[[s^tring]] foo();
355       )cpp",
356 
357       // Variable.
358       R"cpp(
359         namespace A {
360         int [[F^oo]];
361         }
362         int Foo;
363         int Qux = Foo;
364         int Baz = A::[[^Foo]];
365         void fun() {
366           struct {
367             int Foo;
368           } b = {100};
369           int Foo = 100;
370           Baz = Foo;
371           {
372             extern int Foo;
373             Baz = Foo;
374             Foo = A::[[F^oo]] + Baz;
375             A::[[Fo^o]] = b.Foo;
376           }
377           Foo = b.Foo;
378         }
379       )cpp",
380 
381       // Namespace alias.
382       R"cpp(
383         namespace a { namespace b { void foo(); } }
384         namespace [[^x]] = a::b;
385         void bar() {
386           [[x]]::foo();
387         }
388       )cpp",
389 
390       // Scope enums.
391       R"cpp(
392         enum class [[K^ind]] { ABC };
393         void ff() {
394           [[K^ind]] s;
395           s = [[Kind]]::ABC;
396         }
397       )cpp",
398 
399       // template class in template argument list.
400       R"cpp(
401         template<typename T>
402         class [[Fo^o]] {};
403         template <template<typename> class Z> struct Bar { };
404         template <> struct Bar<[[Foo]]> {};
405       )cpp",
406   };
407   for (llvm::StringRef T : Tests) {
408     Annotations Code(T);
409     auto TU = TestTU::withCode(Code.code());
410     TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
411     auto AST = TU.build();
412     llvm::StringRef NewName = "abcde";
413     for (const auto &RenamePos : Code.points()) {
414       auto RenameResult =
415           rename({RenamePos, NewName, AST, testPath(TU.Filename)});
416       ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError();
417       ASSERT_EQ(1u, RenameResult->size());
418       EXPECT_EQ(applyEdits(std::move(*RenameResult)).front().second,
419                 expectedResult(Code, NewName));
420     }
421   }
422 }
423 
TEST(RenameTest,Renameable)424 TEST(RenameTest, Renameable) {
425   struct Case {
426     const char *Code;
427     const char* ErrorMessage; // null if no error
428     bool IsHeaderFile;
429     const SymbolIndex *Index;
430   };
431   TestTU OtherFile = TestTU::withCode("Outside s; auto ss = &foo;");
432   const char *CommonHeader = R"cpp(
433     class Outside {};
434     void foo();
435   )cpp";
436   OtherFile.HeaderCode = CommonHeader;
437   OtherFile.Filename = "other.cc";
438   // The index has a "Outside" reference and a "foo" reference.
439   auto OtherFileIndex = OtherFile.index();
440   const SymbolIndex *Index = OtherFileIndex.get();
441 
442   const bool HeaderFile = true;
443   Case Cases[] = {
444       {R"cpp(// allow -- function-local
445         void f(int [[Lo^cal]]) {
446           [[Local]] = 2;
447         }
448       )cpp",
449        nullptr, HeaderFile, Index},
450 
451       {R"cpp(// allow -- symbol is indexable and has no refs in index.
452         void [[On^lyInThisFile]]();
453       )cpp",
454        nullptr, HeaderFile, Index},
455 
456       {R"cpp(// disallow -- symbol is indexable and has other refs in index.
457         void f() {
458           Out^side s;
459         }
460       )cpp",
461        "used outside main file", HeaderFile, Index},
462 
463       {R"cpp(// disallow -- symbol in anonymous namespace in header is not indexable.
464         namespace {
465         class Unin^dexable {};
466         }
467       )cpp",
468        "not eligible for indexing", HeaderFile, Index},
469 
470       {R"cpp(// allow -- symbol in anonymous namespace in non-header file is indexable.
471         namespace {
472         class [[F^oo]] {};
473         }
474       )cpp",
475        nullptr, !HeaderFile, Index},
476 
477       {R"cpp(// disallow -- namespace symbol isn't supported
478         namespace n^s {}
479       )cpp",
480        "not a supported kind", HeaderFile, Index},
481 
482       {
483           R"cpp(
484          #define MACRO 1
485          int s = MAC^RO;
486        )cpp",
487           "not a supported kind", HeaderFile, Index},
488 
489       {
490           R"cpp(
491         struct X { X operator++(int); };
492         void f(X x) {x+^+;})cpp",
493           "no symbol", HeaderFile, Index},
494 
495       {R"cpp(// foo is declared outside the file.
496         void fo^o() {}
497       )cpp",
498        "used outside main file", !HeaderFile /*cc file*/, Index},
499 
500       {R"cpp(
501          // We should detect the symbol is used outside the file from the AST.
502          void fo^o() {})cpp",
503        "used outside main file", !HeaderFile, nullptr /*no index*/},
504 
505       {R"cpp(
506          void foo(int);
507          void foo(char);
508          template <typename T> void f(T t) {
509            fo^o(t);
510          })cpp",
511        "multiple symbols", !HeaderFile, nullptr /*no index*/},
512 
513       {R"cpp(// disallow rename on unrelated token.
514          cl^ass Foo {};
515        )cpp",
516        "no symbol", !HeaderFile, nullptr},
517 
518       {R"cpp(// disallow rename on unrelated token.
519          temp^late<typename T>
520          class Foo {};
521        )cpp",
522        "no symbol", !HeaderFile, nullptr},
523   };
524 
525   for (const auto& Case : Cases) {
526     Annotations T(Case.Code);
527     TestTU TU = TestTU::withCode(T.code());
528     TU.HeaderCode = CommonHeader;
529     TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
530     if (Case.IsHeaderFile) {
531       // We open the .h file as the main file.
532       TU.Filename = "test.h";
533       // Parsing the .h file as C++ include.
534       TU.ExtraArgs.push_back("-xobjective-c++-header");
535     }
536     auto AST = TU.build();
537     llvm::StringRef NewName = "dummyNewName";
538     auto Results =
539         rename({T.point(), NewName, AST, testPath(TU.Filename), Case.Index});
540     bool WantRename = true;
541     if (T.ranges().empty())
542       WantRename = false;
543     if (!WantRename) {
544       assert(Case.ErrorMessage && "Error message must be set!");
545       EXPECT_FALSE(Results)
546           << "expected rename returned an error: " << T.code();
547       auto ActualMessage = llvm::toString(Results.takeError());
548       EXPECT_THAT(ActualMessage, testing::HasSubstr(Case.ErrorMessage));
549     } else {
550       EXPECT_TRUE(bool(Results)) << "rename returned an error: "
551                                  << llvm::toString(Results.takeError());
552       ASSERT_EQ(1u, Results->size());
553       EXPECT_EQ(applyEdits(std::move(*Results)).front().second,
554                 expectedResult(T, NewName));
555     }
556   }
557 }
558 
TEST(RenameTest,MainFileReferencesOnly)559 TEST(RenameTest, MainFileReferencesOnly) {
560   // filter out references not from main file.
561   llvm::StringRef Test =
562       R"cpp(
563         void test() {
564           int [[fo^o]] = 1;
565           // rename references not from main file are not included.
566           #include "foo.inc"
567         })cpp";
568 
569   Annotations Code(Test);
570   auto TU = TestTU::withCode(Code.code());
571   TU.AdditionalFiles["foo.inc"] = R"cpp(
572       #define Macro(X) X
573       &Macro(foo);
574       &foo;
575     )cpp";
576   auto AST = TU.build();
577   llvm::StringRef NewName = "abcde";
578 
579   auto RenameResult =
580       rename({Code.point(), NewName, AST, testPath(TU.Filename)});
581   ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError() << Code.point();
582   ASSERT_EQ(1u, RenameResult->size());
583   EXPECT_EQ(applyEdits(std::move(*RenameResult)).front().second,
584             expectedResult(Code, NewName));
585 }
586 
TEST(CrossFileRenameTests,DirtyBuffer)587 TEST(CrossFileRenameTests, DirtyBuffer) {
588   Annotations FooCode("class [[Foo]] {};");
589   std::string FooPath = testPath("foo.cc");
590   Annotations FooDirtyBuffer("class [[Foo]] {};\n// this is dirty buffer");
591   Annotations BarCode("void [[Bar]]() {}");
592   std::string BarPath = testPath("bar.cc");
593   // Build the index, the index has "Foo" references from foo.cc and "Bar"
594   // references from bar.cc.
595   FileSymbols FSymbols;
596   FSymbols.update(FooPath, nullptr, buildRefSlab(FooCode, "Foo", FooPath),
597                   nullptr, false);
598   FSymbols.update(BarPath, nullptr, buildRefSlab(BarCode, "Bar", BarPath),
599                   nullptr, false);
600   auto Index = FSymbols.buildIndex(IndexType::Light);
601 
602   Annotations MainCode("class  [[Fo^o]] {};");
603   auto MainFilePath = testPath("main.cc");
604   // Dirty buffer for foo.cc.
605   auto GetDirtyBuffer = [&](PathRef Path) -> llvm::Optional<std::string> {
606     if (Path == FooPath)
607       return FooDirtyBuffer.code().str();
608     return llvm::None;
609   };
610 
611   // Run rename on Foo, there is a dirty buffer for foo.cc, rename should
612   // respect the dirty buffer.
613   TestTU TU = TestTU::withCode(MainCode.code());
614   auto AST = TU.build();
615   llvm::StringRef NewName = "newName";
616   auto Results = rename({MainCode.point(), NewName, AST, MainFilePath,
617                          Index.get(), /*CrossFile=*/true, GetDirtyBuffer});
618   ASSERT_TRUE(bool(Results)) << Results.takeError();
619   EXPECT_THAT(
620       applyEdits(std::move(*Results)),
621       UnorderedElementsAre(
622           Pair(Eq(FooPath), Eq(expectedResult(FooDirtyBuffer, NewName))),
623           Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName)))));
624 
625   // Run rename on Bar, there is no dirty buffer for the affected file bar.cc,
626   // so we should read file content from VFS.
627   MainCode = Annotations("void [[Bar]]() { [[B^ar]](); }");
628   TU = TestTU::withCode(MainCode.code());
629   // Set a file "bar.cc" on disk.
630   TU.AdditionalFiles["bar.cc"] = BarCode.code();
631   AST = TU.build();
632   Results = rename({MainCode.point(), NewName, AST, MainFilePath, Index.get(),
633                     /*CrossFile=*/true, GetDirtyBuffer});
634   ASSERT_TRUE(bool(Results)) << Results.takeError();
635   EXPECT_THAT(
636       applyEdits(std::move(*Results)),
637       UnorderedElementsAre(
638           Pair(Eq(BarPath), Eq(expectedResult(BarCode, NewName))),
639           Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName)))));
640 
641   // Run rename on a pagination index which couldn't return all refs in one
642   // request, we reject rename on this case.
643   class PaginationIndex : public SymbolIndex {
644     bool refs(const RefsRequest &Req,
645               llvm::function_ref<void(const Ref &)> Callback) const override {
646       return true; // has more references
647     }
648 
649     bool fuzzyFind(
650         const FuzzyFindRequest &Req,
651         llvm::function_ref<void(const Symbol &)> Callback) const override {
652       return false;
653     }
654     void
655     lookup(const LookupRequest &Req,
656            llvm::function_ref<void(const Symbol &)> Callback) const override {}
657 
658     void relations(const RelationsRequest &Req,
659                    llvm::function_ref<void(const SymbolID &, const Symbol &)>
660                        Callback) const override {}
661     size_t estimateMemoryUsage() const override { return 0; }
662   } PIndex;
663   Results = rename({MainCode.point(), NewName, AST, MainFilePath, &PIndex,
664                     /*CrossFile=*/true, GetDirtyBuffer});
665   EXPECT_FALSE(Results);
666   EXPECT_THAT(llvm::toString(Results.takeError()),
667               testing::HasSubstr("too many occurrences"));
668 }
669 
TEST(CrossFileRenameTests,DeduplicateRefsFromIndex)670 TEST(CrossFileRenameTests, DeduplicateRefsFromIndex) {
671   auto MainCode = Annotations("int [[^x]] = 2;");
672   auto MainFilePath = testPath("main.cc");
673   auto BarCode = Annotations("int [[x]];");
674   auto BarPath = testPath("bar.cc");
675   auto TU = TestTU::withCode(MainCode.code());
676   // Set a file "bar.cc" on disk.
677   TU.AdditionalFiles["bar.cc"] = BarCode.code();
678   auto AST = TU.build();
679   std::string BarPathURI = URI::create(BarPath).toString();
680   Ref XRefInBarCC = refWithRange(BarCode.range(), BarPathURI);
681   // The index will return duplicated refs, our code should be robost to handle
682   // it.
683   class DuplicatedXRefIndex : public SymbolIndex {
684   public:
685     DuplicatedXRefIndex(const Ref &ReturnedRef) : ReturnedRef(ReturnedRef) {}
686     bool refs(const RefsRequest &Req,
687               llvm::function_ref<void(const Ref &)> Callback) const override {
688       // Return two duplicated refs.
689       Callback(ReturnedRef);
690       Callback(ReturnedRef);
691       return false;
692     }
693 
694     bool fuzzyFind(const FuzzyFindRequest &,
695                    llvm::function_ref<void(const Symbol &)>) const override {
696       return false;
697     }
698     void lookup(const LookupRequest &,
699                 llvm::function_ref<void(const Symbol &)>) const override {}
700 
701     void relations(const RelationsRequest &,
702                    llvm::function_ref<void(const SymbolID &, const Symbol &)>)
703         const override {}
704     size_t estimateMemoryUsage() const override { return 0; }
705     Ref ReturnedRef;
706   } DIndex(XRefInBarCC);
707   llvm::StringRef NewName = "newName";
708   auto Results = rename({MainCode.point(), NewName, AST, MainFilePath, &DIndex,
709                          /*CrossFile=*/true});
710   ASSERT_TRUE(bool(Results)) << Results.takeError();
711   EXPECT_THAT(
712       applyEdits(std::move(*Results)),
713       UnorderedElementsAre(
714           Pair(Eq(BarPath), Eq(expectedResult(BarCode, NewName))),
715           Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName)))));
716 }
717 
TEST(CrossFileRenameTests,WithUpToDateIndex)718 TEST(CrossFileRenameTests, WithUpToDateIndex) {
719   MockCompilationDatabase CDB;
720   CDB.ExtraClangFlags = {"-xc++"};
721   class IgnoreDiagnostics : public DiagnosticsConsumer {
722     void onDiagnosticsReady(PathRef File,
723                             std::vector<Diag> Diagnostics) override {}
724   } DiagConsumer;
725   // rename is runnning on the "^" point in FooH, and "[[]]" ranges are the
726   // expected rename occurrences.
727   struct Case {
728     llvm::StringRef FooH;
729     llvm::StringRef FooCC;
730   } Cases[] = {
731       {
732           // classes.
733           R"cpp(
734         class [[Fo^o]] {
735           [[Foo]]();
736           ~[[Foo]]();
737         };
738       )cpp",
739           R"cpp(
740         #include "foo.h"
741         [[Foo]]::[[Foo]]() {}
742         [[Foo]]::~[[Foo]]() {}
743 
744         void func() {
745           [[Foo]] foo;
746         }
747       )cpp",
748       },
749       {
750           // class methods.
751           R"cpp(
752         class Foo {
753           void [[f^oo]]();
754         };
755       )cpp",
756           R"cpp(
757         #include "foo.h"
758         void Foo::[[foo]]() {}
759 
760         void func(Foo* p) {
761           p->[[foo]]();
762         }
763       )cpp",
764       },
765       {
766           // Constructor.
767           R"cpp(
768         class [[Foo]] {
769           [[^Foo]]();
770           ~[[Foo]]();
771         };
772       )cpp",
773           R"cpp(
774         #include "foo.h"
775         [[Foo]]::[[Foo]]() {}
776         [[Foo]]::~[[Foo]]() {}
777 
778         void func() {
779           [[Foo]] foo;
780         }
781       )cpp",
782       },
783       {
784           // Destructor (selecting before the identifier).
785           R"cpp(
786         class [[Foo]] {
787           [[Foo]]();
788           ~[[Foo^]]();
789         };
790       )cpp",
791           R"cpp(
792         #include "foo.h"
793         [[Foo]]::[[Foo]]() {}
794         [[Foo]]::~[[Foo]]() {}
795 
796         void func() {
797           [[Foo]] foo;
798         }
799       )cpp",
800       },
801       {
802           // functions.
803           R"cpp(
804         void [[f^oo]]();
805       )cpp",
806           R"cpp(
807         #include "foo.h"
808         void [[foo]]() {}
809 
810         void func() {
811           [[foo]]();
812         }
813       )cpp",
814       },
815       {
816           // typedefs.
817           R"cpp(
818       typedef int [[IN^T]];
819       [[INT]] foo();
820       )cpp",
821           R"cpp(
822         #include "foo.h"
823         [[INT]] foo() {}
824       )cpp",
825       },
826       {
827           // usings.
828           R"cpp(
829       using [[I^NT]] = int;
830       [[INT]] foo();
831       )cpp",
832           R"cpp(
833         #include "foo.h"
834         [[INT]] foo() {}
835       )cpp",
836       },
837       {
838           // variables.
839           R"cpp(
840       static const int [[VA^R]] = 123;
841       )cpp",
842           R"cpp(
843         #include "foo.h"
844         int s = [[VAR]];
845       )cpp",
846       },
847       {
848           // scope enums.
849           R"cpp(
850       enum class [[K^ind]] { ABC };
851       )cpp",
852           R"cpp(
853         #include "foo.h"
854         [[Kind]] ff() {
855           return [[Kind]]::ABC;
856         }
857       )cpp",
858       },
859       {
860           // enum constants.
861           R"cpp(
862       enum class Kind { [[A^BC]] };
863       )cpp",
864           R"cpp(
865         #include "foo.h"
866         Kind ff() {
867           return Kind::[[ABC]];
868         }
869       )cpp",
870       },
871   };
872 
873   for (const auto& T : Cases) {
874     Annotations FooH(T.FooH);
875     Annotations FooCC(T.FooCC);
876     std::string FooHPath = testPath("foo.h");
877     std::string FooCCPath = testPath("foo.cc");
878 
879     MockFSProvider FS;
880     FS.Files[FooHPath] = FooH.code();
881     FS.Files[FooCCPath] = FooCC.code();
882 
883     auto ServerOpts = ClangdServer::optsForTest();
884     ServerOpts.CrossFileRename = true;
885     ServerOpts.BuildDynamicSymbolIndex = true;
886     ClangdServer Server(CDB, FS, DiagConsumer, ServerOpts);
887 
888     // Add all files to clangd server to make sure the dynamic index has been
889     // built.
890     runAddDocument(Server, FooHPath, FooH.code());
891     runAddDocument(Server, FooCCPath, FooCC.code());
892 
893     llvm::StringRef NewName = "NewName";
894     auto FileEditsList =
895         llvm::cantFail(runRename(Server, FooHPath, FooH.point(), NewName));
896     EXPECT_THAT(applyEdits(std::move(FileEditsList)),
897                 UnorderedElementsAre(
898                     Pair(Eq(FooHPath), Eq(expectedResult(T.FooH, NewName))),
899                     Pair(Eq(FooCCPath), Eq(expectedResult(T.FooCC, NewName)))));
900   }
901 }
902 
TEST(CrossFileRenameTests,CrossFileOnLocalSymbol)903 TEST(CrossFileRenameTests, CrossFileOnLocalSymbol) {
904   // cross-file rename should work for function-local symbols, even there is no
905   // index provided.
906   Annotations Code("void f(int [[abc]]) { [[a^bc]] = 3; }");
907   auto TU = TestTU::withCode(Code.code());
908   auto Path = testPath(TU.Filename);
909   auto AST = TU.build();
910   llvm::StringRef NewName = "newName";
911   auto Results = rename({Code.point(), NewName, AST, Path});
912   ASSERT_TRUE(bool(Results)) << Results.takeError();
913   EXPECT_THAT(
914       applyEdits(std::move(*Results)),
915       UnorderedElementsAre(Pair(Eq(Path), Eq(expectedResult(Code, NewName)))));
916 }
917 
TEST(CrossFileRenameTests,BuildRenameEdits)918 TEST(CrossFileRenameTests, BuildRenameEdits) {
919   Annotations Code("[[��]]");
920   auto LSPRange = Code.range();
921   llvm::StringRef FilePath = "/test/TestTU.cpp";
922   llvm::StringRef NewName = "abc";
923   auto Edit = buildRenameEdit(FilePath, Code.code(), {LSPRange}, NewName);
924   ASSERT_TRUE(bool(Edit)) << Edit.takeError();
925   ASSERT_EQ(1UL, Edit->Replacements.size());
926   EXPECT_EQ(FilePath, Edit->Replacements.begin()->getFilePath());
927   EXPECT_EQ(4UL, Edit->Replacements.begin()->getLength());
928 
929   // Test invalid range.
930   LSPRange.end = {10, 0}; // out of range
931   Edit = buildRenameEdit(FilePath, Code.code(), {LSPRange}, NewName);
932   EXPECT_FALSE(Edit);
933   EXPECT_THAT(llvm::toString(Edit.takeError()),
934               testing::HasSubstr("fail to convert"));
935 
936   // Normal ascii characters.
937   Annotations T(R"cpp(
938     [[range]]
939               [[range]]
940       [[range]]
941   )cpp");
942   Edit = buildRenameEdit(FilePath, T.code(), T.ranges(), NewName);
943   ASSERT_TRUE(bool(Edit)) << Edit.takeError();
944   EXPECT_EQ(applyEdits(FileEdits{{T.code(), std::move(*Edit)}}).front().second,
945             expectedResult(T, NewName));
946 }
947 
TEST(CrossFileRenameTests,adjustRenameRanges)948 TEST(CrossFileRenameTests, adjustRenameRanges) {
949   // Ranges in IndexedCode indicate the indexed occurrences;
950   // ranges in DraftCode indicate the expected mapped result, empty indicates
951   // we expect no matched result found.
952   struct {
953     llvm::StringRef IndexedCode;
954     llvm::StringRef DraftCode;
955   } Tests[] = {
956     {
957       // both line and column are changed, not a near miss.
958       R"cpp(
959         int [[x]] = 0;
960       )cpp",
961       R"cpp(
962         // insert a line.
963         double x = 0;
964       )cpp",
965     },
966     {
967       // subset.
968       R"cpp(
969         int [[x]] = 0;
970       )cpp",
971       R"cpp(
972         int [[x]] = 0;
973         {int x = 0; }
974       )cpp",
975     },
976     {
977       // shift columns.
978       R"cpp(int [[x]] = 0; void foo(int x);)cpp",
979       R"cpp(double [[x]] = 0; void foo(double x);)cpp",
980     },
981     {
982       // shift lines.
983       R"cpp(
984         int [[x]] = 0;
985         void foo(int x);
986       )cpp",
987       R"cpp(
988         // insert a line.
989         int [[x]] = 0;
990         void foo(int x);
991       )cpp",
992     },
993   };
994   LangOptions LangOpts;
995   LangOpts.CPlusPlus = true;
996   for (const auto &T : Tests) {
997     Annotations Draft(T.DraftCode);
998     auto ActualRanges = adjustRenameRanges(
999         Draft.code(), "x", Annotations(T.IndexedCode).ranges(), LangOpts);
1000     if (!ActualRanges)
1001        EXPECT_THAT(Draft.ranges(), testing::IsEmpty());
1002     else
1003       EXPECT_THAT(Draft.ranges(),
1004                   testing::UnorderedElementsAreArray(*ActualRanges))
1005           << T.DraftCode;
1006   }
1007 }
1008 
TEST(RangePatchingHeuristic,GetMappedRanges)1009 TEST(RangePatchingHeuristic, GetMappedRanges) {
1010   // ^ in LexedCode marks the ranges we expect to be mapped; no ^ indicates
1011   // there are no mapped ranges.
1012   struct {
1013     llvm::StringRef IndexedCode;
1014     llvm::StringRef LexedCode;
1015   } Tests[] = {
1016     {
1017       // no lexed ranges.
1018       "[[]]",
1019       "",
1020     },
1021     {
1022       // both line and column are changed, not a near miss.
1023       R"([[]])",
1024       R"(
1025         [[]]
1026       )",
1027     },
1028     {
1029       // subset.
1030       "[[]]",
1031       "^[[]]  [[]]"
1032     },
1033     {
1034       // shift columns.
1035       "[[]]   [[]]",
1036       "  ^[[]]   ^[[]]  [[]]"
1037     },
1038     {
1039       R"(
1040         [[]]
1041 
1042         [[]] [[]]
1043       )",
1044       R"(
1045         // insert a line
1046         ^[[]]
1047 
1048         ^[[]] ^[[]]
1049       )",
1050     },
1051     {
1052       R"(
1053         [[]]
1054 
1055         [[]] [[]]
1056       )",
1057       R"(
1058         // insert a line
1059         ^[[]]
1060           ^[[]]  ^[[]] // column is shifted.
1061       )",
1062     },
1063     {
1064       R"(
1065         [[]]
1066 
1067         [[]] [[]]
1068       )",
1069       R"(
1070         // insert a line
1071         [[]]
1072 
1073           [[]]  [[]] // not mapped (both line and column are changed).
1074       )",
1075     },
1076     {
1077       R"(
1078         [[]]
1079                 [[]]
1080 
1081                    [[]]
1082                   [[]]
1083 
1084         }
1085       )",
1086       R"(
1087         // insert a new line
1088         ^[[]]
1089                 ^[[]]
1090              [[]] // additional range
1091                    ^[[]]
1092                   ^[[]]
1093             [[]] // additional range
1094       )",
1095     },
1096     {
1097       // non-distinct result (two best results), not a near miss
1098       R"(
1099         [[]]
1100             [[]]
1101             [[]]
1102       )",
1103       R"(
1104         [[]]
1105         [[]]
1106             [[]]
1107             [[]]
1108       )",
1109     }
1110   };
1111   for (const auto &T : Tests) {
1112     auto Lexed = Annotations(T.LexedCode);
1113     auto LexedRanges = Lexed.ranges();
1114     std::vector<Range> ExpectedMatches;
1115     for (auto P : Lexed.points()) {
1116       auto Match = llvm::find_if(LexedRanges, [&P](const Range& R) {
1117         return R.start == P;
1118       });
1119       ASSERT_NE(Match, LexedRanges.end());
1120       ExpectedMatches.push_back(*Match);
1121     }
1122 
1123     auto Mapped =
1124         getMappedRanges(Annotations(T.IndexedCode).ranges(), LexedRanges);
1125     if (!Mapped)
1126       EXPECT_THAT(ExpectedMatches, IsEmpty());
1127     else
1128       EXPECT_THAT(ExpectedMatches, UnorderedElementsAreArray(*Mapped))
1129           << T.IndexedCode;
1130   }
1131 }
1132 
TEST(CrossFileRenameTests,adjustmentCost)1133 TEST(CrossFileRenameTests, adjustmentCost) {
1134   struct {
1135     llvm::StringRef RangeCode;
1136     size_t ExpectedCost;
1137   } Tests[] = {
1138     {
1139       R"(
1140         $idx[[]]$lex[[]] // diff: 0
1141       )",
1142       0,
1143     },
1144     {
1145       R"(
1146         $idx[[]]
1147         $lex[[]] // line diff: +1
1148                        $idx[[]]
1149                        $lex[[]] // line diff: +1
1150         $idx[[]]
1151         $lex[[]] // line diff: +1
1152 
1153           $idx[[]]
1154 
1155           $lex[[]] // line diff: +2
1156       )",
1157       1 + 1
1158     },
1159     {
1160        R"(
1161         $idx[[]]
1162         $lex[[]] // line diff: +1
1163                        $idx[[]]
1164 
1165                        $lex[[]] // line diff: +2
1166         $idx[[]]
1167 
1168 
1169         $lex[[]] // line diff: +3
1170       )",
1171       1 + 1 + 1
1172     },
1173     {
1174        R"(
1175         $idx[[]]
1176 
1177 
1178         $lex[[]] // line diff: +3
1179                        $idx[[]]
1180 
1181                        $lex[[]] // line diff: +2
1182         $idx[[]]
1183         $lex[[]] // line diff: +1
1184       )",
1185       3 + 1 + 1
1186     },
1187     {
1188       R"(
1189         $idx[[]]
1190         $lex[[]] // line diff: +1
1191                        $lex[[]] // line diff: -2
1192 
1193                        $idx[[]]
1194         $idx[[]]
1195 
1196 
1197         $lex[[]] // line diff: +3
1198       )",
1199       1 + 3 + 5
1200     },
1201     {
1202       R"(
1203                        $idx[[]] $lex[[]] // column diff: +1
1204         $idx[[]]$lex[[]] // diff: 0
1205       )",
1206       1
1207     },
1208     {
1209       R"(
1210         $idx[[]]
1211         $lex[[]] // diff: +1
1212                        $idx[[]] $lex[[]] // column diff: +1
1213         $idx[[]]$lex[[]] // diff: 0
1214       )",
1215       1 + 1 + 1
1216     },
1217     {
1218       R"(
1219         $idx[[]] $lex[[]] // column diff: +1
1220       )",
1221       1
1222     },
1223     {
1224       R"(
1225         // column diffs: +1, +2, +3
1226         $idx[[]] $lex[[]] $idx[[]]  $lex[[]] $idx[[]]   $lex[[]]
1227       )",
1228       1 + 1 + 1,
1229     },
1230   };
1231   for (const auto &T : Tests) {
1232     Annotations C(T.RangeCode);
1233     std::vector<size_t> MappedIndex;
1234     for (size_t I = 0; I < C.ranges("lex").size(); ++I)
1235       MappedIndex.push_back(I);
1236     EXPECT_EQ(renameRangeAdjustmentCost(C.ranges("idx"), C.ranges("lex"),
1237                                         MappedIndex),
1238               T.ExpectedCost) << T.RangeCode;
1239   }
1240 }
1241 
1242 } // namespace
1243 } // namespace clangd
1244 } // namespace clang
1245