clang-tools  14.0.0git
BackgroundIndexTests.cpp
Go to the documentation of this file.
1 #include "CompileCommands.h"
2 #include "Config.h"
3 #include "Headers.h"
4 #include "SyncAPI.h"
5 #include "TestFS.h"
6 #include "TestIndex.h"
7 #include "TestTU.h"
8 #include "index/Background.h"
10 #include "clang/Tooling/ArgumentsAdjusters.h"
11 #include "clang/Tooling/CompilationDatabase.h"
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/Support/ScopedPrinter.h"
14 #include "llvm/Support/Threading.h"
15 #include "gmock/gmock.h"
16 #include "gtest/gtest.h"
17 #include <deque>
18 #include <thread>
19 
20 using ::testing::_;
21 using ::testing::AllOf;
22 using ::testing::Contains;
23 using ::testing::ElementsAre;
24 using ::testing::Not;
25 using ::testing::Pair;
26 using ::testing::UnorderedElementsAre;
27 
28 namespace clang {
29 namespace clangd {
30 
31 MATCHER_P(Named, N, "") { return arg.Name == N; }
32 MATCHER_P(QName, N, "") { return (arg.Scope + arg.Name).str() == N; }
33 MATCHER(Declared, "") {
34  return !StringRef(arg.CanonicalDeclaration.FileURI).empty();
35 }
36 MATCHER(Defined, "") { return !StringRef(arg.Definition.FileURI).empty(); }
37 MATCHER_P(FileURI, F, "") { return StringRef(arg.Location.FileURI) == F; }
38 ::testing::Matcher<const RefSlab &>
39 RefsAre(std::vector<::testing::Matcher<Ref>> Matchers) {
40  return ElementsAre(::testing::Pair(_, UnorderedElementsAreArray(Matchers)));
41 }
42 // URI cannot be empty since it references keys in the IncludeGraph.
43 MATCHER(EmptyIncludeNode, "") {
44  return arg.Flags == IncludeGraphNode::SourceFlag::None && !arg.URI.empty() &&
45  arg.Digest == FileDigest{{0}} && arg.DirectIncludes.empty();
46 }
47 
48 MATCHER(HadErrors, "") {
49  return arg.Flags & IncludeGraphNode::SourceFlag::HadErrors;
50 }
51 
52 MATCHER_P(NumReferences, N, "") { return arg.References == N; }
53 
55  mutable std::mutex StorageMu;
56  llvm::StringMap<std::string> &Storage;
57  size_t &CacheHits;
58 
59 public:
60  MemoryShardStorage(llvm::StringMap<std::string> &Storage, size_t &CacheHits)
61  : Storage(Storage), CacheHits(CacheHits) {}
62  llvm::Error storeShard(llvm::StringRef ShardIdentifier,
63  IndexFileOut Shard) const override {
64  std::lock_guard<std::mutex> Lock(StorageMu);
65  AccessedPaths.insert(ShardIdentifier);
66  Storage[ShardIdentifier] = llvm::to_string(Shard);
67  return llvm::Error::success();
68  }
69  std::unique_ptr<IndexFileIn>
70  loadShard(llvm::StringRef ShardIdentifier) const override {
71  std::lock_guard<std::mutex> Lock(StorageMu);
72  AccessedPaths.insert(ShardIdentifier);
73  if (Storage.find(ShardIdentifier) == Storage.end()) {
74  return nullptr;
75  }
76  auto IndexFile =
77  readIndexFile(Storage[ShardIdentifier], SymbolOrigin::Background);
78  if (!IndexFile) {
79  ADD_FAILURE() << "Error while reading " << ShardIdentifier << ':'
80  << IndexFile.takeError();
81  return nullptr;
82  }
83  CacheHits++;
84  return std::make_unique<IndexFileIn>(std::move(*IndexFile));
85  }
86 
87  mutable llvm::StringSet<> AccessedPaths;
88 };
89 
90 class BackgroundIndexTest : public ::testing::Test {
91 protected:
93 };
94 
95 TEST_F(BackgroundIndexTest, NoCrashOnErrorFile) {
96  MockFS FS;
97  FS.Files[testPath("root/A.cc")] = "error file";
98  llvm::StringMap<std::string> Storage;
99  size_t CacheHits = 0;
100  MemoryShardStorage MSS(Storage, CacheHits);
101  OverlayCDB CDB(/*Base=*/nullptr);
102  BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
103  /*Opts=*/{});
104 
105  tooling::CompileCommand Cmd;
106  Cmd.Filename = testPath("root/A.cc");
107  Cmd.Directory = testPath("root");
108  Cmd.CommandLine = {"clang++", "-DA=1", testPath("root/A.cc")};
109  CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
110 
111  ASSERT_TRUE(Idx.blockUntilIdleForTest());
112 }
113 
115  MockFS FS;
116  // Set up two identical TUs, foo and bar.
117  // They define foo::one and bar::one.
118  std::vector<tooling::CompileCommand> Cmds;
119  for (std::string Name : {"foo", "bar", "baz"}) {
120  std::string Filename = Name + ".cpp";
121  std::string Header = Name + ".h";
122  FS.Files[Filename] = "#include \"" + Header + "\"";
123  FS.Files[Header] = "namespace " + Name + " { int one; }";
124  tooling::CompileCommand Cmd;
125  Cmd.Filename = Filename;
126  Cmd.Directory = testRoot();
127  Cmd.CommandLine = {"clang++", Filename};
128  Cmds.push_back(std::move(Cmd));
129  }
130  // Context provider that installs a configuration mutating foo's command.
131  // This causes it to define foo::two instead of foo::one.
132  // It also disables indexing of baz entirely.
134  Opts.ContextProvider = [](PathRef P) {
135  Config C;
136  if (P.endswith("foo.cpp"))
137  C.CompileFlags.Edits.push_back([](std::vector<std::string> &Argv) {
138  Argv = tooling::getInsertArgumentAdjuster("-Done=two")(Argv, "");
139  });
140  if (P.endswith("baz.cpp"))
141  C.Index.Background = Config::BackgroundPolicy::Skip;
142  return Context::current().derive(Config::Key, std::move(C));
143  };
144  // Create the background index.
145  llvm::StringMap<std::string> Storage;
146  size_t CacheHits = 0;
147  MemoryShardStorage MSS(Storage, CacheHits);
148  // We need the CommandMangler, because that applies the config we're testing.
149  OverlayCDB CDB(/*Base=*/nullptr, /*FallbackFlags=*/{},
150  tooling::ArgumentsAdjuster(CommandMangler::forTests()));
151 
152  BackgroundIndex Idx(
153  FS, CDB, [&](llvm::StringRef) { return &MSS; }, std::move(Opts));
154  // Index the two files.
155  for (auto &Cmd : Cmds) {
156  std::string FullPath = testPath(Cmd.Filename);
157  CDB.setCompileCommand(FullPath, std::move(Cmd));
158  }
159  // Wait for both files to be indexed.
160  ASSERT_TRUE(Idx.blockUntilIdleForTest());
161  EXPECT_THAT(runFuzzyFind(Idx, ""),
162  UnorderedElementsAre(QName("foo"), QName("foo::two"),
163  QName("bar"), QName("bar::one")));
164 }
165 
166 TEST_F(BackgroundIndexTest, IndexTwoFiles) {
167  MockFS FS;
168  // a.h yields different symbols when included by A.cc vs B.cc.
169  FS.Files[testPath("root/A.h")] = R"cpp(
170  void common();
171  void f_b();
172  #if A
173  class A_CC {};
174  #else
175  class B_CC{};
176  #endif
177  )cpp";
178  FS.Files[testPath("root/A.cc")] =
179  "#include \"A.h\"\nstatic void g() { (void)common; }";
180  FS.Files[testPath("root/B.cc")] =
181  R"cpp(
182  #define A 0
183  #include "A.h"
184  void f_b() {
185  (void)common;
186  (void)common;
187  (void)common;
188  (void)common;
189  })cpp";
190  llvm::StringMap<std::string> Storage;
191  size_t CacheHits = 0;
192  MemoryShardStorage MSS(Storage, CacheHits);
193  OverlayCDB CDB(/*Base=*/nullptr);
195  BackgroundIndex Idx(
196  FS, CDB, [&](llvm::StringRef) { return &MSS; }, Opts);
197 
198  tooling::CompileCommand Cmd;
199  Cmd.Filename = testPath("root/A.cc");
200  Cmd.Directory = testPath("root");
201  Cmd.CommandLine = {"clang++", "-DA=1", testPath("root/A.cc")};
202  CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
203 
204  ASSERT_TRUE(Idx.blockUntilIdleForTest());
205  EXPECT_THAT(runFuzzyFind(Idx, ""),
206  UnorderedElementsAre(AllOf(Named("common"), NumReferences(1U)),
207  AllOf(Named("A_CC"), NumReferences(0U)),
208  AllOf(Named("g"), NumReferences(1U)),
209  AllOf(Named("f_b"), Declared(),
210  Not(Defined()), NumReferences(0U))));
211 
212  Cmd.Filename = testPath("root/B.cc");
213  Cmd.CommandLine = {"clang++", Cmd.Filename};
214  CDB.setCompileCommand(testPath("root/B.cc"), Cmd);
215 
216  ASSERT_TRUE(Idx.blockUntilIdleForTest());
217  // B_CC is dropped as we don't collect symbols from A.h in this compilation.
218  EXPECT_THAT(runFuzzyFind(Idx, ""),
219  UnorderedElementsAre(AllOf(Named("common"), NumReferences(5U)),
220  AllOf(Named("A_CC"), NumReferences(0U)),
221  AllOf(Named("g"), NumReferences(1U)),
222  AllOf(Named("f_b"), Declared(), Defined(),
223  NumReferences(1U))));
224 
225  auto Syms = runFuzzyFind(Idx, "common");
226  EXPECT_THAT(Syms, UnorderedElementsAre(Named("common")));
227  auto Common = *Syms.begin();
228  EXPECT_THAT(getRefs(Idx, Common.ID),
229  RefsAre({FileURI("unittest:///root/A.h"),
230  FileURI("unittest:///root/A.cc"),
231  FileURI("unittest:///root/B.cc"),
232  FileURI("unittest:///root/B.cc"),
233  FileURI("unittest:///root/B.cc"),
234  FileURI("unittest:///root/B.cc")}));
235 }
236 
237 TEST_F(BackgroundIndexTest, MainFileRefs) {
238  MockFS FS;
239  FS.Files[testPath("root/A.h")] = R"cpp(
240  void header_sym();
241  )cpp";
242  FS.Files[testPath("root/A.cc")] =
243  "#include \"A.h\"\nstatic void main_sym() { (void)header_sym; }";
244 
245  llvm::StringMap<std::string> Storage;
246  size_t CacheHits = 0;
247  MemoryShardStorage MSS(Storage, CacheHits);
248  OverlayCDB CDB(/*Base=*/nullptr);
249  BackgroundIndex::Options Opts;
250  BackgroundIndex Idx(
251  FS, CDB, [&](llvm::StringRef) { return &MSS; }, Opts);
252 
253  tooling::CompileCommand Cmd;
254  Cmd.Filename = testPath("root/A.cc");
255  Cmd.Directory = testPath("root");
256  Cmd.CommandLine = {"clang++", testPath("root/A.cc")};
257  CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
258 
259  ASSERT_TRUE(Idx.blockUntilIdleForTest());
260  EXPECT_THAT(
261  runFuzzyFind(Idx, ""),
262  UnorderedElementsAre(AllOf(Named("header_sym"), NumReferences(1U)),
263  AllOf(Named("main_sym"), NumReferences(1U))));
264 }
265 
266 TEST_F(BackgroundIndexTest, ShardStorageTest) {
267  MockFS FS;
268  FS.Files[testPath("root/A.h")] = R"cpp(
269  void common();
270  void f_b();
271  class A_CC {};
272  )cpp";
273  std::string A_CC = "";
274  FS.Files[testPath("root/A.cc")] = R"cpp(
275  #include "A.h"
276  void g() { (void)common; }
277  class B_CC : public A_CC {};
278  )cpp";
279 
280  llvm::StringMap<std::string> Storage;
281  size_t CacheHits = 0;
282  MemoryShardStorage MSS(Storage, CacheHits);
283 
284  tooling::CompileCommand Cmd;
285  Cmd.Filename = testPath("root/A.cc");
286  Cmd.Directory = testPath("root");
287  Cmd.CommandLine = {"clang++", testPath("root/A.cc")};
288  // Check nothing is loaded from Storage, but A.cc and A.h has been stored.
289  {
290  OverlayCDB CDB(/*Base=*/nullptr);
291  BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
292  /*Opts=*/{});
293  CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
294  ASSERT_TRUE(Idx.blockUntilIdleForTest());
295  }
296  EXPECT_EQ(CacheHits, 0U);
297  EXPECT_EQ(Storage.size(), 2U);
298 
299  {
300  OverlayCDB CDB(/*Base=*/nullptr);
301  BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
302  /*Opts=*/{});
303  CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
304  ASSERT_TRUE(Idx.blockUntilIdleForTest());
305  }
306  EXPECT_EQ(CacheHits, 2U); // Check both A.cc and A.h loaded from cache.
307  EXPECT_EQ(Storage.size(), 2U);
308 
309  auto ShardHeader = MSS.loadShard(testPath("root/A.h"));
310  EXPECT_NE(ShardHeader, nullptr);
311  EXPECT_THAT(
312  *ShardHeader->Symbols,
313  UnorderedElementsAre(Named("common"), Named("A_CC"),
314  AllOf(Named("f_b"), Declared(), Not(Defined()))));
315  for (const auto &Ref : *ShardHeader->Refs)
316  EXPECT_THAT(Ref.second,
317  UnorderedElementsAre(FileURI("unittest:///root/A.h")));
318 
319  auto ShardSource = MSS.loadShard(testPath("root/A.cc"));
320  EXPECT_NE(ShardSource, nullptr);
321  EXPECT_THAT(*ShardSource->Symbols,
322  UnorderedElementsAre(Named("g"), Named("B_CC")));
323  for (const auto &Ref : *ShardSource->Refs)
324  EXPECT_THAT(Ref.second,
325  UnorderedElementsAre(FileURI("unittest:///root/A.cc")));
326 
327  // The BaseOf relationship between A_CC and B_CC is stored in both the file
328  // containing the definition of the subject (A_CC) and the file containing
329  // the definition of the object (B_CC).
330  SymbolID A = findSymbol(*ShardHeader->Symbols, "A_CC").ID;
331  SymbolID B = findSymbol(*ShardSource->Symbols, "B_CC").ID;
332  EXPECT_THAT(*ShardHeader->Relations,
333  UnorderedElementsAre(Relation{A, RelationKind::BaseOf, B}));
334  EXPECT_THAT(*ShardSource->Relations,
335  UnorderedElementsAre(Relation{A, RelationKind::BaseOf, B}));
336 }
337 
338 TEST_F(BackgroundIndexTest, DirectIncludesTest) {
339  MockFS FS;
340  FS.Files[testPath("root/B.h")] = "";
341  FS.Files[testPath("root/A.h")] = R"cpp(
342  #include "B.h"
343  void common();
344  void f_b();
345  class A_CC {};
346  )cpp";
347  std::string A_CC = "#include \"A.h\"\nvoid g() { (void)common; }";
348  FS.Files[testPath("root/A.cc")] = A_CC;
349 
350  llvm::StringMap<std::string> Storage;
351  size_t CacheHits = 0;
352  MemoryShardStorage MSS(Storage, CacheHits);
353 
354  tooling::CompileCommand Cmd;
355  Cmd.Filename = testPath("root/A.cc");
356  Cmd.Directory = testPath("root");
357  Cmd.CommandLine = {"clang++", testPath("root/A.cc")};
358  {
359  OverlayCDB CDB(/*Base=*/nullptr);
360  BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
361  /*Opts=*/{});
362  CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
363  ASSERT_TRUE(Idx.blockUntilIdleForTest());
364  }
365 
366  auto ShardSource = MSS.loadShard(testPath("root/A.cc"));
367  EXPECT_TRUE(ShardSource->Sources);
368  EXPECT_EQ(ShardSource->Sources->size(), 2U); // A.cc, A.h
369  EXPECT_THAT(
370  ShardSource->Sources->lookup("unittest:///root/A.cc").DirectIncludes,
371  UnorderedElementsAre("unittest:///root/A.h"));
372  EXPECT_NE(ShardSource->Sources->lookup("unittest:///root/A.cc").Digest,
373  FileDigest{{0}});
374  EXPECT_THAT(ShardSource->Sources->lookup("unittest:///root/A.h"),
375  EmptyIncludeNode());
376 
377  auto ShardHeader = MSS.loadShard(testPath("root/A.h"));
378  EXPECT_TRUE(ShardHeader->Sources);
379  EXPECT_EQ(ShardHeader->Sources->size(), 2U); // A.h, B.h
380  EXPECT_THAT(
381  ShardHeader->Sources->lookup("unittest:///root/A.h").DirectIncludes,
382  UnorderedElementsAre("unittest:///root/B.h"));
383  EXPECT_NE(ShardHeader->Sources->lookup("unittest:///root/A.h").Digest,
384  FileDigest{{0}});
385  EXPECT_THAT(ShardHeader->Sources->lookup("unittest:///root/B.h"),
386  EmptyIncludeNode());
387 }
388 
389 TEST_F(BackgroundIndexTest, ShardStorageLoad) {
390  MockFS FS;
391  FS.Files[testPath("root/A.h")] = R"cpp(
392  void common();
393  void f_b();
394  class A_CC {};
395  )cpp";
396  FS.Files[testPath("root/A.cc")] =
397  "#include \"A.h\"\nvoid g() { (void)common; }";
398 
399  llvm::StringMap<std::string> Storage;
400  size_t CacheHits = 0;
401  MemoryShardStorage MSS(Storage, CacheHits);
402 
403  tooling::CompileCommand Cmd;
404  Cmd.Filename = testPath("root/A.cc");
405  Cmd.Directory = testPath("root");
406  Cmd.CommandLine = {"clang++", testPath("root/A.cc")};
407  // Check nothing is loaded from Storage, but A.cc and A.h has been stored.
408  {
409  OverlayCDB CDB(/*Base=*/nullptr);
410  BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
411  /*Opts=*/{});
412  CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
413  ASSERT_TRUE(Idx.blockUntilIdleForTest());
414  }
415 
416  // Change header.
417  FS.Files[testPath("root/A.h")] = R"cpp(
418  void common();
419  void f_b();
420  class A_CC {};
421  class A_CCnew {};
422  )cpp";
423  {
424  OverlayCDB CDB(/*Base=*/nullptr);
425  BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
426  /*Opts=*/{});
427  CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
428  ASSERT_TRUE(Idx.blockUntilIdleForTest());
429  }
430  EXPECT_EQ(CacheHits, 2U); // Check both A.cc and A.h loaded from cache.
431 
432  // Check if the new symbol has arrived.
433  auto ShardHeader = MSS.loadShard(testPath("root/A.h"));
434  EXPECT_NE(ShardHeader, nullptr);
435  EXPECT_THAT(*ShardHeader->Symbols, Contains(Named("A_CCnew")));
436 
437  // Change source.
438  FS.Files[testPath("root/A.cc")] =
439  "#include \"A.h\"\nvoid g() { (void)common; }\nvoid f_b() {}";
440  {
441  CacheHits = 0;
442  OverlayCDB CDB(/*Base=*/nullptr);
443  BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
444  /*Opts=*/{});
445  CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
446  ASSERT_TRUE(Idx.blockUntilIdleForTest());
447  }
448  EXPECT_EQ(CacheHits, 2U); // Check both A.cc and A.h loaded from cache.
449 
450  // Check if the new symbol has arrived.
451  ShardHeader = MSS.loadShard(testPath("root/A.h"));
452  EXPECT_NE(ShardHeader, nullptr);
453  EXPECT_THAT(*ShardHeader->Symbols, Contains(Named("A_CCnew")));
454  auto ShardSource = MSS.loadShard(testPath("root/A.cc"));
455  EXPECT_NE(ShardSource, nullptr);
456  EXPECT_THAT(*ShardSource->Symbols,
457  Contains(AllOf(Named("f_b"), Declared(), Defined())));
458 }
459 
460 TEST_F(BackgroundIndexTest, ShardStorageEmptyFile) {
461  MockFS FS;
462  FS.Files[testPath("root/A.h")] = R"cpp(
463  void common();
464  void f_b();
465  class A_CC {};
466  )cpp";
467  FS.Files[testPath("root/B.h")] = R"cpp(
468  #include "A.h"
469  )cpp";
470  FS.Files[testPath("root/A.cc")] =
471  "#include \"B.h\"\nvoid g() { (void)common; }";
472 
473  llvm::StringMap<std::string> Storage;
474  size_t CacheHits = 0;
475  MemoryShardStorage MSS(Storage, CacheHits);
476 
477  tooling::CompileCommand Cmd;
478  Cmd.Filename = testPath("root/A.cc");
479  Cmd.Directory = testPath("root");
480  Cmd.CommandLine = {"clang++", testPath("root/A.cc")};
481  // Check that A.cc, A.h and B.h has been stored.
482  {
483  OverlayCDB CDB(/*Base=*/nullptr);
484  BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
485  /*Opts=*/{});
486  CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
487  ASSERT_TRUE(Idx.blockUntilIdleForTest());
488  }
489  EXPECT_THAT(Storage.keys(),
490  UnorderedElementsAre(testPath("root/A.cc"), testPath("root/A.h"),
491  testPath("root/B.h")));
492  auto ShardHeader = MSS.loadShard(testPath("root/B.h"));
493  EXPECT_NE(ShardHeader, nullptr);
494  EXPECT_TRUE(ShardHeader->Symbols->empty());
495 
496  // Check that A.cc, A.h and B.h has been loaded.
497  {
498  CacheHits = 0;
499  OverlayCDB CDB(/*Base=*/nullptr);
500  BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
501  /*Opts=*/{});
502  CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
503  ASSERT_TRUE(Idx.blockUntilIdleForTest());
504  }
505  EXPECT_EQ(CacheHits, 3U);
506 
507  // Update B.h to contain some symbols.
508  FS.Files[testPath("root/B.h")] = R"cpp(
509  #include "A.h"
510  void new_func();
511  )cpp";
512  // Check that B.h has been stored with new contents.
513  {
514  CacheHits = 0;
515  OverlayCDB CDB(/*Base=*/nullptr);
516  BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
517  /*Opts=*/{});
518  CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
519  ASSERT_TRUE(Idx.blockUntilIdleForTest());
520  }
521  EXPECT_EQ(CacheHits, 3U);
522  ShardHeader = MSS.loadShard(testPath("root/B.h"));
523  EXPECT_NE(ShardHeader, nullptr);
524  EXPECT_THAT(*ShardHeader->Symbols,
525  Contains(AllOf(Named("new_func"), Declared(), Not(Defined()))));
526 }
527 
528 TEST_F(BackgroundIndexTest, NoDotsInAbsPath) {
529  MockFS FS;
530  llvm::StringMap<std::string> Storage;
531  size_t CacheHits = 0;
532  MemoryShardStorage MSS(Storage, CacheHits);
533  OverlayCDB CDB(/*Base=*/nullptr);
534  BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
535  /*Opts=*/{});
536  ASSERT_TRUE(Idx.blockUntilIdleForTest());
537 
538  tooling::CompileCommand Cmd;
539  FS.Files[testPath("root/A.cc")] = "";
540  Cmd.Filename = "../A.cc";
541  Cmd.Directory = testPath("root/build");
542  Cmd.CommandLine = {"clang++", "../A.cc"};
543  CDB.setCompileCommand(testPath("root/build/../A.cc"), Cmd);
544  ASSERT_TRUE(Idx.blockUntilIdleForTest());
545 
546  FS.Files[testPath("root/B.cc")] = "";
547  Cmd.Filename = "./B.cc";
548  Cmd.Directory = testPath("root");
549  Cmd.CommandLine = {"clang++", "./B.cc"};
550  CDB.setCompileCommand(testPath("root/./B.cc"), Cmd);
551  ASSERT_TRUE(Idx.blockUntilIdleForTest());
552 
553  for (llvm::StringRef AbsPath : MSS.AccessedPaths.keys()) {
554  EXPECT_FALSE(AbsPath.contains("./")) << AbsPath;
555  EXPECT_FALSE(AbsPath.contains("../")) << AbsPath;
556  }
557 }
558 
559 TEST_F(BackgroundIndexTest, UncompilableFiles) {
560  MockFS FS;
561  llvm::StringMap<std::string> Storage;
562  size_t CacheHits = 0;
563  MemoryShardStorage MSS(Storage, CacheHits);
564  OverlayCDB CDB(/*Base=*/nullptr);
565  BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
566  /*Opts=*/{});
567 
568  tooling::CompileCommand Cmd;
569  FS.Files[testPath("A.h")] = "void foo();";
570  FS.Files[testPath("B.h")] = "#include \"C.h\"\nasdf;";
571  FS.Files[testPath("C.h")] = "";
572  FS.Files[testPath("A.cc")] = R"cpp(
573  #include "A.h"
574  #include "B.h"
575  #include "not_found_header.h"
576 
577  void foo() {}
578  )cpp";
579  Cmd.Filename = "../A.cc";
580  Cmd.Directory = testPath("build");
581  Cmd.CommandLine = {"clang++", "../A.cc"};
582  CDB.setCompileCommand(testPath("build/../A.cc"), Cmd);
583  ASSERT_TRUE(Idx.blockUntilIdleForTest());
584 
585  EXPECT_THAT(Storage.keys(), ElementsAre(testPath("A.cc"), testPath("A.h"),
586  testPath("B.h"), testPath("C.h")));
587 
588  {
589  auto Shard = MSS.loadShard(testPath("A.cc"));
590  EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(Named("foo")));
591  EXPECT_THAT(Shard->Sources->keys(),
592  UnorderedElementsAre("unittest:///A.cc", "unittest:///A.h",
593  "unittest:///B.h"));
594  EXPECT_THAT(Shard->Sources->lookup("unittest:///A.cc"), HadErrors());
595  }
596 
597  {
598  auto Shard = MSS.loadShard(testPath("A.h"));
599  EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(Named("foo")));
600  EXPECT_THAT(Shard->Sources->keys(),
601  UnorderedElementsAre("unittest:///A.h"));
602  EXPECT_THAT(Shard->Sources->lookup("unittest:///A.h"), HadErrors());
603  }
604 
605  {
606  auto Shard = MSS.loadShard(testPath("B.h"));
607  EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(Named("asdf")));
608  EXPECT_THAT(Shard->Sources->keys(),
609  UnorderedElementsAre("unittest:///B.h", "unittest:///C.h"));
610  EXPECT_THAT(Shard->Sources->lookup("unittest:///B.h"), HadErrors());
611  }
612 
613  {
614  auto Shard = MSS.loadShard(testPath("C.h"));
615  EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre());
616  EXPECT_THAT(Shard->Sources->keys(),
617  UnorderedElementsAre("unittest:///C.h"));
618  EXPECT_THAT(Shard->Sources->lookup("unittest:///C.h"), HadErrors());
619  }
620 }
621 
622 TEST_F(BackgroundIndexTest, CmdLineHash) {
623  MockFS FS;
624  llvm::StringMap<std::string> Storage;
625  size_t CacheHits = 0;
626  MemoryShardStorage MSS(Storage, CacheHits);
627  OverlayCDB CDB(/*Base=*/nullptr);
628  BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
629  /*Opts=*/{});
630 
631  tooling::CompileCommand Cmd;
632  FS.Files[testPath("A.cc")] = "#include \"A.h\"";
633  FS.Files[testPath("A.h")] = "";
634  Cmd.Filename = "../A.cc";
635  Cmd.Directory = testPath("build");
636  Cmd.CommandLine = {"clang++", "../A.cc", "-fsyntax-only"};
637  CDB.setCompileCommand(testPath("build/../A.cc"), Cmd);
638  ASSERT_TRUE(Idx.blockUntilIdleForTest());
639 
640  EXPECT_THAT(Storage.keys(), ElementsAre(testPath("A.cc"), testPath("A.h")));
641  // Make sure we only store the Cmd for main file.
642  EXPECT_FALSE(MSS.loadShard(testPath("A.h"))->Cmd);
643 
644  tooling::CompileCommand CmdStored = *MSS.loadShard(testPath("A.cc"))->Cmd;
645  EXPECT_EQ(CmdStored.CommandLine, Cmd.CommandLine);
646  EXPECT_EQ(CmdStored.Directory, Cmd.Directory);
647 }
648 
649 TEST_F(BackgroundIndexTest, Reindex) {
650  MockFS FS;
651  llvm::StringMap<std::string> Storage;
652  size_t CacheHits = 0;
653  MemoryShardStorage MSS(Storage, CacheHits);
654  OverlayCDB CDB(/*Base=*/nullptr);
655  BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
656  /*Opts=*/{});
657 
658  // Index a file.
659  FS.Files[testPath("A.cc")] = "int theOldFunction();";
660  tooling::CompileCommand Cmd;
661  Cmd.Filename = "../A.cc";
662  Cmd.Directory = testPath("build");
663  Cmd.CommandLine = {"clang++", "../A.cc", "-fsyntax-only"};
664  CDB.setCompileCommand(testPath("A.cc"), Cmd);
665  ASSERT_TRUE(Idx.blockUntilIdleForTest());
666 
667  // Verify the result is indexed and stored.
668  EXPECT_EQ(1u, runFuzzyFind(Idx, "theOldFunction").size());
669  EXPECT_EQ(0u, runFuzzyFind(Idx, "theNewFunction").size());
670  std::string OldShard = Storage.lookup(testPath("A.cc"));
671  EXPECT_NE("", OldShard);
672 
673  // Change the content and command, and notify to reindex it.
674  Cmd.CommandLine.push_back("-DFOO");
675  FS.Files[testPath("A.cc")] = "int theNewFunction();";
676  CDB.setCompileCommand(testPath("A.cc"), Cmd);
677  ASSERT_TRUE(Idx.blockUntilIdleForTest());
678 
679  // Currently, we will never index the same main file again.
680  EXPECT_EQ(1u, runFuzzyFind(Idx, "theOldFunction").size());
681  EXPECT_EQ(0u, runFuzzyFind(Idx, "theNewFunction").size());
682  EXPECT_EQ(OldShard, Storage.lookup(testPath("A.cc")));
683 }
684 
685 class BackgroundIndexRebuilderTest : public testing::Test {
686 protected:
688  : Source(IndexContents::All), Target(std::make_unique<MemIndex>()),
689  Rebuilder(&Target, &Source, /*Threads=*/10) {
690  // Prepare FileSymbols with TestSymbol in it, for checkRebuild.
691  TestSymbol.ID = SymbolID("foo");
692  }
693 
694  // Perform Action and determine whether it rebuilt the index or not.
695  bool checkRebuild(std::function<void()> Action) {
696  // Update name so we can tell if the index updates.
697  VersionStorage.push_back("Sym" + std::to_string(++VersionCounter));
698  TestSymbol.Name = VersionStorage.back();
700  SB.insert(TestSymbol);
701  Source.update("", std::make_unique<SymbolSlab>(std::move(SB).build()),
702  nullptr, nullptr, false);
703  // Now maybe update the index.
704  Action();
705  // Now query the index to get the name count.
706  std::string ReadName;
708  Req.IDs.insert(TestSymbol.ID);
709  Target.lookup(Req,
710  [&](const Symbol &S) { ReadName = std::string(S.Name); });
711  // The index was rebuild if the name is up to date.
712  return ReadName == VersionStorage.back();
713  }
714 
715  Symbol TestSymbol;
716  FileSymbols Source;
718  BackgroundIndexRebuilder Rebuilder;
719 
720  unsigned VersionCounter = 0;
721  std::deque<std::string> VersionStorage;
722 };
723 
724 TEST_F(BackgroundIndexRebuilderTest, IndexingTUs) {
725  for (unsigned I = 0; I < Rebuilder.TUsBeforeFirstBuild - 1; ++I)
726  EXPECT_FALSE(checkRebuild([&] { Rebuilder.indexedTU(); }));
727  EXPECT_TRUE(checkRebuild([&] { Rebuilder.indexedTU(); }));
728  for (unsigned I = 0; I < Rebuilder.TUsBeforeRebuild - 1; ++I)
729  EXPECT_FALSE(checkRebuild([&] { Rebuilder.indexedTU(); }));
730  EXPECT_TRUE(checkRebuild([&] { Rebuilder.indexedTU(); }));
731 }
732 
733 TEST_F(BackgroundIndexRebuilderTest, LoadingShards) {
734  Rebuilder.startLoading();
735  Rebuilder.loadedShard(10);
736  Rebuilder.loadedShard(20);
737  EXPECT_TRUE(checkRebuild([&] { Rebuilder.doneLoading(); }));
738 
739  // No rebuild for no shards.
740  Rebuilder.startLoading();
741  EXPECT_FALSE(checkRebuild([&] { Rebuilder.doneLoading(); }));
742 
743  // Loads can overlap.
744  Rebuilder.startLoading();
745  Rebuilder.loadedShard(1);
746  Rebuilder.startLoading();
747  Rebuilder.loadedShard(1);
748  EXPECT_FALSE(checkRebuild([&] { Rebuilder.doneLoading(); }));
749  Rebuilder.loadedShard(1);
750  EXPECT_TRUE(checkRebuild([&] { Rebuilder.doneLoading(); }));
751 
752  // No rebuilding for indexed files while loading.
753  Rebuilder.startLoading();
754  for (unsigned I = 0; I < 3 * Rebuilder.TUsBeforeRebuild; ++I)
755  EXPECT_FALSE(checkRebuild([&] { Rebuilder.indexedTU(); }));
756  // But they get indexed when we're done, even if no shards were loaded.
757  EXPECT_TRUE(checkRebuild([&] { Rebuilder.doneLoading(); }));
758 }
759 
760 TEST(BackgroundQueueTest, Priority) {
761  // Create high and low priority tasks.
762  // Once a bunch of high priority tasks have run, the queue is stopped.
763  // So the low priority tasks should never run.
764  BackgroundQueue Q;
765  std::atomic<unsigned> HiRan(0), LoRan(0);
766  BackgroundQueue::Task Lo([&] { ++LoRan; });
767  BackgroundQueue::Task Hi([&] {
768  if (++HiRan >= 10)
769  Q.stop();
770  });
771  Hi.QueuePri = 100;
772 
773  // Enqueuing the low-priority ones first shouldn't make them run first.
774  Q.append(std::vector<BackgroundQueue::Task>(30, Lo));
775  for (unsigned I = 0; I < 30; ++I)
776  Q.push(Hi);
777 
778  AsyncTaskRunner ThreadPool;
779  for (unsigned I = 0; I < 5; ++I)
780  ThreadPool.runAsync("worker", [&] { Q.work(); });
781  // We should test enqueue with active workers, but it's hard to avoid races.
782  // Just make sure we don't crash.
783  Q.push(Lo);
784  Q.append(std::vector<BackgroundQueue::Task>(2, Hi));
785 
786  // After finishing, check the tasks that ran.
787  ThreadPool.wait();
788  EXPECT_GE(HiRan, 10u);
789  EXPECT_EQ(LoRan, 0u);
790 }
791 
792 TEST(BackgroundQueueTest, Boost) {
793  std::string Sequence;
794 
795  BackgroundQueue::Task A([&] { Sequence.push_back('A'); });
796  A.Tag = "A";
797  A.QueuePri = 1;
798 
799  BackgroundQueue::Task B([&] { Sequence.push_back('B'); });
800  B.QueuePri = 2;
801  B.Tag = "B";
802 
803  {
804  BackgroundQueue Q;
805  Q.append({A, B});
806  Q.work([&] { Q.stop(); });
807  EXPECT_EQ("BA", Sequence) << "priority order";
808  }
809  Sequence.clear();
810  {
811  BackgroundQueue Q;
812  Q.boost("A", 3);
813  Q.append({A, B});
814  Q.work([&] { Q.stop(); });
815  EXPECT_EQ("AB", Sequence) << "A was boosted before enqueueing";
816  }
817  Sequence.clear();
818  {
820  Q.append({A, B});
821  Q.boost("A", 3);
822  Q.work([&] { Q.stop(); });
823  EXPECT_EQ("AB", Sequence) << "A was boosted after enqueueing";
824  }
825 }
826 
827 TEST(BackgroundQueueTest, Duplicates) {
828  std::string Sequence;
829  BackgroundQueue::Task A([&] { Sequence.push_back('A'); });
830  A.QueuePri = 100;
831  A.Key = 1;
832  BackgroundQueue::Task B([&] { Sequence.push_back('B'); });
833  // B has no key, and is not subject to duplicate detection.
834  B.QueuePri = 50;
835 
836  BackgroundQueue Q;
837  Q.append({A, B, A, B}); // One A is dropped, the other is high priority.
838  Q.work(/*OnIdle=*/[&] {
839  // The first time we go idle, we enqueue the same task again.
840  if (!llvm::is_contained(Sequence, ' ')) {
841  Sequence.push_back(' ');
842  Q.append({A, B, A, B}); // Both As are dropped.
843  } else {
844  Q.stop();
845  }
846  });
847 
848  // This could reasonably be "ABB BBA", if we had good *re*indexing support.
849  EXPECT_EQ("ABB BB", Sequence);
850 }
851 
852 TEST(BackgroundQueueTest, Progress) {
853  using testing::AnyOf;
854  BackgroundQueue::Stats S;
855  BackgroundQueue Q([&](BackgroundQueue::Stats New) {
856  // Verify values are sane.
857  // Items are enqueued one at a time (at least in this test).
858  EXPECT_THAT(New.Enqueued, AnyOf(S.Enqueued, S.Enqueued + 1));
859  // Items are completed one at a time.
860  EXPECT_THAT(New.Completed, AnyOf(S.Completed, S.Completed + 1));
861  // Items are started or completed one at a time.
862  EXPECT_THAT(New.Active, AnyOf(S.Active - 1, S.Active, S.Active + 1));
863  // Idle point only advances in time.
864  EXPECT_GE(New.LastIdle, S.LastIdle);
865  // Idle point is a task that has been completed in the past.
866  EXPECT_LE(New.LastIdle, New.Completed);
867  // LastIdle is now only if we're really idle.
868  EXPECT_EQ(New.LastIdle == New.Enqueued,
869  New.Completed == New.Enqueued && New.Active == 0u);
870  S = New;
871  });
872 
873  // Two types of tasks: a ping task enqueues a pong task.
874  // This avoids all enqueues followed by all completions (boring!)
875  std::atomic<int> PingCount(0), PongCount(0);
876  BackgroundQueue::Task Pong([&] { ++PongCount; });
877  BackgroundQueue::Task Ping([&] {
878  ++PingCount;
879  Q.push(Pong);
880  });
881 
882  for (int I = 0; I < 1000; ++I)
883  Q.push(Ping);
884  // Spin up some workers and stop while idle.
885  AsyncTaskRunner ThreadPool;
886  for (unsigned I = 0; I < 5; ++I)
887  ThreadPool.runAsync("worker", [&] { Q.work([&] { Q.stop(); }); });
888  ThreadPool.wait();
889 
890  // Everything's done, check final stats.
891  // Assertions above ensure we got from 0 to 2000 in a reasonable way.
892  EXPECT_EQ(PingCount.load(), 1000);
893  EXPECT_EQ(PongCount.load(), 1000);
894  EXPECT_EQ(S.Active, 0u);
895  EXPECT_EQ(S.Enqueued, 2000u);
896  EXPECT_EQ(S.Completed, 2000u);
897  EXPECT_EQ(S.LastIdle, 2000u);
898 }
899 
900 TEST(BackgroundIndex, Profile) {
901  MockFS FS;
902  MockCompilationDatabase CDB;
903  BackgroundIndex Idx(FS, CDB, [](llvm::StringRef) { return nullptr; },
904  /*Opts=*/{});
905 
906  llvm::BumpPtrAllocator Alloc;
907  MemoryTree MT(&Alloc);
908  Idx.profile(MT);
909  ASSERT_THAT(MT.children(),
910  UnorderedElementsAre(Pair("slabs", _), Pair("index", _)));
911 }
912 
913 } // namespace clangd
914 } // namespace clang
clang::clangd::BackgroundQueue
Definition: Background.h:69
Headers.h
Background.h
clang::clangd::runFuzzyFind
SymbolSlab runFuzzyFind(const SymbolIndex &Index, llvm::StringRef Query)
Definition: SyncAPI.cpp:126
clang::clangd::RelationKind::BaseOf
@ BaseOf
clang::clangd::SymbolOrigin::Background
@ Background
clang::clangd::Config::BackgroundPolicy::Skip
@ Skip
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::Context::current
static const Context & current()
Returns the context for the current thread, creating it if needed.
Definition: Context.cpp:27
clang::clangd::BackgroundQueue::append
void append(std::vector< Task >)
Definition: BackgroundQueue.cpp:101
clang::clangd::SwapIndex
Definition: Index.h:161
TestTU.h
clang::clangd::MemoryShardStorage::AccessedPaths
llvm::StringSet AccessedPaths
Definition: BackgroundIndexTests.cpp:87
Filename
std::string Filename
Filename as a string.
Definition: IncludeOrderCheck.cpp:39
clang::clangd::BackgroundQueue::work
void work(std::function< void()> OnIdle=nullptr)
Definition: BackgroundQueue.cpp:21
clang::clangd::Config
Settings that express user/project preferences and control clangd behavior.
Definition: Config.h:43
clang::clangd::Relation
Represents a relation between two symbols.
Definition: Relation.h:34
clang::clangd::MemoryShardStorage::loadShard
std::unique_ptr< IndexFileIn > loadShard(llvm::StringRef ShardIdentifier) const override
Definition: BackgroundIndexTests.cpp:70
clang::clangd::TEST_F
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
Definition: BackgroundIndexTests.cpp:95
BackgroundRebuild.h
clang::clangd::FileSymbols
A container of slabs associated with a key.
Definition: FileIndex.h:72
Action
llvm::unique_function< void()> Action
Definition: TUScheduler.cpp:604
clang::clangd::IndexFileOut
Definition: Serialization.h:55
clang::clangd::IncludeGraphNode::SourceFlag::None
@ None
clang::clangd::RefsAre
::testing::Matcher< const RefSlab & > RefsAre(std::vector<::testing::Matcher< Ref >> Matchers)
Definition: BackgroundIndexTests.cpp:39
Target
std::string Target
Definition: QueryDriverDatabase.cpp:64
clang::clangd::readIndexFile
llvm::Expected< IndexFileIn > readIndexFile(llvm::StringRef Data, SymbolOrigin Origin)
Definition: Serialization.cpp:688
clang::clangd::BackgroundQueue::stop
void stop()
Definition: BackgroundQueue.cpp:67
clang::clangd::getRefs
RefSlab getRefs(const SymbolIndex &Index, SymbolID ID)
Definition: SyncAPI.cpp:139
ns1::ns2::A
@ A
Definition: CategoricalFeature.h:3
clang::clangd::BackgroundIndexRebuilderTest
Definition: BackgroundIndexTests.cpp:677
clang::clangd::testRoot
const char * testRoot()
Definition: TestFS.cpp:74
clang::clangd::MemoryShardStorage
Definition: BackgroundIndexTests.cpp:54
clang::clangd::BackgroundQueue::boost
void boost(llvm::StringRef Tag, unsigned NewPriority)
Definition: BackgroundQueue.cpp:116
clang::clangd::MockFS
Definition: TestFS.h:34
CompileCommands.h
TestFS.h
clang::clangd::Symbol
The class presents a C++ symbol, e.g.
Definition: Symbol.h:36
clang::clangd::IndexContents
IndexContents
Describes what data is covered by an index.
Definition: Index.h:91
clang::clangd::BackgroundQueue::preventThreadStarvationInTests
static void preventThreadStarvationInTests()
Definition: BackgroundQueue.cpp:17
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:28
SyncAPI.h
clang::clangd::Symbol::Name
llvm::StringRef Name
The unqualified name of the symbol, e.g. "bar" (for ns::bar).
Definition: Symbol.h:42
clang::doc::SymbolID
std::array< uint8_t, 20 > SymbolID
Definition: Representation.h:30
clang::clangd::MemIndex
MemIndex is a naive in-memory index suitable for a small set of symbols.
Definition: MemIndex.h:20
clang::clangd::TEST_F
TEST_F(BackgroundIndexRebuilderTest, LoadingShards)
Definition: BackgroundIndexTests.cpp:725
clang::clangd::BackgroundIndexTest::BackgroundIndexTest
BackgroundIndexTest()
Definition: BackgroundIndexTests.cpp:92
clang::clangd::LookupRequest::IDs
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:66
clang::clangd::BackgroundIndex::Options
Definition: Background.h:136
clang::clangd::MemoryShardStorage::MemoryShardStorage
MemoryShardStorage(llvm::StringMap< std::string > &Storage, size_t &CacheHits)
Definition: BackgroundIndexTests.cpp:60
Config.h
clang::clangd::LookupRequest
Definition: Index.h:65
clang::clangd::BackgroundIndexRebuilder
Definition: BackgroundRebuild.h:48
clang::clangd::Context::derive
Context derive(const Key< Type > &Key, typename std::decay< Type >::type Value) const &
Derives a child context It is safe to move or destroy a parent context after calling derive().
Definition: Context.h:119
clang::clangd::IncludeGraphNode::SourceFlag::HadErrors
@ HadErrors
TestIndex.h
clang::clangd::PathRef
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:29
clang::clangd::MATCHER_P
MATCHER_P(Named, N, "")
Definition: BackgroundIndexTests.cpp:31
clang::clangd::FileDigest
std::array< uint8_t, 8 > FileDigest
Definition: SourceCode.h:41
C
const Criteria C
Definition: FunctionCognitiveComplexityCheck.cpp:93
clang::clangd::BackgroundIndexStorage
Definition: Background.h:41
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::Config::Key
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
Definition: Config.h:47
clang::clangd::SymbolSlab::Builder
SymbolSlab::Builder is a mutable container that can 'freeze' to SymbolSlab.
Definition: Symbol.h:200
clang::clangd::CommandMangler::forTests
static CommandMangler forTests()
Definition: CompileCommands.cpp:196
clang::clangd::BackgroundIndex
Definition: Background.h:134
clang::clangd::TEST
TEST(BackgroundIndex, Profile)
Definition: BackgroundIndexTests.cpp:892
ns1::ns2::B
@ B
Definition: CategoricalFeature.h:3
clang::clangd::SymbolID
Definition: SymbolID.h:32
clang::clangd::findSymbol
const Symbol & findSymbol(const SymbolSlab &Slab, llvm::StringRef QName)
Definition: TestTU.cpp:181
clang::clangd::SymbolSlab::Builder::insert
void insert(const Symbol &S)
Adds a symbol, overwriting any existing one with the same ID.
Definition: Symbol.cpp:50
clang::clangd::MATCHER
MATCHER(Declared, "")
Definition: BackgroundIndexTests.cpp:33
clang::clangd::MemoryShardStorage::storeShard
llvm::Error storeShard(llvm::StringRef ShardIdentifier, IndexFileOut Shard) const override
Definition: BackgroundIndexTests.cpp:62
clang::clangd::BackgroundIndexTest
Definition: BackgroundIndexTests.cpp:90
clang::clangd::OverlayCDB
Wraps another compilation database, and supports overriding the commands using an in-memory mapping.
Definition: GlobalCompilationDatabase.h:174