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 "gmock/gmock.h"
15#include "gtest/gtest.h"
20using ::testing::AllOf;
21using ::testing::Contains;
22using ::testing::ElementsAre;
25using ::testing::UnorderedElementsAre;
31MATCHER_P(qName, N,
"") {
return (arg.Scope + arg.Name).str() == N; }
33 return !StringRef(arg.CanonicalDeclaration.FileURI).empty();
35MATCHER(defined,
"") {
return !StringRef(arg.Definition.FileURI).empty(); }
36MATCHER_P(fileURI, F,
"") {
return StringRef(arg.Location.FileURI) == F; }
37::testing::Matcher<const RefSlab &>
38refsAre(std::vector<::testing::Matcher<Ref>> Matchers) {
39 return ElementsAre(::testing::Pair(_, UnorderedElementsAreArray(Matchers)));
44 arg.Digest ==
FileDigest{{0}} && arg.DirectIncludes.empty();
51MATCHER_P(numReferences, N,
"") {
return arg.References == N; }
54 mutable std::mutex StorageMu;
55 llvm::StringMap<std::string> &Storage;
60 : Storage(Storage), CacheHits(CacheHits) {}
63 std::lock_guard<std::mutex> Lock(StorageMu);
65 Storage[ShardIdentifier] = llvm::to_string(Shard);
66 return llvm::Error::success();
68 std::unique_ptr<IndexFileIn>
69 loadShard(llvm::StringRef ShardIdentifier)
const override {
70 std::lock_guard<std::mutex> Lock(StorageMu);
72 if (!Storage.contains(ShardIdentifier)) {
78 ADD_FAILURE() <<
"Error while reading " << ShardIdentifier <<
':'
79 << IndexFile.takeError();
83 return std::make_unique<IndexFileIn>(std::move(*IndexFile));
96 FS.Files[
testPath(
"root/A.cc")] =
"error file";
97 llvm::StringMap<std::string> Storage;
104 tooling::CompileCommand Cmd;
105 Cmd.Filename =
testPath(
"root/A.cc");
107 Cmd.CommandLine = {
"clang++",
"-DA=1",
testPath(
"root/A.cc")};
108 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
110 ASSERT_TRUE(Idx.blockUntilIdleForTest());
117 std::vector<tooling::CompileCommand> Cmds;
118 for (std::string
Name : {
"foo",
"bar",
"baz"}) {
120 std::string Header =
Name +
".h";
121 FS.Files[
Filename] =
"#include \"" + Header +
"\"";
122 FS.Files[Header] =
"namespace " +
Name +
" { int one; }";
123 tooling::CompileCommand Cmd;
126 Cmd.CommandLine = {
"clang++",
Filename};
127 Cmds.push_back(std::move(Cmd));
133 Opts.ContextProvider = [](
PathRef P) {
135 if (P.ends_with(
"foo.cpp"))
136 C.CompileFlags.Edits.push_back([](std::vector<std::string> &Argv) {
137 Argv = tooling::getInsertArgumentAdjuster(
"-Done=two")(Argv,
"");
139 if (P.ends_with(
"baz.cpp"))
144 llvm::StringMap<std::string> Storage;
145 size_t CacheHits = 0;
152 FS, CDB, [&](llvm::StringRef) {
return &MSS; }, std::move(Opts));
154 for (
auto &Cmd : Cmds) {
155 std::string FullPath =
testPath(Cmd.Filename);
156 CDB.setCompileCommand(FullPath, std::move(Cmd));
159 ASSERT_TRUE(Idx.blockUntilIdleForTest());
161 UnorderedElementsAre(qName(
"foo"), qName(
"foo::two"),
162 qName(
"bar"), qName(
"bar::one")));
168 FS.Files[
testPath(
"root/A.h")] = R
"cpp(
178 "#include \"A.h\"\nstatic void g() { (void)common; }";
189 llvm::StringMap<std::string> Storage;
190 size_t CacheHits = 0;
195 FS, CDB, [&](llvm::StringRef) {
return &MSS; }, Opts);
197 tooling::CompileCommand Cmd;
198 Cmd.Filename =
testPath(
"root/A.cc");
200 Cmd.CommandLine = {
"clang++",
"-DA=1",
testPath(
"root/A.cc")};
201 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
203 ASSERT_TRUE(Idx.blockUntilIdleForTest());
205 UnorderedElementsAre(AllOf(named(
"common"), numReferences(1U)),
206 AllOf(named(
"A_CC"), numReferences(0U)),
207 AllOf(named(
"g"), numReferences(1U)),
208 AllOf(named(
"f_b"), declared(),
209 Not(defined()), numReferences(0U))));
211 Cmd.Filename =
testPath(
"root/B.cc");
212 Cmd.CommandLine = {
"clang++", Cmd.Filename};
213 CDB.setCompileCommand(
testPath(
"root/B.cc"), Cmd);
215 ASSERT_TRUE(Idx.blockUntilIdleForTest());
218 UnorderedElementsAre(AllOf(named(
"common"), numReferences(5U)),
219 AllOf(named(
"A_CC"), numReferences(0U)),
220 AllOf(named(
"g"), numReferences(1U)),
221 AllOf(named(
"f_b"), declared(), defined(),
222 numReferences(1U))));
225 EXPECT_THAT(Syms, UnorderedElementsAre(named(
"common")));
226 auto Common = *Syms.begin();
227 EXPECT_THAT(
getRefs(Idx, Common.ID),
228 refsAre({fileURI(
"unittest:///root/A.h"),
229 fileURI(
"unittest:///root/A.cc"),
230 fileURI(
"unittest:///root/B.cc"),
231 fileURI(
"unittest:///root/B.cc"),
232 fileURI(
"unittest:///root/B.cc"),
233 fileURI(
"unittest:///root/B.cc")}));
236TEST_F(BackgroundIndexTest, MainFileRefs) {
238 FS.Files[
testPath(
"root/A.h")] = R
"cpp(
242 "#include \"A.h\"\nstatic void main_sym() { (void)header_sym; }";
244 llvm::StringMap<std::string> Storage;
245 size_t CacheHits = 0;
246 MemoryShardStorage MSS(Storage, CacheHits);
247 OverlayCDB CDB(
nullptr);
248 BackgroundIndex::Options Opts;
250 FS, CDB, [&](llvm::StringRef) {
return &MSS; }, Opts);
252 tooling::CompileCommand Cmd;
253 Cmd.Filename =
testPath(
"root/A.cc");
255 Cmd.CommandLine = {
"clang++",
testPath(
"root/A.cc")};
256 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
258 ASSERT_TRUE(Idx.blockUntilIdleForTest());
261 UnorderedElementsAre(AllOf(named(
"header_sym"), numReferences(1U)),
262 AllOf(named(
"main_sym"), numReferences(1U))));
265TEST_F(BackgroundIndexTest, ShardStorageTest) {
267 FS.Files[
testPath(
"root/A.h")] = R
"cpp(
272 FS.Files[testPath("root/A.cc")] = R
"cpp(
274 void g() { (void)common; }
275 class B_CC : public A_CC {};
278 llvm::StringMap<std::string> Storage;
279 size_t CacheHits = 0;
280 MemoryShardStorage MSS(Storage, CacheHits);
282 tooling::CompileCommand Cmd;
283 Cmd.Filename =
testPath(
"root/A.cc");
285 Cmd.CommandLine = {
"clang++",
testPath(
"root/A.cc")};
288 OverlayCDB CDB(
nullptr);
289 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
291 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
292 ASSERT_TRUE(Idx.blockUntilIdleForTest());
294 EXPECT_EQ(CacheHits, 0U);
295 EXPECT_EQ(Storage.size(), 2U);
298 OverlayCDB CDB(
nullptr);
299 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
301 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
302 ASSERT_TRUE(Idx.blockUntilIdleForTest());
304 EXPECT_EQ(CacheHits, 2U);
305 EXPECT_EQ(Storage.size(), 2U);
308 EXPECT_NE(ShardHeader,
nullptr);
310 *ShardHeader->Symbols,
311 UnorderedElementsAre(named(
"common"), named(
"A_CC"),
312 AllOf(named(
"f_b"), declared(), Not(defined()))));
313 for (
const auto &Ref : *ShardHeader->Refs)
314 EXPECT_THAT(Ref.second,
315 UnorderedElementsAre(fileURI(
"unittest:///root/A.h")));
318 EXPECT_NE(ShardSource,
nullptr);
319 EXPECT_THAT(*ShardSource->Symbols,
320 UnorderedElementsAre(named(
"g"), named(
"B_CC")));
321 for (
const auto &Ref : *ShardSource->Refs)
322 EXPECT_THAT(Ref.second,
323 UnorderedElementsAre(fileURI(
"unittest:///root/A.cc")));
330 EXPECT_THAT(*ShardHeader->Relations,
332 EXPECT_THAT(*ShardSource->Relations,
336TEST_F(BackgroundIndexTest, DirectIncludesTest) {
338 FS.Files[
testPath(
"root/B.h")] =
"";
339 FS.Files[
testPath(
"root/A.h")] = R
"cpp(
346 "#include \"A.h\"\nvoid g() { (void)common; }";
348 llvm::StringMap<std::string> Storage;
349 size_t CacheHits = 0;
350 MemoryShardStorage MSS(Storage, CacheHits);
352 tooling::CompileCommand Cmd;
353 Cmd.Filename =
testPath(
"root/A.cc");
355 Cmd.CommandLine = {
"clang++",
testPath(
"root/A.cc")};
357 OverlayCDB CDB(
nullptr);
358 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
360 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
361 ASSERT_TRUE(Idx.blockUntilIdleForTest());
365 EXPECT_TRUE(ShardSource->Sources);
366 EXPECT_EQ(ShardSource->Sources->size(), 2U);
368 ShardSource->Sources->lookup(
"unittest:///root/A.cc").DirectIncludes,
369 UnorderedElementsAre(
"unittest:///root/A.h"));
370 EXPECT_NE(ShardSource->Sources->lookup(
"unittest:///root/A.cc").Digest,
372 EXPECT_THAT(ShardSource->Sources->lookup(
"unittest:///root/A.h"),
376 EXPECT_TRUE(ShardHeader->Sources);
377 EXPECT_EQ(ShardHeader->Sources->size(), 2U);
379 ShardHeader->Sources->lookup(
"unittest:///root/A.h").DirectIncludes,
380 UnorderedElementsAre(
"unittest:///root/B.h"));
381 EXPECT_NE(ShardHeader->Sources->lookup(
"unittest:///root/A.h").Digest,
383 EXPECT_THAT(ShardHeader->Sources->lookup(
"unittest:///root/B.h"),
387TEST_F(BackgroundIndexTest, ShardStorageLoad) {
389 FS.Files[testPath(
"root/A.h")] = R
"cpp(
394 FS.Files[testPath("root/A.cc")] =
395 "#include \"A.h\"\nvoid g() { (void)common; }";
397 llvm::StringMap<std::string> Storage;
398 size_t CacheHits = 0;
399 MemoryShardStorage MSS(Storage, CacheHits);
401 tooling::CompileCommand Cmd;
402 Cmd.Filename = testPath(
"root/A.cc");
403 Cmd.Directory = testPath(
"root");
404 Cmd.CommandLine = {
"clang++", testPath(
"root/A.cc")};
407 OverlayCDB CDB(
nullptr);
408 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
410 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
411 ASSERT_TRUE(Idx.blockUntilIdleForTest());
415 FS.Files[
testPath(
"root/A.h")] = R
"cpp(
422 OverlayCDB CDB(nullptr);
423 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
425 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
426 ASSERT_TRUE(Idx.blockUntilIdleForTest());
428 EXPECT_EQ(CacheHits, 2U);
432 EXPECT_NE(ShardHeader,
nullptr);
433 EXPECT_THAT(*ShardHeader->Symbols, Contains(named(
"A_CCnew")));
437 "#include \"A.h\"\nvoid g() { (void)common; }\nvoid f_b() {}";
440 OverlayCDB CDB(
nullptr);
441 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
443 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
444 ASSERT_TRUE(Idx.blockUntilIdleForTest());
446 EXPECT_EQ(CacheHits, 2U);
449 ShardHeader = MSS.
loadShard(testPath(
"root/A.h"));
450 EXPECT_NE(ShardHeader,
nullptr);
451 EXPECT_THAT(*ShardHeader->Symbols, Contains(named(
"A_CCnew")));
452 auto ShardSource = MSS.
loadShard(testPath(
"root/A.cc"));
453 EXPECT_NE(ShardSource,
nullptr);
454 EXPECT_THAT(*ShardSource->Symbols,
455 Contains(AllOf(named(
"f_b"), declared(), defined())));
458TEST_F(BackgroundIndexTest, ShardStorageEmptyFile) {
460 FS.Files[testPath(
"root/A.h")] = R
"cpp(
465 FS.Files[testPath("root/B.h")] = R
"cpp(
468 FS.Files[testPath("root/A.cc")] =
469 "#include \"B.h\"\nvoid g() { (void)common; }";
471 llvm::StringMap<std::string> Storage;
472 size_t CacheHits = 0;
473 MemoryShardStorage MSS(Storage, CacheHits);
475 tooling::CompileCommand Cmd;
476 Cmd.Filename = testPath(
"root/A.cc");
477 Cmd.Directory = testPath(
"root");
478 Cmd.CommandLine = {
"clang++", testPath(
"root/A.cc")};
481 OverlayCDB CDB(
nullptr);
482 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
484 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
485 ASSERT_TRUE(Idx.blockUntilIdleForTest());
487 EXPECT_THAT(Storage.keys(),
491 EXPECT_NE(ShardHeader,
nullptr);
492 EXPECT_TRUE(ShardHeader->Symbols->empty());
497 OverlayCDB CDB(
nullptr);
498 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
500 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
501 ASSERT_TRUE(Idx.blockUntilIdleForTest());
503 EXPECT_EQ(CacheHits, 3U);
506 FS.Files[
testPath(
"root/B.h")] = R
"cpp(
516 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
517 ASSERT_TRUE(Idx.blockUntilIdleForTest());
519 EXPECT_EQ(CacheHits, 3U);
520 ShardHeader = MSS.
loadShard(testPath(
"root/B.h"));
521 EXPECT_NE(ShardHeader,
nullptr);
522 EXPECT_THAT(*ShardHeader->Symbols,
523 Contains(AllOf(named(
"new_func"), declared(), Not(defined()))));
526TEST_F(BackgroundIndexTest, NoDotsInAbsPath) {
528 llvm::StringMap<std::string> Storage;
529 size_t CacheHits = 0;
530 MemoryShardStorage MSS(Storage, CacheHits);
531 OverlayCDB CDB(
nullptr);
532 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
534 ASSERT_TRUE(Idx.blockUntilIdleForTest());
536 tooling::CompileCommand Cmd;
537 FS.Files[
testPath(
"root/A.cc")] =
"";
538 Cmd.Filename =
"../A.cc";
539 Cmd.Directory =
testPath(
"root/build");
540 Cmd.CommandLine = {
"clang++",
"../A.cc"};
541 CDB.setCompileCommand(
testPath(
"root/build/../A.cc"), Cmd);
542 ASSERT_TRUE(Idx.blockUntilIdleForTest());
544 FS.Files[
testPath(
"root/B.cc")] =
"";
545 Cmd.Filename =
"./B.cc";
547 Cmd.CommandLine = {
"clang++",
"./B.cc"};
548 CDB.setCompileCommand(testPath(
"root/./B.cc"), Cmd);
549 ASSERT_TRUE(Idx.blockUntilIdleForTest());
552 EXPECT_FALSE(AbsPath.contains(
"./")) << AbsPath;
553 EXPECT_FALSE(AbsPath.contains(
"../")) << AbsPath;
557TEST_F(BackgroundIndexTest, UncompilableFiles) {
559 llvm::StringMap<std::string> Storage;
560 size_t CacheHits = 0;
561 MemoryShardStorage MSS(Storage, CacheHits);
562 OverlayCDB CDB(
nullptr);
563 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
566 tooling::CompileCommand Cmd;
567 FS.Files[
testPath(
"A.h")] =
"void foo();";
568 FS.Files[
testPath(
"B.h")] =
"#include \"C.h\"\nasdf;";
573 #include "not_found_header.h"
577 Cmd.Filename = "../A.cc";
579 Cmd.CommandLine = {
"clang++",
"../A.cc"};
580 CDB.setCompileCommand(
testPath(
"build/../A.cc"), Cmd);
581 ASSERT_TRUE(Idx.blockUntilIdleForTest());
583 EXPECT_THAT(Storage.keys(),
589 EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(named(
"foo")));
590 EXPECT_THAT(Shard->Sources->keys(),
591 UnorderedElementsAre(
"unittest:///A.cc",
"unittest:///A.h",
593 EXPECT_THAT(Shard->Sources->lookup(
"unittest:///A.cc"), hadErrors());
598 EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(named(
"foo")));
599 EXPECT_THAT(Shard->Sources->keys(),
600 UnorderedElementsAre(
"unittest:///A.h"));
601 EXPECT_THAT(Shard->Sources->lookup(
"unittest:///A.h"), hadErrors());
606 EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(named(
"asdf")));
607 EXPECT_THAT(Shard->Sources->keys(),
608 UnorderedElementsAre(
"unittest:///B.h",
"unittest:///C.h"));
609 EXPECT_THAT(Shard->Sources->lookup(
"unittest:///B.h"), hadErrors());
613 auto Shard = MSS.
loadShard(testPath(
"C.h"));
614 EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre());
615 EXPECT_THAT(Shard->Sources->keys(),
616 UnorderedElementsAre(
"unittest:///C.h"));
617 EXPECT_THAT(Shard->Sources->lookup(
"unittest:///C.h"), hadErrors());
621TEST_F(BackgroundIndexTest, CmdLineHash) {
623 llvm::StringMap<std::string> Storage;
624 size_t CacheHits = 0;
625 MemoryShardStorage MSS(Storage, CacheHits);
626 OverlayCDB CDB(
nullptr);
627 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
630 tooling::CompileCommand Cmd;
633 Cmd.Filename =
"../A.cc";
635 Cmd.CommandLine = {
"clang++",
"../A.cc",
"-fsyntax-only"};
636 CDB.setCompileCommand(testPath(
"build/../A.cc"), Cmd);
637 ASSERT_TRUE(Idx.blockUntilIdleForTest());
639 EXPECT_THAT(Storage.keys(),
640 UnorderedElementsAre(testPath(
"A.cc"), testPath(
"A.h")));
642 EXPECT_FALSE(MSS.
loadShard(testPath(
"A.h"))->Cmd);
644 tooling::CompileCommand CmdStored = *MSS.
loadShard(testPath(
"A.cc"))->Cmd;
645 EXPECT_EQ(CmdStored.CommandLine, Cmd.CommandLine);
646 EXPECT_EQ(CmdStored.Directory, Cmd.Directory);
649TEST_F(BackgroundIndexTest, Reindex) {
651 llvm::StringMap<std::string> Storage;
652 size_t CacheHits = 0;
653 MemoryShardStorage MSS(Storage, CacheHits);
654 OverlayCDB CDB(
nullptr);
655 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
659 FS.Files[
testPath(
"A.cc")] =
"int theOldFunction();";
660 tooling::CompileCommand Cmd;
661 Cmd.Filename =
"../A.cc";
663 Cmd.CommandLine = {
"clang++",
"../A.cc",
"-fsyntax-only"};
664 CDB.setCompileCommand(
testPath(
"A.cc"), Cmd);
665 ASSERT_TRUE(Idx.blockUntilIdleForTest());
668 EXPECT_EQ(1u,
runFuzzyFind(Idx,
"theOldFunction").size());
670 std::string OldShard = Storage.lookup(
testPath(
"A.cc"));
671 EXPECT_NE(
"", OldShard);
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());
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")));
689 Rebuilder(&Target, &Source, 10) {
695 bool checkRebuild(std::function<
void()>
Action) {
697 VersionStorage.push_back(
"Sym" + std::to_string(++VersionCounter));
698 TestSymbol.Name = VersionStorage.back();
701 Source.update(
"", std::make_unique<SymbolSlab>(std::move(SB).build()),
702 nullptr,
nullptr,
false);
706 std::string ReadName;
708 Req.
IDs.insert(TestSymbol.ID);
710 [&](
const Symbol &S) { ReadName = std::string(S.Name); });
712 return ReadName == VersionStorage.back();
720 unsigned VersionCounter = 0;
721 std::deque<std::string> VersionStorage;
724TEST_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(); }));
733TEST_F(BackgroundIndexRebuilderTest, LoadingShards) {
734 Rebuilder.startLoading();
735 Rebuilder.loadedShard(10);
736 Rebuilder.loadedShard(20);
737 EXPECT_TRUE(checkRebuild([&] { Rebuilder.doneLoading(); }));
740 Rebuilder.startLoading();
741 EXPECT_FALSE(checkRebuild([&] { Rebuilder.doneLoading(); }));
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(); }));
753 Rebuilder.startLoading();
754 for (
unsigned I = 0; I < 3 * Rebuilder.TUsBeforeRebuild; ++I)
755 EXPECT_FALSE(checkRebuild([&] { Rebuilder.indexedTU(); }));
757 EXPECT_TRUE(checkRebuild([&] { Rebuilder.doneLoading(); }));
760TEST(BackgroundQueueTest, Priority) {
765 std::atomic<unsigned> HiRan(0), LoRan(0);
766 BackgroundQueue::Task Lo([&] { ++LoRan; });
767 BackgroundQueue::Task Hi([&] {
774 Q.append(std::vector<BackgroundQueue::Task>(30, Lo));
775 for (
unsigned I = 0; I < 30; ++I)
779 for (
unsigned I = 0; I < 5; ++I)
780 ThreadPool.
runAsync(
"worker", [&] { Q.work(); });
784 Q.append(std::vector<BackgroundQueue::Task>(2, Hi));
788 EXPECT_GE(HiRan, 10u);
789 EXPECT_EQ(LoRan, 0u);
792TEST(BackgroundQueueTest, Boost) {
793 std::string Sequence;
795 BackgroundQueue::Task A([&] { Sequence.push_back(
'A'); });
799 BackgroundQueue::Task B([&] { Sequence.push_back(
'B'); });
806 Q.work([&] { Q.stop(); });
807 EXPECT_EQ(
"BA", Sequence) <<
"priority order";
815 EXPECT_EQ(
"AB", Sequence) <<
"A was boosted before enqueueing";
822 Q.work([&] { Q.stop(); });
823 EXPECT_EQ(
"AB", Sequence) <<
"A was boosted after enqueueing";
827TEST(BackgroundQueueTest, Duplicates) {
828 std::string Sequence;
829 BackgroundQueue::Task
A([&] { Sequence.push_back(
'A'); });
832 BackgroundQueue::Task
B([&] { Sequence.push_back(
'B'); });
840 if (!llvm::is_contained(Sequence,
' ')) {
841 Sequence.push_back(
' ');
849 EXPECT_EQ(
"ABB BB", Sequence);
852TEST(BackgroundQueueTest, Progress) {
853 using testing::AnyOf;
854 BackgroundQueue::Stats S;
855 BackgroundQueue Q([&](BackgroundQueue::Stats New) {
858 EXPECT_THAT(New.Enqueued, AnyOf(S.Enqueued, S.Enqueued + 1));
860 EXPECT_THAT(New.Completed, AnyOf(S.Completed, S.Completed + 1));
862 EXPECT_THAT(New.Active, AnyOf(S.Active - 1, S.Active, S.Active + 1));
864 EXPECT_GE(New.LastIdle, S.LastIdle);
866 EXPECT_LE(New.LastIdle, New.Completed);
868 EXPECT_EQ(New.LastIdle == New.Enqueued,
869 New.Completed == New.Enqueued && New.Active == 0u);
875 std::atomic<int> PingCount(0), PongCount(0);
876 BackgroundQueue::Task Pong([&] { ++PongCount; });
877 BackgroundQueue::Task Ping([&] {
882 for (
int I = 0; I < 1000; ++I)
886 for (
unsigned I = 0; I < 5; ++I)
887 ThreadPool.
runAsync(
"worker", [&] { Q.work([&] { Q.stop(); }); });
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);
900TEST(BackgroundIndex, Profile) {
902 MockCompilationDatabase CDB;
903 BackgroundIndex Idx(FS, CDB, [](llvm::StringRef) {
return nullptr; },
906 llvm::BumpPtrAllocator Alloc;
907 MemoryTree MT(&Alloc);
909 ASSERT_THAT(MT.children(),
910 UnorderedElementsAre(Pair(
"slabs", _), Pair(
"index", _)));
llvm::SmallString< 256U > Name
std::string Filename
Filename as a string.
Runs tasks on separate (detached) threads and wait for all tasks to finish.
void runAsync(const llvm::Twine &Name, llvm::unique_function< void()> Action)
static void preventThreadStarvationInTests()
void append(std::vector< Task >)
void work(std::function< void()> OnIdle=nullptr)
void boost(llvm::StringRef Tag, unsigned NewPriority)
Context derive(const Key< Type > &Key, std::decay_t< Type > Value) const &
Derives a child context It is safe to move or destroy a parent context after calling derive().
static const Context & current()
Returns the context for the current thread, creating it if needed.
A container of slabs associated with a key.
MemIndex is a naive in-memory index suitable for a small set of symbols.
llvm::Error storeShard(llvm::StringRef ShardIdentifier, IndexFileOut Shard) const override
std::unique_ptr< IndexFileIn > loadShard(llvm::StringRef ShardIdentifier) const override
llvm::StringSet AccessedPaths
MemoryShardStorage(llvm::StringMap< std::string > &Storage, size_t &CacheHits)
Wraps another compilation database, and supports overriding the commands using an in-memory mapping.
SymbolSlab::Builder is a mutable container that can 'freeze' to SymbolSlab.
void insert(const Symbol &S)
Adds a symbol, overwriting any existing one with the same ID.
::testing::Matcher< const RefSlab & > refsAre(std::vector<::testing::Matcher< Ref > > Matchers)
llvm::Expected< IndexFileIn > readIndexFile(llvm::StringRef Data, SymbolOrigin Origin)
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
IndexContents
Describes what data is covered by an index.
std::array< uint8_t, 8 > FileDigest
std::string testPath(PathRef File, llvm::sys::path::Style Style)
TEST(BackgroundQueueTest, Priority)
RefSlab getRefs(const SymbolIndex &Index, SymbolID ID)
const Symbol & findSymbol(const SymbolSlab &Slab, llvm::StringRef QName)
llvm::StringRef PathRef
A typedef to represent a ref to file path.
SymbolSlab runFuzzyFind(const SymbolIndex &Index, llvm::StringRef Query)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static CommandMangler forTests()
Settings that express user/project preferences and control clangd behavior.
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
llvm::DenseSet< SymbolID > IDs
Represents a relation between two symbols.
The class presents a C++ symbol, e.g.
SymbolID ID
The ID of the symbol.