clang-tools  14.0.0git
RenameTests.cpp
Go to the documentation of this file.
1 //===-- RenameTests.cpp -----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Annotations.h"
10 #include "ClangdServer.h"
11 #include "SyncAPI.h"
12 #include "TestFS.h"
13 #include "TestTU.h"
14 #include "index/Ref.h"
15 #include "refactor/Rename.h"
16 #include "support/TestTracer.h"
17 #include "clang/Tooling/Core/Replacement.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/Support/MemoryBuffer.h"
20 #include <algorithm>
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 
24 namespace clang {
25 namespace clangd {
26 namespace {
27 
28 using testing::ElementsAre;
29 using testing::Eq;
30 using testing::IsEmpty;
31 using testing::Pair;
32 using testing::SizeIs;
33 using testing::UnorderedElementsAre;
34 using testing::UnorderedElementsAreArray;
35 
36 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>
37 createOverlay(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> Base,
38  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> Overlay) {
39  auto OFS =
40  llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(std::move(Base));
41  OFS->pushOverlay(std::move(Overlay));
42  return OFS;
43 }
44 
45 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> getVFSFromAST(ParsedAST &AST) {
46  return &AST.getSourceManager().getFileManager().getVirtualFileSystem();
47 }
48 
49 // Convert a Range to a Ref.
50 Ref refWithRange(const clangd::Range &Range, const std::string &URI) {
51  Ref Result;
52  Result.Kind = RefKind::Reference | RefKind::Spelled;
53  Result.Location.Start.setLine(Range.start.line);
54  Result.Location.Start.setColumn(Range.start.character);
55  Result.Location.End.setLine(Range.end.line);
56  Result.Location.End.setColumn(Range.end.character);
57  Result.Location.FileURI = URI.c_str();
58  return Result;
59 }
60 
61 // Build a RefSlab from all marked ranges in the annotation. The ranges are
62 // assumed to associate with the given SymbolName.
63 std::unique_ptr<RefSlab> buildRefSlab(const Annotations &Code,
64  llvm::StringRef SymbolName,
65  llvm::StringRef Path) {
67  TestTU TU;
68  TU.HeaderCode = std::string(Code.code());
69  auto Symbols = TU.headerSymbols();
70  const auto &SymbolID = findSymbol(Symbols, SymbolName).ID;
71  std::string PathURI = URI::create(Path).toString();
72  for (const auto &Range : Code.ranges())
73  Builder.insert(SymbolID, refWithRange(Range, PathURI));
74 
75  return std::make_unique<RefSlab>(std::move(Builder).build());
76 }
77 
78 std::vector<
79  std::pair</*FilePath*/ std::string, /*CodeAfterRename*/ std::string>>
80 applyEdits(FileEdits FE) {
81  std::vector<std::pair<std::string, std::string>> Results;
82  for (auto &It : FE)
83  Results.emplace_back(
84  It.first().str(),
85  llvm::cantFail(tooling::applyAllReplacements(
86  It.getValue().InitialCode, It.getValue().Replacements)));
87  return Results;
88 }
89 
90 // Generates an expected rename result by replacing all ranges in the given
91 // annotation with the NewName.
92 std::string expectedResult(Annotations Test, llvm::StringRef NewName) {
93  std::string Result;
94  unsigned NextChar = 0;
95  llvm::StringRef Code = Test.code();
96  for (const auto &R : Test.llvm::Annotations::ranges()) {
97  assert(R.Begin <= R.End && NextChar <= R.Begin);
98  Result += Code.substr(NextChar, R.Begin - NextChar);
99  Result += NewName;
100  NextChar = R.End;
101  }
102  Result += Code.substr(NextChar);
103  return Result;
104 }
105 
106 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]]();
114  }
115  )cpp",
116 
117  // Type.
118  R"cpp(
119  struct [[foo^]] {};
120  [[foo]] test() {
121  [[f^oo]] x;
122  return x;
123  }
124  )cpp",
125 
126  // Local variable.
127  R"cpp(
128  void bar() {
129  if (auto [[^foo]] = 5) {
130  [[foo]] = 3;
131  }
132  }
133  )cpp",
134 
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);
141 
142  [[F^oo]] *Ptr;
143  };
144  [[F^oo]]::[[Fo^o]]() {}
145  [[F^oo]]::~[[Fo^o]]() {}
146  [[F^oo]] *[[F^oo]]::foo(int x) { return Ptr; }
147  )cpp",
148 
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);
156  };
157 
158  template<typename T>
159  [[F^oo]]<T>::[[Fo^o]]() {}
160 
161  template<typename T>
162  [[F^oo]]<T>::~[[Fo^o]]() {}
163  )cpp",
164 
165  // Template class constructor.
166  R"cpp(
167  class [[F^oo]] {
168  template<typename T>
169  [[Fo^o]]();
170 
171  template<typename T>
172  [[F^oo]](T t);
173  };
174 
175  template<typename T>
176  [[F^oo]]::[[Fo^o]]() {}
177  )cpp",
178 
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;
188  }
189  )cpp",
190 
191  // Forward class declaration without definition.
192  R"cpp(
193  class [[F^oo]];
194  [[F^oo]] *f();
195  )cpp",
196 
197  // Member function.
198  R"cpp(
199  struct X {
200  void [[F^oo]]() {}
201  void Baz() { [[F^oo]](); }
202  };
203  )cpp",
204 
205  // Templated method instantiation.
206  R"cpp(
207  template<typename T>
208  class Foo {
209  public:
210  static T [[f^oo]]() {}
211  };
212 
213  void bar() {
214  Foo<int>::[[f^oo]]();
215  }
216  )cpp",
217  R"cpp(
218  template<typename T>
219  class Foo {
220  public:
221  T [[f^oo]]() {}
222  };
223 
224  void bar() {
225  Foo<int>().[[f^oo]]();
226  }
227  )cpp",
228 
229  // Template class (partial) specializations.
230  R"cpp(
231  template <typename T>
232  class [[F^oo]] {};
233 
234  template<>
235  class [[F^oo]]<bool> {};
236  template <typename T>
237  class [[F^oo]]<T*> {};
238 
239  void test() {
240  [[F^oo]]<int> x;
241  [[F^oo]]<bool> y;
242  [[F^oo]]<int*> z;
243  }
244  )cpp",
245 
246  // Incomplete class specializations
247  R"cpp(
248  template <typename T>
249  class [[Fo^o]] {};
250  void func([[F^oo]]<int>);
251  )cpp",
252 
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;
264  }
265  static void foo(T value) {}
266  T member;
267  };
268 
269  template <typename T>
270  void func() {
271  [[F^oo]]<T> obj;
272  obj.member = T();
273  [[Foo]]<T>::foo();
274  }
275 
276  void test() {
277  [[F^oo]]<int> i;
278  i.member = 0;
279  [[F^oo]]<int>::foo(0);
280 
281  [[F^oo]]<bool> b;
282  b.member = false;
283  [[F^oo]]<bool>::foo(false);
284  }
285  )cpp",
286 
287  // Template class methods.
288  R"cpp(
289  template <typename T>
290  class A {
291  public:
292  void [[f^oo]]() {}
293  };
294 
295  void func() {
296  A<int>().[[f^oo]]();
297  A<double>().[[f^oo]]();
298  A<float>().[[f^oo]]();
299  }
300  )cpp",
301 
302  // Templated class specialization.
303  R"cpp(
304  template<typename T, typename U=bool>
305  class [[Foo^]];
306 
307  template<typename T, typename U>
308  class [[Foo^]] {};
309 
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^]];
316 
317  template<typename T, typename U>
318  class [[Foo^]] {};
319  )cpp",
320 
321  // Function template specialization.
322  R"cpp(
323  template<typename T=int, typename U=bool>
324  U [[foo^]]();
325 
326  template<typename T, typename U>
327  U [[foo^]]() {};
328  )cpp",
329  R"cpp(
330  template<typename T, typename U>
331  U [[foo^]]() {};
332 
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^]]();
339 
340  template<typename T, typename U>
341  U [[foo^]]();
342  )cpp",
343  R"cpp(
344  template <typename T>
345  void [[f^oo]](T t);
346 
347  template <>
348  void [[f^oo]](int a);
349 
350  void test() {
351  [[f^oo]]<double>(1);
352  }
353  )cpp",
354 
355  // Variable template.
356  R"cpp(
357  template <typename T, int U>
358  bool [[F^oo]] = true;
359 
360  // Explicit template specialization
361  template <>
362  bool [[F^oo]]<int, 0> = false;
363 
364  // Partial template specialization
365  template <typename T>
366  bool [[F^oo]]<T, 1> = false;
367 
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>;
373  }
374  )cpp",
375 
376  // Complicated class type.
377  R"cpp(
378  // Forward declaration.
379  class [[Fo^o]];
380  class Baz {
381  virtual int getValue() const = 0;
382  };
383 
384  class [[F^oo]] : public Baz {
385  public:
386  [[F^oo]](int value = 0) : x(value) {}
387 
388  [[F^oo]] &operator++(int);
389 
390  bool operator<([[Foo]] const &rhs);
391  int getValue() const;
392  private:
393  int x;
394  };
395 
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();
408  }
409  )cpp",
410 
411  // Static class member.
412  R"cpp(
413  struct Foo {
414  static Foo *[[Static^Member]];
415  };
416 
417  Foo* Foo::[[Static^Member]] = nullptr;
418 
419  void foo() {
420  Foo* Pointer = Foo::[[Static^Member]];
421  }
422  )cpp",
423 
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) {}
433 
434  function() {}
435 
436  R operator()(ArgTypes...) const {}
437  };
438 
439  namespace ns {
440  class [[Old]] {};
441  void f() {
442  function<void([[Old]])> func;
443  }
444  } // namespace ns
445  )cpp",
446 
447  // Destructor explicit call.
448  R"cpp(
449  class [[F^oo]] {
450  public:
451  ~[[^Foo]]();
452  };
453 
454  [[Foo^]]::~[[^Foo]]() {}
455 
456  int main() {
457  [[Fo^o]] f;
458  f.~/*something*/[[^Foo]]();
459  f.~[[^Foo]]();
460  }
461  )cpp",
462 
463  // Derived destructor explicit call.
464  R"cpp(
465  class [[Bas^e]] {};
466  class Derived : public [[Bas^e]] {};
467 
468  int main() {
469  [[Bas^e]] *foo = new Derived();
470  foo->[[^Base]]::~[[^Base]]();
471  }
472  )cpp",
473 
474  // CXXConstructor initializer list.
475  R"cpp(
476  class Baz {};
477  class Qux {
478  Baz [[F^oo]];
479  public:
480  Qux();
481  };
482  Qux::Qux() : [[F^oo]]() {}
483  )cpp",
484 
485  // DeclRefExpr.
486  R"cpp(
487  class C {
488  public:
489  static int [[F^oo]];
490  };
491 
492  int foo(int x);
493  #define MACRO(a) foo(a)
494 
495  void func() {
496  C::[[F^oo]] = 1;
497  MACRO(C::[[Foo]]);
498  int y = C::[[F^oo]];
499  }
500  )cpp",
501 
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);
509 
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.
517  }
518  )cpp",
519 
520  // MemberExpr in macros
521  R"cpp(
522  class Baz {
523  public:
524  int [[F^oo]];
525  };
526  int qux(int x);
527  #define MACRO(a) qux(a)
528 
529  int main() {
530  Baz baz;
531  baz.[[F^oo]] = 1;
532  MACRO(baz.[[F^oo]]);
533  int y = baz.[[F^oo]];
534  }
535  )cpp",
536 
537  // Fields in classes & partial and full specialiations.
538  R"cpp(
539  template<typename T>
540  struct Foo {
541  T [[Vari^able]] = 42;
542  };
543 
544  void foo() {
545  Foo<int> f;
546  f.[[Varia^ble]] = 9000;
547  }
548  )cpp",
549  R"cpp(
550  template<typename T, typename U>
551  struct Foo {
552  T Variable[42];
553  U Another;
554 
555  void bar() {}
556  };
557 
558  template<typename T>
559  struct Foo<T, bool> {
560  T [[Var^iable]];
561  void bar() { ++[[Var^iable]]; }
562  };
563 
564  void foo() {
565  Foo<unsigned, bool> f;
566  f.[[Var^iable]] = 9000;
567  }
568  )cpp",
569  R"cpp(
570  template<typename T, typename U>
571  struct Foo {
572  T Variable[42];
573  U Another;
574 
575  void bar() {}
576  };
577 
578  template<typename T>
579  struct Foo<T, bool> {
580  T Variable;
581  void bar() { ++Variable; }
582  };
583 
584  template<>
585  struct Foo<unsigned, bool> {
586  unsigned [[Var^iable]];
587  void bar() { ++[[Var^iable]]; }
588  };
589 
590  void foo() {
591  Foo<unsigned, bool> f;
592  f.[[Var^iable]] = 9000;
593  }
594  )cpp",
595  // Static fields.
596  R"cpp(
597  struct Foo {
598  static int [[Var^iable]];
599  };
600 
601  int Foo::[[Var^iable]] = 42;
602 
603  void foo() {
604  int LocalInt = Foo::[[Var^iable]];
605  }
606  )cpp",
607  R"cpp(
608  template<typename T>
609  struct Foo {
610  static T [[Var^iable]];
611  };
612 
613  template <>
614  int Foo<int>::[[Var^iable]] = 42;
615 
616  template <>
617  bool Foo<bool>::[[Var^iable]] = true;
618 
619  void foo() {
620  int LocalInt = Foo<int>::[[Var^iable]];
621  bool LocalBool = Foo<bool>::[[Var^iable]];
622  }
623  )cpp",
624 
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;
635  }
636  static void foo([[T^]] value) {}
637  [[T^]] member;
638  };
639  )cpp",
640 
641  // Typedef.
642  R"cpp(
643  namespace ns {
644  class basic_string {};
645  typedef basic_string [[s^tring]];
646  } // namespace ns
647 
648  ns::[[s^tring]] foo();
649  )cpp",
650 
651  // Variable.
652  R"cpp(
653  namespace A {
654  int [[F^oo]];
655  }
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;
665  {
666  extern int Foo;
667  Baz = Foo;
668  Foo = A::[[F^oo]] + Baz;
669  A::[[Fo^o]] = b.Foo;
670  }
671  Foo = b.Foo;
672  }
673  )cpp",
674 
675  // Namespace alias.
676  R"cpp(
677  namespace a { namespace b { void foo(); } }
678  namespace [[^x]] = a::b;
679  void bar() {
680  [[x^]]::foo();
681  }
682  )cpp",
683 
684  // Enum.
685  R"cpp(
686  enum [[C^olor]] { Red, Green, Blue };
687  void foo() {
688  [[C^olor]] c;
689  c = [[C^olor]]::Blue;
690  }
691  )cpp",
692 
693  // Scoped enum.
694  R"cpp(
695  enum class [[K^ind]] { ABC };
696  void ff() {
697  [[K^ind]] s;
698  s = [[K^ind]]::ABC;
699  }
700  )cpp",
701 
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",
709 
710  // Designated initializer.
711  R"cpp(
712  struct Bar {
713  int [[Fo^o]];
714  };
715  Bar bar { .[[^Foo]] = 42 };
716  )cpp",
717 
718  // Nested designated initializer.
719  R"cpp(
720  struct Baz {
721  int Field;
722  };
723  struct Bar {
724  Baz [[Fo^o]];
725  };
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]];
732  };
733  struct Bar {
734  Baz Foo;
735  };
736  Bar bar { .Foo.[[^Field]] = 42 };
737  )cpp",
738 
739  // Templated alias.
740  R"cpp(
741  template <typename T>
742  class X { T t; };
743 
744  template <typename T>
745  using [[Fo^o]] = X<T>;
746 
747  void bar() {
748  [[Fo^o]]<int> Bar;
749  }
750  )cpp",
751 
752  // Alias.
753  R"cpp(
754  class X {};
755  using [[F^oo]] = X;
756 
757  void bar() {
758  [[Fo^o]] Bar;
759  }
760  )cpp",
761 
762  // Alias within a namespace.
763  R"cpp(
764  namespace x { class X {}; }
765  namespace ns {
766  using [[Fo^o]] = x::X;
767  }
768 
769  void bar() {
770  ns::[[Fo^o]] Bar;
771  }
772  )cpp",
773 
774  // Alias within macros.
775  R"cpp(
776  namespace x { class Old {}; }
777  namespace ns {
778  #define REF(alias) alias alias_var;
779 
780  #define ALIAS(old) \
781  using old##Alias = x::old; \
782  REF(old##Alias);
783 
784  ALIAS(Old);
785 
786  [[Old^Alias]] old_alias;
787  }
788 
789  void bar() {
790  ns::[[Old^Alias]] Bar;
791  }
792  )cpp",
793 
794  // User defined conversion.
795  R"cpp(
796  class [[F^oo]] {
797  public:
798  [[F^oo]]() {}
799  };
800 
801  class Baz {
802  public:
803  operator [[F^oo]]() {
804  return [[F^oo]]();
805  }
806  };
807 
808  int main() {
809  Baz boo;
810  [[F^oo]] foo = static_cast<[[F^oo]]>(boo);
811  }
812  )cpp",
813 
814  // ObjC, should not crash.
815  R"cpp(
816  @interface ObjC {
817  char [[da^ta]];
818  } @end
819  )cpp",
820  };
821  llvm::StringRef NewName = "NewName";
822  for (llvm::StringRef T : Tests) {
823  SCOPED_TRACE(T);
824  Annotations Code(T);
825  auto TU = TestTU::withCode(Code.code());
826  TU.ExtraArgs.push_back("-xobjective-c++");
827  auto AST = TU.build();
828  auto Index = TU.index();
829  for (const auto &RenamePos : Code.points()) {
830  auto RenameResult =
831  rename({RenamePos, NewName, AST, testPath(TU.Filename),
832  getVFSFromAST(AST), Index.get()});
833  ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError();
834  ASSERT_EQ(1u, RenameResult->GlobalChanges.size());
835  EXPECT_EQ(
836  applyEdits(std::move(RenameResult->GlobalChanges)).front().second,
837  expectedResult(Code, NewName));
838  }
839  }
840 }
841 
842 TEST(RenameTest, Renameable) {
843  struct Case {
844  const char *Code;
845  const char* ErrorMessage; // null if no error
846  bool IsHeaderFile;
847  llvm::StringRef NewName = "MockName";
848  };
849  const bool HeaderFile = true;
850  Case Cases[] = {
851  {R"cpp(// allow -- function-local
852  void f(int [[Lo^cal]]) {
853  [[Local]] = 2;
854  }
855  )cpp",
856  nullptr, HeaderFile},
857 
858  {R"cpp(// disallow -- symbol in anonymous namespace in header is not indexable.
859  namespace {
860  class Unin^dexable {};
861  }
862  )cpp",
863  "not eligible for indexing", HeaderFile},
864 
865  {R"cpp(// disallow -- namespace symbol isn't supported
866  namespace n^s {}
867  )cpp",
868  "not a supported kind", HeaderFile},
869 
870  {
871  R"cpp(
872  #define MACRO 1
873  int s = MAC^RO;
874  )cpp",
875  "not a supported kind", HeaderFile},
876 
877  {
878  R"cpp(
879  struct X { X operator++(int); };
880  void f(X x) {x+^+;})cpp",
881  "no symbol", HeaderFile},
882 
883  {R"cpp(// disallow rename on excluded symbols (e.g. std symbols)
884  namespace std {
885  class str^ing {};
886  }
887  )cpp",
888  "not a supported kind", !HeaderFile},
889  {R"cpp(// disallow rename on excluded symbols (e.g. std symbols)
890  namespace std {
891  inline namespace __u {
892  class str^ing {};
893  }
894  }
895  )cpp",
896  "not a supported kind", !HeaderFile},
897 
898  {R"cpp(// disallow rename on non-normal identifiers.
899  @interface Foo {}
900  -(int) fo^o:(int)x; // Token is an identifier, but declaration name isn't a simple identifier.
901  @end
902  )cpp",
903  "not a supported kind", HeaderFile},
904  {R"cpp(// FIXME: rename virtual/override methods is not supported yet.
905  struct A {
906  virtual void f^oo() {}
907  };
908  )cpp",
909  "not a supported kind", !HeaderFile},
910  {R"cpp(
911  void foo(int);
912  void foo(char);
913  template <typename T> void f(T t) {
914  fo^o(t);
915  })cpp",
916  "multiple symbols", !HeaderFile},
917 
918  {R"cpp(// disallow rename on unrelated token.
919  cl^ass Foo {};
920  )cpp",
921  "no symbol", !HeaderFile},
922 
923  {R"cpp(// disallow rename on unrelated token.
924  temp^late<typename T>
925  class Foo {};
926  )cpp",
927  "no symbol", !HeaderFile},
928 
929  {R"cpp(
930  namespace {
931  int Conflict;
932  int Va^r;
933  }
934  )cpp",
935  "conflict", !HeaderFile, "Conflict"},
936 
937  {R"cpp(
938  int Conflict;
939  int Va^r;
940  )cpp",
941  "conflict", !HeaderFile, "Conflict"},
942 
943  {R"cpp(
944  class Foo {
945  int Conflict;
946  int Va^r;
947  };
948  )cpp",
949  "conflict", !HeaderFile, "Conflict"},
950 
951  {R"cpp(
952  enum E {
953  Conflict,
954  Fo^o,
955  };
956  )cpp",
957  "conflict", !HeaderFile, "Conflict"},
958 
959  {R"cpp(
960  int Conflict;
961  enum E { // transparent context.
962  F^oo,
963  };
964  )cpp",
965  "conflict", !HeaderFile, "Conflict"},
966 
967  {R"cpp(
968  void func() {
969  bool Whatever;
970  int V^ar;
971  char Conflict;
972  }
973  )cpp",
974  "conflict", !HeaderFile, "Conflict"},
975 
976  {R"cpp(
977  void func() {
978  if (int Conflict = 42) {
979  int V^ar;
980  }
981  }
982  )cpp",
983  "conflict", !HeaderFile, "Conflict"},
984 
985  {R"cpp(
986  void func() {
987  if (int Conflict = 42) {
988  } else {
989  bool V^ar;
990  }
991  }
992  )cpp",
993  "conflict", !HeaderFile, "Conflict"},
994 
995  {R"cpp(
996  void func() {
997  if (int V^ar = 42) {
998  } else {
999  bool Conflict;
1000  }
1001  }
1002  )cpp",
1003  "conflict", !HeaderFile, "Conflict"},
1004 
1005  {R"cpp(
1006  void func() {
1007  while (int V^ar = 10) {
1008  bool Conflict = true;
1009  }
1010  }
1011  )cpp",
1012  "conflict", !HeaderFile, "Conflict"},
1013 
1014  {R"cpp(
1015  void func() {
1016  for (int Something = 9000, Anything = 14, Conflict = 42; Anything > 9;
1017  ++Something) {
1018  int V^ar;
1019  }
1020  }
1021  )cpp",
1022  "conflict", !HeaderFile, "Conflict"},
1023 
1024  {R"cpp(
1025  void func() {
1026  for (int V^ar = 14, Conflict = 42;;) {
1027  }
1028  }
1029  )cpp",
1030  "conflict", !HeaderFile, "Conflict"},
1031 
1032  {R"cpp(
1033  void func(int Conflict) {
1034  bool V^ar;
1035  }
1036  )cpp",
1037  "conflict", !HeaderFile, "Conflict"},
1038 
1039  {R"cpp(
1040  void func(int Var);
1041 
1042  void func(int V^ar) {
1043  bool Conflict;
1044  }
1045  )cpp",
1046  "conflict", !HeaderFile, "Conflict"},
1047 
1048  {R"cpp(// No conflict: only forward declaration's argument is renamed.
1049  void func(int [[V^ar]]);
1050 
1051  void func(int Var) {
1052  bool Conflict;
1053  }
1054  )cpp",
1055  nullptr, !HeaderFile, "Conflict"},
1056 
1057  {R"cpp(
1058  void func(int V^ar, int Conflict) {
1059  }
1060  )cpp",
1061  "conflict", !HeaderFile, "Conflict"},
1062 
1063  {R"cpp(// Trying to rename into the same name, SameName == SameName.
1064  void func() {
1065  int S^ameName;
1066  }
1067  )cpp",
1068  "new name is the same", !HeaderFile, "SameName"},
1069  {R"cpp(// Ensure it doesn't associate base specifier with base name.
1070  struct A {};
1071  struct B : priv^ate A {};
1072  )cpp",
1073  "Cannot rename symbol: there is no symbol at the given location", false},
1074  {R"cpp(// Ensure it doesn't associate base specifier with base name.
1075  /*error-ok*/
1076  struct A {
1077  A() : inva^lid(0) {}
1078  };
1079  )cpp",
1080  "no symbol", false},
1081  };
1082 
1083  for (const auto& Case : Cases) {
1084  SCOPED_TRACE(Case.Code);
1085  Annotations T(Case.Code);
1086  TestTU TU = TestTU::withCode(T.code());
1087  TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
1088  if (Case.IsHeaderFile) {
1089  // We open the .h file as the main file.
1090  TU.Filename = "test.h";
1091  // Parsing the .h file as C++ include.
1092  TU.ExtraArgs.push_back("-xobjective-c++-header");
1093  }
1094  auto AST = TU.build();
1095  llvm::StringRef NewName = Case.NewName;
1096  auto Results = rename({T.point(), NewName, AST, testPath(TU.Filename)});
1097  bool WantRename = true;
1098  if (T.ranges().empty())
1099  WantRename = false;
1100  if (!WantRename) {
1101  assert(Case.ErrorMessage && "Error message must be set!");
1102  EXPECT_FALSE(Results)
1103  << "expected rename returned an error: " << T.code();
1104  auto ActualMessage = llvm::toString(Results.takeError());
1105  EXPECT_THAT(ActualMessage, testing::HasSubstr(Case.ErrorMessage));
1106  } else {
1107  EXPECT_TRUE(bool(Results)) << "rename returned an error: "
1108  << llvm::toString(Results.takeError());
1109  ASSERT_EQ(1u, Results->GlobalChanges.size());
1110  EXPECT_EQ(applyEdits(std::move(Results->GlobalChanges)).front().second,
1111  expectedResult(T, NewName));
1112  }
1113  }
1114 }
1115 
1116 MATCHER_P(newText, T, "") { return arg.newText == T; }
1117 
1118 TEST(RenameTest, IndexMergeMainFile) {
1119  Annotations Code("int ^x();");
1120  TestTU TU = TestTU::withCode(Code.code());
1121  TU.Filename = "main.cc";
1122  auto AST = TU.build();
1123 
1124  auto Main = testPath("main.cc");
1125  auto InMemFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
1126  InMemFS->addFile(testPath("main.cc"), 0,
1127  llvm::MemoryBuffer::getMemBuffer(Code.code()));
1128  InMemFS->addFile(testPath("other.cc"), 0,
1129  llvm::MemoryBuffer::getMemBuffer(Code.code()));
1130 
1131  auto Rename = [&](const SymbolIndex *Idx) {
1132  RenameInputs Inputs{Code.point(),
1133  "xPrime",
1134  AST,
1135  Main,
1136  Idx ? createOverlay(getVFSFromAST(AST), InMemFS)
1137  : nullptr,
1138  Idx,
1139  RenameOptions()};
1140  auto Results = rename(Inputs);
1141  EXPECT_TRUE(bool(Results)) << llvm::toString(Results.takeError());
1142  return std::move(*Results);
1143  };
1144 
1145  // We do not expect to see duplicated edits from AST vs index.
1146  auto Results = Rename(TU.index().get());
1147  EXPECT_THAT(Results.GlobalChanges.keys(), ElementsAre(Main));
1148  EXPECT_THAT(Results.GlobalChanges[Main].asTextEdits(),
1149  ElementsAre(newText("xPrime")));
1150 
1151  // Sanity check: we do expect to see index results!
1152  TU.Filename = "other.cc";
1153  Results = Rename(TU.index().get());
1154  EXPECT_THAT(Results.GlobalChanges.keys(),
1155  UnorderedElementsAre(Main, testPath("other.cc")));
1156 
1157 #ifdef CLANGD_PATH_CASE_INSENSITIVE
1158  // On case-insensitive systems, no duplicates if AST vs index case differs.
1159  // https://github.com/clangd/clangd/issues/665
1160  TU.Filename = "MAIN.CC";
1161  Results = Rename(TU.index().get());
1162  EXPECT_THAT(Results.GlobalChanges.keys(), ElementsAre(Main));
1163  EXPECT_THAT(Results.GlobalChanges[Main].asTextEdits(),
1164  ElementsAre(newText("xPrime")));
1165 #endif
1166 }
1167 
1168 TEST(RenameTest, MainFileReferencesOnly) {
1169  // filter out references not from main file.
1170  llvm::StringRef Test =
1171  R"cpp(
1172  void test() {
1173  int [[fo^o]] = 1;
1174  // rename references not from main file are not included.
1175  #include "foo.inc"
1176  })cpp";
1177 
1178  Annotations Code(Test);
1179  auto TU = TestTU::withCode(Code.code());
1180  TU.AdditionalFiles["foo.inc"] = R"cpp(
1181  #define Macro(X) X
1182  &Macro(foo);
1183  &foo;
1184  )cpp";
1185  auto AST = TU.build();
1186  llvm::StringRef NewName = "abcde";
1187 
1188  auto RenameResult =
1189  rename({Code.point(), NewName, AST, testPath(TU.Filename)});
1190  ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError() << Code.point();
1191  ASSERT_EQ(1u, RenameResult->GlobalChanges.size());
1192  EXPECT_EQ(applyEdits(std::move(RenameResult->GlobalChanges)).front().second,
1193  expectedResult(Code, NewName));
1194 }
1195 
1196 TEST(RenameTest, ProtobufSymbolIsExcluded) {
1197  Annotations Code("Prot^obuf buf;");
1198  auto TU = TestTU::withCode(Code.code());
1199  TU.HeaderCode =
1200  R"cpp(// Generated by the protocol buffer compiler. DO NOT EDIT!
1201  class Protobuf {};
1202  )cpp";
1203  TU.HeaderFilename = "protobuf.pb.h";
1204  auto AST = TU.build();
1205  auto Results = rename({Code.point(), "newName", AST, testPath(TU.Filename)});
1206  EXPECT_FALSE(Results);
1207  EXPECT_THAT(llvm::toString(Results.takeError()),
1208  testing::HasSubstr("not a supported kind"));
1209 }
1210 
1211 TEST(RenameTest, PrepareRename) {
1212  Annotations FooH("void func();");
1213  Annotations FooCC(R"cpp(
1214  #include "foo.h"
1215  void [[fu^nc]]() {}
1216  )cpp");
1217  std::string FooHPath = testPath("foo.h");
1218  std::string FooCCPath = testPath("foo.cc");
1219  MockFS FS;
1220  FS.Files[FooHPath] = std::string(FooH.code());
1221  FS.Files[FooCCPath] = std::string(FooCC.code());
1222 
1223  auto ServerOpts = ClangdServer::optsForTest();
1224  ServerOpts.BuildDynamicSymbolIndex = true;
1225 
1226  trace::TestTracer Tracer;
1227  MockCompilationDatabase CDB;
1228  ClangdServer Server(CDB, FS, ServerOpts);
1229  runAddDocument(Server, FooHPath, FooH.code());
1230  runAddDocument(Server, FooCCPath, FooCC.code());
1231 
1232  auto Results = runPrepareRename(Server, FooCCPath, FooCC.point(),
1233  /*NewName=*/llvm::None, {});
1234  // Verify that for multi-file rename, we only return main-file occurrences.
1235  ASSERT_TRUE(bool(Results)) << Results.takeError();
1236  // We don't know the result is complete in prepareRename (passing a nullptr
1237  // index internally), so GlobalChanges should be empty.
1238  EXPECT_TRUE(Results->GlobalChanges.empty());
1239  EXPECT_THAT(FooCC.ranges(),
1240  testing::UnorderedElementsAreArray(Results->LocalChanges));
1241 
1242  // Name validation.
1243  Results = runPrepareRename(Server, FooCCPath, FooCC.point(),
1244  /*NewName=*/std::string("int"), {});
1245  EXPECT_FALSE(Results);
1246  EXPECT_THAT(llvm::toString(Results.takeError()),
1247  testing::HasSubstr("keyword"));
1248  EXPECT_THAT(Tracer.takeMetric("rename_name_invalid", "Keywords"),
1249  ElementsAre(1));
1250 
1251  for (std::string BadIdent : {"foo!bar", "123foo", "😀@"}) {
1252  Results = runPrepareRename(Server, FooCCPath, FooCC.point(),
1253  /*NewName=*/BadIdent, {});
1254  EXPECT_FALSE(Results);
1255  EXPECT_THAT(llvm::toString(Results.takeError()),
1256  testing::HasSubstr("identifier"));
1257  EXPECT_THAT(Tracer.takeMetric("rename_name_invalid", "BadIdentifier"),
1258  ElementsAre(1));
1259  }
1260  for (std::string GoodIdent : {"fooBar", "__foo$", "😀"}) {
1261  Results = runPrepareRename(Server, FooCCPath, FooCC.point(),
1262  /*NewName=*/GoodIdent, {});
1263  EXPECT_TRUE(bool(Results));
1264  }
1265 }
1266 
1267 TEST(CrossFileRenameTests, DirtyBuffer) {
1268  Annotations FooCode("class [[Foo]] {};");
1269  std::string FooPath = testPath("foo.cc");
1270  Annotations FooDirtyBuffer("class [[Foo]] {};\n// this is dirty buffer");
1271  Annotations BarCode("void [[Bar]]() {}");
1272  std::string BarPath = testPath("bar.cc");
1273  // Build the index, the index has "Foo" references from foo.cc and "Bar"
1274  // references from bar.cc.
1275  FileSymbols FSymbols(IndexContents::All);
1276  FSymbols.update(FooPath, nullptr, buildRefSlab(FooCode, "Foo", FooPath),
1277  nullptr, false);
1278  FSymbols.update(BarPath, nullptr, buildRefSlab(BarCode, "Bar", BarPath),
1279  nullptr, false);
1280  auto Index = FSymbols.buildIndex(IndexType::Light);
1281 
1282  Annotations MainCode("class [[Fo^o]] {};");
1283  auto MainFilePath = testPath("main.cc");
1284  llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemFS =
1286  InMemFS->addFile(FooPath, 0,
1287  llvm::MemoryBuffer::getMemBuffer(FooDirtyBuffer.code()));
1288 
1289  // Run rename on Foo, there is a dirty buffer for foo.cc, rename should
1290  // respect the dirty buffer.
1291  TestTU TU = TestTU::withCode(MainCode.code());
1292  auto AST = TU.build();
1293  llvm::StringRef NewName = "newName";
1294  auto Results =
1295  rename({MainCode.point(), NewName, AST, MainFilePath,
1296  createOverlay(getVFSFromAST(AST), InMemFS), Index.get()});
1297  ASSERT_TRUE(bool(Results)) << Results.takeError();
1298  EXPECT_THAT(
1299  applyEdits(std::move(Results->GlobalChanges)),
1300  UnorderedElementsAre(
1301  Pair(Eq(FooPath), Eq(expectedResult(FooDirtyBuffer, NewName))),
1302  Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName)))));
1303 
1304  // Run rename on Bar, there is no dirty buffer for the affected file bar.cc,
1305  // so we should read file content from VFS.
1306  MainCode = Annotations("void [[Bar]]() { [[B^ar]](); }");
1307  TU = TestTU::withCode(MainCode.code());
1308  // Set a file "bar.cc" on disk.
1309  TU.AdditionalFiles["bar.cc"] = std::string(BarCode.code());
1310  AST = TU.build();
1311  Results = rename({MainCode.point(), NewName, AST, MainFilePath,
1312  createOverlay(getVFSFromAST(AST), InMemFS), Index.get()});
1313  ASSERT_TRUE(bool(Results)) << Results.takeError();
1314  EXPECT_THAT(
1315  applyEdits(std::move(Results->GlobalChanges)),
1316  UnorderedElementsAre(
1317  Pair(Eq(BarPath), Eq(expectedResult(BarCode, NewName))),
1318  Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName)))));
1319 
1320  // Run rename on a pagination index which couldn't return all refs in one
1321  // request, we reject rename on this case.
1322  class PaginationIndex : public SymbolIndex {
1323  bool refs(const RefsRequest &Req,
1324  llvm::function_ref<void(const Ref &)> Callback) const override {
1325  return true; // has more references
1326  }
1327 
1328  bool fuzzyFind(
1329  const FuzzyFindRequest &Req,
1330  llvm::function_ref<void(const Symbol &)> Callback) const override {
1331  return false;
1332  }
1333  void
1334  lookup(const LookupRequest &Req,
1335  llvm::function_ref<void(const Symbol &)> Callback) const override {}
1336 
1337  void relations(const RelationsRequest &Req,
1338  llvm::function_ref<void(const SymbolID &, const Symbol &)>
1339  Callback) const override {}
1340 
1341  llvm::unique_function<IndexContents(llvm::StringRef) const>
1342  indexedFiles() const override {
1343  return [](llvm::StringRef) { return IndexContents::None; };
1344  }
1345 
1346  size_t estimateMemoryUsage() const override { return 0; }
1347  } PIndex;
1348  Results = rename({MainCode.point(), NewName, AST, MainFilePath,
1349  createOverlay(getVFSFromAST(AST), InMemFS), &PIndex});
1350  EXPECT_FALSE(Results);
1351  EXPECT_THAT(llvm::toString(Results.takeError()),
1352  testing::HasSubstr("too many occurrences"));
1353 }
1354 
1355 TEST(CrossFileRenameTests, DeduplicateRefsFromIndex) {
1356  auto MainCode = Annotations("int [[^x]] = 2;");
1357  auto MainFilePath = testPath("main.cc");
1358  auto BarCode = Annotations("int [[x]];");
1359  auto BarPath = testPath("bar.cc");
1360  auto TU = TestTU::withCode(MainCode.code());
1361  // Set a file "bar.cc" on disk.
1362  TU.AdditionalFiles["bar.cc"] = std::string(BarCode.code());
1363  auto AST = TU.build();
1364  std::string BarPathURI = URI::create(BarPath).toString();
1365  Ref XRefInBarCC = refWithRange(BarCode.range(), BarPathURI);
1366  // The index will return duplicated refs, our code should be robost to handle
1367  // it.
1368  class DuplicatedXRefIndex : public SymbolIndex {
1369  public:
1370  DuplicatedXRefIndex(const Ref &ReturnedRef) : ReturnedRef(ReturnedRef) {}
1371  bool refs(const RefsRequest &Req,
1372  llvm::function_ref<void(const Ref &)> Callback) const override {
1373  // Return two duplicated refs.
1374  Callback(ReturnedRef);
1375  Callback(ReturnedRef);
1376  return false;
1377  }
1378 
1379  bool fuzzyFind(const FuzzyFindRequest &,
1380  llvm::function_ref<void(const Symbol &)>) const override {
1381  return false;
1382  }
1383  void lookup(const LookupRequest &,
1384  llvm::function_ref<void(const Symbol &)>) const override {}
1385 
1386  void relations(const RelationsRequest &,
1387  llvm::function_ref<void(const SymbolID &, const Symbol &)>)
1388  const override {}
1389 
1390  llvm::unique_function<IndexContents(llvm::StringRef) const>
1391  indexedFiles() const override {
1392  return [](llvm::StringRef) { return IndexContents::None; };
1393  }
1394 
1395  size_t estimateMemoryUsage() const override { return 0; }
1396  Ref ReturnedRef;
1397  } DIndex(XRefInBarCC);
1398  llvm::StringRef NewName = "newName";
1399  auto Results = rename({MainCode.point(), NewName, AST, MainFilePath,
1400  getVFSFromAST(AST), &DIndex});
1401  ASSERT_TRUE(bool(Results)) << Results.takeError();
1402  EXPECT_THAT(
1403  applyEdits(std::move(Results->GlobalChanges)),
1404  UnorderedElementsAre(
1405  Pair(Eq(BarPath), Eq(expectedResult(BarCode, NewName))),
1406  Pair(Eq(MainFilePath), Eq(expectedResult(MainCode, NewName)))));
1407 }
1408 
1409 TEST(CrossFileRenameTests, WithUpToDateIndex) {
1410  MockCompilationDatabase CDB;
1411  CDB.ExtraClangFlags = {"-xc++"};
1412  // rename is runnning on all "^" points in FooH, and "[[]]" ranges are the
1413  // expected rename occurrences.
1414  struct Case {
1415  llvm::StringRef FooH;
1416  llvm::StringRef FooCC;
1417  } Cases[] = {
1418  {
1419  // classes.
1420  R"cpp(
1421  class [[Fo^o]] {
1422  [[Foo]]();
1423  ~[[Foo]]();
1424  };
1425  )cpp",
1426  R"cpp(
1427  #include "foo.h"
1428  [[Foo]]::[[Foo]]() {}
1429  [[Foo]]::~[[Foo]]() {}
1430 
1431  void func() {
1432  [[Foo]] foo;
1433  }
1434  )cpp",
1435  },
1436  {
1437  // class templates.
1438  R"cpp(
1439  template <typename T>
1440  class [[Foo]] {};
1441  // FIXME: explicit template specializations are not supported due the
1442  // clangd index limitations.
1443  template <>
1444  class Foo<double> {};
1445  )cpp",
1446  R"cpp(
1447  #include "foo.h"
1448  void func() {
1449  [[F^oo]]<int> foo;
1450  }
1451  )cpp",
1452  },
1453  {
1454  // class methods.
1455  R"cpp(
1456  class Foo {
1457  void [[f^oo]]();
1458  };
1459  )cpp",
1460  R"cpp(
1461  #include "foo.h"
1462  void Foo::[[foo]]() {}
1463 
1464  void func(Foo* p) {
1465  p->[[foo]]();
1466  }
1467  )cpp",
1468  },
1469  {
1470  // rename on constructor and destructor.
1471  R"cpp(
1472  class [[Foo]] {
1473  [[^Foo]]();
1474  ~[[Foo^]]();
1475  };
1476  )cpp",
1477  R"cpp(
1478  #include "foo.h"
1479  [[Foo]]::[[Foo]]() {}
1480  [[Foo]]::~[[Foo]]() {}
1481 
1482  void func() {
1483  [[Foo]] foo;
1484  }
1485  )cpp",
1486  },
1487  {
1488  // functions.
1489  R"cpp(
1490  void [[f^oo]]();
1491  )cpp",
1492  R"cpp(
1493  #include "foo.h"
1494  void [[foo]]() {}
1495 
1496  void func() {
1497  [[foo]]();
1498  }
1499  )cpp",
1500  },
1501  {
1502  // typedefs.
1503  R"cpp(
1504  typedef int [[IN^T]];
1505  [[INT]] foo();
1506  )cpp",
1507  R"cpp(
1508  #include "foo.h"
1509  [[INT]] foo() {}
1510  )cpp",
1511  },
1512  {
1513  // usings.
1514  R"cpp(
1515  using [[I^NT]] = int;
1516  [[INT]] foo();
1517  )cpp",
1518  R"cpp(
1519  #include "foo.h"
1520  [[INT]] foo() {}
1521  )cpp",
1522  },
1523  {
1524  // variables.
1525  R"cpp(
1526  static const int [[VA^R]] = 123;
1527  )cpp",
1528  R"cpp(
1529  #include "foo.h"
1530  int s = [[VAR]];
1531  )cpp",
1532  },
1533  {
1534  // scope enums.
1535  R"cpp(
1536  enum class [[K^ind]] { ABC };
1537  )cpp",
1538  R"cpp(
1539  #include "foo.h"
1540  [[Kind]] ff() {
1541  return [[Kind]]::ABC;
1542  }
1543  )cpp",
1544  },
1545  {
1546  // enum constants.
1547  R"cpp(
1548  enum class Kind { [[A^BC]] };
1549  )cpp",
1550  R"cpp(
1551  #include "foo.h"
1552  Kind ff() {
1553  return Kind::[[ABC]];
1554  }
1555  )cpp",
1556  },
1557  {
1558  // Implicit references in macro expansions.
1559  R"cpp(
1560  class [[Fo^o]] {};
1561  #define FooFoo Foo
1562  #define FOO Foo
1563  )cpp",
1564  R"cpp(
1565  #include "foo.h"
1566  void bar() {
1567  [[Foo]] x;
1568  FOO y;
1569  FooFoo z;
1570  }
1571  )cpp",
1572  },
1573  };
1574 
1575  trace::TestTracer Tracer;
1576  for (const auto &T : Cases) {
1577  SCOPED_TRACE(T.FooH);
1578  Annotations FooH(T.FooH);
1579  Annotations FooCC(T.FooCC);
1580  std::string FooHPath = testPath("foo.h");
1581  std::string FooCCPath = testPath("foo.cc");
1582 
1583  MockFS FS;
1584  FS.Files[FooHPath] = std::string(FooH.code());
1585  FS.Files[FooCCPath] = std::string(FooCC.code());
1586 
1587  auto ServerOpts = ClangdServer::optsForTest();
1588  ServerOpts.BuildDynamicSymbolIndex = true;
1589  ClangdServer Server(CDB, FS, ServerOpts);
1590 
1591  // Add all files to clangd server to make sure the dynamic index has been
1592  // built.
1593  runAddDocument(Server, FooHPath, FooH.code());
1594  runAddDocument(Server, FooCCPath, FooCC.code());
1595 
1596  llvm::StringRef NewName = "NewName";
1597  for (const auto &RenamePos : FooH.points()) {
1598  EXPECT_THAT(Tracer.takeMetric("rename_files"), SizeIs(0));
1599  auto FileEditsList =
1600  llvm::cantFail(runRename(Server, FooHPath, RenamePos, NewName, {}));
1601  EXPECT_THAT(Tracer.takeMetric("rename_files"), ElementsAre(2));
1602  EXPECT_THAT(
1603  applyEdits(std::move(FileEditsList.GlobalChanges)),
1604  UnorderedElementsAre(
1605  Pair(Eq(FooHPath), Eq(expectedResult(T.FooH, NewName))),
1606  Pair(Eq(FooCCPath), Eq(expectedResult(T.FooCC, NewName)))));
1607  }
1608  }
1609 }
1610 
1611 TEST(CrossFileRenameTests, CrossFileOnLocalSymbol) {
1612  // cross-file rename should work for function-local symbols, even there is no
1613  // index provided.
1614  Annotations Code("void f(int [[abc]]) { [[a^bc]] = 3; }");
1615  auto TU = TestTU::withCode(Code.code());
1616  auto Path = testPath(TU.Filename);
1617  auto AST = TU.build();
1618  llvm::StringRef NewName = "newName";
1619  auto Results = rename({Code.point(), NewName, AST, Path});
1620  ASSERT_TRUE(bool(Results)) << Results.takeError();
1621  EXPECT_THAT(
1622  applyEdits(std::move(Results->GlobalChanges)),
1623  UnorderedElementsAre(Pair(Eq(Path), Eq(expectedResult(Code, NewName)))));
1624 }
1625 
1626 TEST(CrossFileRenameTests, BuildRenameEdits) {
1627  Annotations Code("[[😂]]");
1628  auto LSPRange = Code.range();
1629  llvm::StringRef FilePath = "/test/TestTU.cpp";
1630  llvm::StringRef NewName = "abc";
1631  auto Edit = buildRenameEdit(FilePath, Code.code(), {LSPRange}, NewName);
1632  ASSERT_TRUE(bool(Edit)) << Edit.takeError();
1633  ASSERT_EQ(1UL, Edit->Replacements.size());
1634  EXPECT_EQ(FilePath, Edit->Replacements.begin()->getFilePath());
1635  EXPECT_EQ(4UL, Edit->Replacements.begin()->getLength());
1636 
1637  // Test invalid range.
1638  LSPRange.end = {10, 0}; // out of range
1639  Edit = buildRenameEdit(FilePath, Code.code(), {LSPRange}, NewName);
1640  EXPECT_FALSE(Edit);
1641  EXPECT_THAT(llvm::toString(Edit.takeError()),
1642  testing::HasSubstr("fail to convert"));
1643 
1644  // Normal ascii characters.
1645  Annotations T(R"cpp(
1646  [[range]]
1647  [[range]]
1648  [[range]]
1649  )cpp");
1650  Edit = buildRenameEdit(FilePath, T.code(), T.ranges(), NewName);
1651  ASSERT_TRUE(bool(Edit)) << Edit.takeError();
1652  EXPECT_EQ(applyEdits(FileEdits{{T.code(), std::move(*Edit)}}).front().second,
1653  expectedResult(T, NewName));
1654 }
1655 
1656 TEST(CrossFileRenameTests, adjustRenameRanges) {
1657  // Ranges in IndexedCode indicate the indexed occurrences;
1658  // ranges in DraftCode indicate the expected mapped result, empty indicates
1659  // we expect no matched result found.
1660  struct {
1661  llvm::StringRef IndexedCode;
1662  llvm::StringRef DraftCode;
1663  } Tests[] = {
1664  {
1665  // both line and column are changed, not a near miss.
1666  R"cpp(
1667  int [[x]] = 0;
1668  )cpp",
1669  R"cpp(
1670  // insert a line.
1671  double x = 0;
1672  )cpp",
1673  },
1674  {
1675  // subset.
1676  R"cpp(
1677  int [[x]] = 0;
1678  )cpp",
1679  R"cpp(
1680  int [[x]] = 0;
1681  {int x = 0; }
1682  )cpp",
1683  },
1684  {
1685  // shift columns.
1686  R"cpp(int [[x]] = 0; void foo(int x);)cpp",
1687  R"cpp(double [[x]] = 0; void foo(double x);)cpp",
1688  },
1689  {
1690  // shift lines.
1691  R"cpp(
1692  int [[x]] = 0;
1693  void foo(int x);
1694  )cpp",
1695  R"cpp(
1696  // insert a line.
1697  int [[x]] = 0;
1698  void foo(int x);
1699  )cpp",
1700  },
1701  };
1702  LangOptions LangOpts;
1703  LangOpts.CPlusPlus = true;
1704  for (const auto &T : Tests) {
1705  SCOPED_TRACE(T.DraftCode);
1706  Annotations Draft(T.DraftCode);
1707  auto ActualRanges = adjustRenameRanges(
1708  Draft.code(), "x", Annotations(T.IndexedCode).ranges(), LangOpts);
1709  if (!ActualRanges)
1710  EXPECT_THAT(Draft.ranges(), testing::IsEmpty());
1711  else
1712  EXPECT_THAT(Draft.ranges(),
1713  testing::UnorderedElementsAreArray(*ActualRanges));
1714  }
1715 }
1716 
1717 TEST(RangePatchingHeuristic, GetMappedRanges) {
1718  // ^ in LexedCode marks the ranges we expect to be mapped; no ^ indicates
1719  // there are no mapped ranges.
1720  struct {
1721  llvm::StringRef IndexedCode;
1722  llvm::StringRef LexedCode;
1723  } Tests[] = {
1724  {
1725  // no lexed ranges.
1726  "[[]]",
1727  "",
1728  },
1729  {
1730  // both line and column are changed, not a near miss.
1731  R"([[]])",
1732  R"(
1733  [[]]
1734  )",
1735  },
1736  {
1737  // subset.
1738  "[[]]",
1739  "^[[]] [[]]"
1740  },
1741  {
1742  // shift columns.
1743  "[[]] [[]]",
1744  " ^[[]] ^[[]] [[]]"
1745  },
1746  {
1747  R"(
1748  [[]]
1749 
1750  [[]] [[]]
1751  )",
1752  R"(
1753  // insert a line
1754  ^[[]]
1755 
1756  ^[[]] ^[[]]
1757  )",
1758  },
1759  {
1760  R"(
1761  [[]]
1762 
1763  [[]] [[]]
1764  )",
1765  R"(
1766  // insert a line
1767  ^[[]]
1768  ^[[]] ^[[]] // column is shifted.
1769  )",
1770  },
1771  {
1772  R"(
1773  [[]]
1774 
1775  [[]] [[]]
1776  )",
1777  R"(
1778  // insert a line
1779  [[]]
1780 
1781  [[]] [[]] // not mapped (both line and column are changed).
1782  )",
1783  },
1784  {
1785  R"(
1786  [[]]
1787  [[]]
1788 
1789  [[]]
1790  [[]]
1791 
1792  }
1793  )",
1794  R"(
1795  // insert a new line
1796  ^[[]]
1797  ^[[]]
1798  [[]] // additional range
1799  ^[[]]
1800  ^[[]]
1801  [[]] // additional range
1802  )",
1803  },
1804  {
1805  // non-distinct result (two best results), not a near miss
1806  R"(
1807  [[]]
1808  [[]]
1809  [[]]
1810  )",
1811  R"(
1812  [[]]
1813  [[]]
1814  [[]]
1815  [[]]
1816  )",
1817  }
1818  };
1819  for (const auto &T : Tests) {
1820  SCOPED_TRACE(T.IndexedCode);
1821  auto Lexed = Annotations(T.LexedCode);
1822  auto LexedRanges = Lexed.ranges();
1823  std::vector<Range> ExpectedMatches;
1824  for (auto P : Lexed.points()) {
1825  auto Match = llvm::find_if(LexedRanges, [&P](const Range& R) {
1826  return R.start == P;
1827  });
1828  ASSERT_NE(Match, LexedRanges.end());
1829  ExpectedMatches.push_back(*Match);
1830  }
1831 
1832  auto Mapped =
1833  getMappedRanges(Annotations(T.IndexedCode).ranges(), LexedRanges);
1834  if (!Mapped)
1835  EXPECT_THAT(ExpectedMatches, IsEmpty());
1836  else
1837  EXPECT_THAT(ExpectedMatches, UnorderedElementsAreArray(*Mapped));
1838  }
1839 }
1840 
1841 TEST(CrossFileRenameTests, adjustmentCost) {
1842  struct {
1843  llvm::StringRef RangeCode;
1844  size_t ExpectedCost;
1845  } Tests[] = {
1846  {
1847  R"(
1848  $idx[[]]$lex[[]] // diff: 0
1849  )",
1850  0,
1851  },
1852  {
1853  R"(
1854  $idx[[]]
1855  $lex[[]] // line diff: +1
1856  $idx[[]]
1857  $lex[[]] // line diff: +1
1858  $idx[[]]
1859  $lex[[]] // line diff: +1
1860 
1861  $idx[[]]
1862 
1863  $lex[[]] // line diff: +2
1864  )",
1865  1 + 1
1866  },
1867  {
1868  R"(
1869  $idx[[]]
1870  $lex[[]] // line diff: +1
1871  $idx[[]]
1872 
1873  $lex[[]] // line diff: +2
1874  $idx[[]]
1875 
1876 
1877  $lex[[]] // line diff: +3
1878  )",
1879  1 + 1 + 1
1880  },
1881  {
1882  R"(
1883  $idx[[]]
1884 
1885 
1886  $lex[[]] // line diff: +3
1887  $idx[[]]
1888 
1889  $lex[[]] // line diff: +2
1890  $idx[[]]
1891  $lex[[]] // line diff: +1
1892  )",
1893  3 + 1 + 1
1894  },
1895  {
1896  R"(
1897  $idx[[]]
1898  $lex[[]] // line diff: +1
1899  $lex[[]] // line diff: -2
1900 
1901  $idx[[]]
1902  $idx[[]]
1903 
1904 
1905  $lex[[]] // line diff: +3
1906  )",
1907  1 + 3 + 5
1908  },
1909  {
1910  R"(
1911  $idx[[]] $lex[[]] // column diff: +1
1912  $idx[[]]$lex[[]] // diff: 0
1913  )",
1914  1
1915  },
1916  {
1917  R"(
1918  $idx[[]]
1919  $lex[[]] // diff: +1
1920  $idx[[]] $lex[[]] // column diff: +1
1921  $idx[[]]$lex[[]] // diff: 0
1922  )",
1923  1 + 1 + 1
1924  },
1925  {
1926  R"(
1927  $idx[[]] $lex[[]] // column diff: +1
1928  )",
1929  1
1930  },
1931  {
1932  R"(
1933  // column diffs: +1, +2, +3
1934  $idx[[]] $lex[[]] $idx[[]] $lex[[]] $idx[[]] $lex[[]]
1935  )",
1936  1 + 1 + 1,
1937  },
1938  };
1939  for (const auto &T : Tests) {
1940  SCOPED_TRACE(T.RangeCode);
1941  Annotations C(T.RangeCode);
1942  std::vector<size_t> MappedIndex;
1943  for (size_t I = 0; I < C.ranges("lex").size(); ++I)
1944  MappedIndex.push_back(I);
1945  EXPECT_EQ(renameRangeAdjustmentCost(C.ranges("idx"), C.ranges("lex"),
1946  MappedIndex),
1947  T.ExpectedCost);
1948  }
1949 }
1950 
1951 } // namespace
1952 } // namespace clangd
1953 } // namespace clang
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:38
Base
std::unique_ptr< GlobalCompilationDatabase > Base
Definition: GlobalCompilationDatabaseTests.cpp:90
clang::clangd::TEST
TEST(BackgroundQueueTest, Priority)
Definition: BackgroundIndexTests.cpp:751
clang::clangd::rename
llvm::Expected< RenameResult > rename(const RenameInputs &RInputs)
Renames all occurrences of the symbol.
Definition: Rename.cpp:697
clang::clangd::testPath
std::string testPath(PathRef File, llvm::sys::path::Style Style)
Definition: TestFS.cpp:82
clang::clangd::Symbol::ID
SymbolID ID
The ID of the symbol.
Definition: Symbol.h:38
clang::clangd::Path
std::string Path
A typedef to represent a file path.
Definition: Path.h:26
Tracer
std::unique_ptr< trace::EventTracer > Tracer
Definition: TraceTests.cpp:164
clang::clangd::URI::create
static llvm::Expected< URI > create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme)
Creates a URI for a file in the given scheme.
Definition: URI.cpp:211
TestTU.h
clang::clangd::ClangdServer::optsForTest
static Options optsForTest()
Definition: ClangdServer.cpp:135
clang::clangd::runAddDocument
void runAddDocument(ClangdServer &Server, PathRef File, llvm::StringRef Contents, llvm::StringRef Version, WantDiagnostics WantDiags, bool ForceRebuild)
Definition: SyncAPI.cpp:15
clang::clangd::runPrepareRename
llvm::Expected< RenameResult > runPrepareRename(ClangdServer &Server, PathRef File, Position Pos, llvm::Optional< std::string > NewName, const RenameOptions &RenameOpts)
Definition: SyncAPI.cpp:109
clang::clangd::ParsedAST::build
static llvm::Optional< ParsedAST > build(llvm::StringRef Filename, const ParseInputs &Inputs, std::unique_ptr< clang::CompilerInvocation > CI, llvm::ArrayRef< Diag > CompilerInvocationDiags, std::shared_ptr< const PreambleData > Preamble)
Attempts to run Clang and store the parsed AST.
Definition: ParsedAST.cpp:248
Inputs
ParseInputs Inputs
Definition: TUScheduler.cpp:451
Rename.h
Code
std::string Code
Definition: FindTargetTests.cpp:67
Builder
CodeCompletionBuilder Builder
Definition: CodeCompletionStringsTests.cpp:36
TestFS.h
clang::clangd::IndexContents
IndexContents
Describes what data is covered by an index.
Definition: Index.h:91
SyncAPI.h
clang::clangd::buildRenameEdit
llvm::Expected< Edit > buildRenameEdit(llvm::StringRef AbsFilePath, llvm::StringRef InitialCode, std::vector< Range > Occurrences, llvm::StringRef NewName)
Generates rename edits that replaces all given occurrences with the NewName.
Definition: Rename.cpp:810
clang::clangd::RefKind::Reference
@ Reference
Results
std::vector< CodeCompletionResult > Results
Definition: CodeComplete.cpp:771
clang::doc::SymbolID
std::array< uint8_t, 20 > SymbolID
Definition: Representation.h:30
clang::clangd::TestTU::withCode
static TestTU withCode(llvm::StringRef Code)
Definition: TestTU.h:37
Annotations.h
clang::clangd::lookup
std::vector< std::string > lookup(const SymbolIndex &I, llvm::ArrayRef< SymbolID > IDs)
Definition: TestIndex.cpp:106
clang::clangd::runRename
llvm::Expected< RenameResult > runRename(ClangdServer &Server, PathRef File, Position Pos, llvm::StringRef NewName, const RenameOptions &RenameOpts)
Definition: SyncAPI.cpp:100
clang::clangd::getMappedRanges
llvm::Optional< std::vector< Range > > getMappedRanges(ArrayRef< Range > Indexed, ArrayRef< Range > Lexed)
Calculates the lexed occurrences that the given indexed occurrences map to.
Definition: Rename.cpp:889
TestTracer.h
clang::clangd::IndexContents::All
@ All
Index
const SymbolIndex * Index
Definition: Dexp.cpp:99
InMemoryFileSystem
llvm::IntrusiveRefCntPtr< llvm::vfs::InMemoryFileSystem > InMemoryFileSystem
Definition: IndexActionTests.cpp:109
clang::clangd::RefKind::Spelled
@ Spelled
clang::clangd::IndexContents::None
@ None
clang::clangd::MATCHER_P
MATCHER_P(Named, N, "")
Definition: BackgroundIndexTests.cpp:31
Ref.h
C
const Criteria C
Definition: FunctionCognitiveComplexityCheck.cpp:93
clang::tidy::readability::ErrorMessage
const char ErrorMessage[]
Definition: IdentifierLengthCheck.cpp:30
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::renameRangeAdjustmentCost
size_t renameRangeAdjustmentCost(ArrayRef< Range > Indexed, ArrayRef< Range > Lexed, ArrayRef< size_t > MappedIndex)
Evaluates how good the mapped result is.
Definition: Rename.cpp:957
ClangdServer.h
clang::tidy::cppcoreguidelines::toString
static llvm::StringRef toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K)
Definition: SpecialMemberFunctionsCheck.cpp:55
clang::clangd::FileEdits
llvm::StringMap< Edit > FileEdits
A mapping from absolute file path (the one used for accessing the underlying VFS) to edits.
Definition: SourceCode.h:203
clang::clangd::Callback
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Function.h:28
clang::clangd::adjustRenameRanges
llvm::Optional< std::vector< Range > > adjustRenameRanges(llvm::StringRef DraftCode, llvm::StringRef Identifier, std::vector< Range > Indexed, const LangOptions &LangOpts)
Adjusts indexed occurrences to match the current state of the file.
Definition: Rename.cpp:878
clang::clangd::ParsedAST::getSourceManager
SourceManager & getSourceManager()
Definition: ParsedAST.h:75
clang::clangd::findSymbol
const Symbol & findSymbol(const SymbolSlab &Slab, llvm::StringRef QName)
Definition: TestTU.cpp:181
clang::clangd::IndexType::Light
@ Light