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