11#include "clang/Tooling/ArgumentsAdjusters.h"
12#include "clang/Tooling/CompilationDatabase.h"
13#include "llvm/ADT/STLExtras.h"
14#include "llvm/Support/ScopedPrinter.h"
15#include "gmock/gmock.h"
16#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));
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")};
110 ASSERT_TRUE(Idx.blockUntilIdleForTest());
117 std::vector<tooling::CompileCommand> Cmds;
118 for (std::string Name : {
"foo",
"bar",
"baz"}) {
119 std::string Filename = Name +
".cpp";
120 std::string Header = Name +
".h";
121 FS.
Files[Filename] =
"#include \"" + Header +
"\"";
122 FS.
Files[Header] =
"namespace " + Name +
" { int one; }";
123 tooling::CompileCommand Cmd;
124 Cmd.Filename = Filename;
126 Cmd.CommandLine = {
"clang++", Filename};
127 Cmds.push_back(std::move(Cmd));
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")));
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")};
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};
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, ConstructorForwarding) {
237 Annotations Header(R
"cpp(
239 template <class T> T &&forward(T &t);
240 template <class T, class... Args> T *make_unique(Args &&...args) {
241 return new T(std::forward<Args>(args)...);
248 Annotations Main(R"cpp(
249 #include "header.hpp"
251 auto a = std::[[make_unique]]<Test>();
256 llvm::StringMap<std::string> Storage;
257 size_t CacheHits = 0;
261 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; }, Opts);
266 tooling::CompileCommand Cmd;
267 Cmd.Filename =
testPath(
"root/test.cpp");
269 Cmd.CommandLine = {
"clang++",
testPath(
"root/test.cpp")};
272 ASSERT_TRUE(Idx.blockUntilIdleForTest());
276 std::find_if(Syms.begin(), Syms.end(), [](
const Symbol &S) {
277 return S.SymInfo.Kind == index::SymbolKind::Constructor;
281 refsAre({fileURI(
"unittest:///root/header.hpp"),
282 fileURI(
"unittest:///root/test.cpp")}));
293 template <class T> T &&forward(T &t);
294 template <class T, class... Args> T *make_unique(Args &&...args) {
295 return new T(std::forward<Args>(args)...);
303 #include "header.hpp"
305 auto a = std::[[make_unique]]<Test>();
309 #include "header.hpp"
311 auto a = std::[[make_unique]]<Test>();
316 llvm::StringMap<std::string> Storage;
317 size_t CacheHits = 0;
321 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; }, Opts);
327 tooling::CompileCommand Cmd;
328 Cmd.Filename =
testPath(
"root/first.cpp");
330 Cmd.CommandLine = {
"clang++",
testPath(
"root/first.cpp")};
335 ASSERT_TRUE(Idx.blockUntilIdleForTest());
337 Cmd.Filename =
testPath(
"root/second.cpp");
339 Cmd.CommandLine = {
"clang++",
testPath(
"root/second.cpp")};
342 ASSERT_TRUE(Idx.blockUntilIdleForTest());
346 std::find_if(Syms.begin(), Syms.end(), [](
const Symbol &S) {
347 return S.SymInfo.Kind == index::SymbolKind::Constructor;
351 refsAre({fileURI(
"unittest:///root/header.hpp"),
352 fileURI(
"unittest:///root/first.cpp"),
353 fileURI(
"unittest:///root/second.cpp")}));
362 "#include \"A.h\"\nstatic void main_sym() { (void)header_sym; }";
364 llvm::StringMap<std::string> Storage;
365 size_t CacheHits = 0;
370 FS, CDB, [&](llvm::StringRef) {
return &MSS; }, Opts);
372 tooling::CompileCommand Cmd;
373 Cmd.Filename =
testPath(
"root/A.cc");
375 Cmd.CommandLine = {
"clang++",
testPath(
"root/A.cc")};
378 ASSERT_TRUE(Idx.blockUntilIdleForTest());
381 UnorderedElementsAre(AllOf(named(
"header_sym"), numReferences(1U)),
382 AllOf(named(
"main_sym"), numReferences(1U))));
392 FS.Files[testPath("root/A.cc")] = R
"cpp(
394 void g() { (void)common; }
395 class B_CC : public A_CC {};
398 llvm::StringMap<std::string> Storage;
399 size_t CacheHits = 0;
402 tooling::CompileCommand Cmd;
403 Cmd.Filename =
testPath(
"root/A.cc");
405 Cmd.CommandLine = {
"clang++",
testPath(
"root/A.cc")};
408 OverlayCDB CDB(
nullptr);
409 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
412 ASSERT_TRUE(Idx.blockUntilIdleForTest());
414 EXPECT_EQ(CacheHits, 0U);
415 EXPECT_EQ(Storage.size(), 2U);
422 ASSERT_TRUE(Idx.blockUntilIdleForTest());
424 EXPECT_EQ(CacheHits, 2U);
425 EXPECT_EQ(Storage.size(), 2U);
428 EXPECT_NE(ShardHeader,
nullptr);
430 *ShardHeader->Symbols,
431 UnorderedElementsAre(named(
"common"), named(
"A_CC"),
432 AllOf(named(
"f_b"), declared(), Not(defined()))));
433 for (
const auto &
Ref : *ShardHeader->Refs)
434 EXPECT_THAT(
Ref.second,
435 UnorderedElementsAre(fileURI(
"unittest:///root/A.h")));
438 EXPECT_NE(ShardSource,
nullptr);
439 EXPECT_THAT(*ShardSource->Symbols,
440 UnorderedElementsAre(named(
"g"), named(
"B_CC")));
441 for (
const auto &
Ref : *ShardSource->Refs)
442 EXPECT_THAT(
Ref.second,
443 UnorderedElementsAre(fileURI(
"unittest:///root/A.cc")));
450 EXPECT_THAT(*ShardHeader->Relations,
452 EXPECT_THAT(*ShardSource->Relations,
459 FS.Files[
testPath(
"root/A.h")] = R
"cpp(
466 "#include \"A.h\"\nvoid g() { (void)common; }";
468 llvm::StringMap<std::string> Storage;
469 size_t CacheHits = 0;
472 tooling::CompileCommand Cmd;
473 Cmd.Filename =
testPath(
"root/A.cc");
475 Cmd.CommandLine = {
"clang++",
testPath(
"root/A.cc")};
481 ASSERT_TRUE(Idx.blockUntilIdleForTest());
485 EXPECT_TRUE(ShardSource->Sources);
486 EXPECT_EQ(ShardSource->Sources->size(), 2U);
488 ShardSource->Sources->lookup(
"unittest:///root/A.cc").DirectIncludes,
489 UnorderedElementsAre(
"unittest:///root/A.h"));
490 EXPECT_NE(ShardSource->Sources->lookup(
"unittest:///root/A.cc").Digest,
492 EXPECT_THAT(ShardSource->Sources->lookup(
"unittest:///root/A.h"),
496 EXPECT_TRUE(ShardHeader->Sources);
497 EXPECT_EQ(ShardHeader->Sources->size(), 2U);
499 ShardHeader->Sources->lookup(
"unittest:///root/A.h").DirectIncludes,
500 UnorderedElementsAre(
"unittest:///root/B.h"));
501 EXPECT_NE(ShardHeader->Sources->lookup(
"unittest:///root/A.h").Digest,
503 EXPECT_THAT(ShardHeader->Sources->lookup(
"unittest:///root/B.h"),
507TEST_F(BackgroundIndexTest, ShardStorageLoad) {
509 FS.Files[testPath(
"root/A.h")] = R
"cpp(
514 FS.Files[testPath("root/A.cc")] =
515 "#include \"A.h\"\nvoid g() { (void)common; }";
517 llvm::StringMap<std::string> Storage;
518 size_t CacheHits = 0;
519 MemoryShardStorage MSS(Storage, CacheHits);
521 tooling::CompileCommand Cmd;
522 Cmd.Filename = testPath(
"root/A.cc");
523 Cmd.Directory = testPath(
"root");
524 Cmd.CommandLine = {
"clang++", testPath(
"root/A.cc")};
527 OverlayCDB CDB(
nullptr);
528 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
531 ASSERT_TRUE(Idx.blockUntilIdleForTest());
535 FS.Files[
testPath(
"root/A.h")] = R
"cpp(
542 OverlayCDB CDB(nullptr);
543 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
546 ASSERT_TRUE(Idx.blockUntilIdleForTest());
548 EXPECT_EQ(CacheHits, 2U);
552 EXPECT_NE(ShardHeader,
nullptr);
553 EXPECT_THAT(*ShardHeader->Symbols, Contains(named(
"A_CCnew")));
557 "#include \"A.h\"\nvoid g() { (void)common; }\nvoid f_b() {}";
560 OverlayCDB CDB(
nullptr);
561 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
564 ASSERT_TRUE(Idx.blockUntilIdleForTest());
566 EXPECT_EQ(CacheHits, 2U);
569 ShardHeader = MSS.
loadShard(testPath(
"root/A.h"));
570 EXPECT_NE(ShardHeader,
nullptr);
571 EXPECT_THAT(*ShardHeader->Symbols, Contains(named(
"A_CCnew")));
572 auto ShardSource = MSS.
loadShard(testPath(
"root/A.cc"));
573 EXPECT_NE(ShardSource,
nullptr);
574 EXPECT_THAT(*ShardSource->Symbols,
575 Contains(AllOf(named(
"f_b"), declared(), defined())));
578TEST_F(BackgroundIndexTest, ShardStorageEmptyFile) {
580 FS.Files[
testPath(
"root/A.h")] = R
"cpp(
585 FS.Files[testPath("root/B.h")] = R
"cpp(
589 "#include \"B.h\"\nvoid g() { (void)common; }";
591 llvm::StringMap<std::string> Storage;
592 size_t CacheHits = 0;
595 tooling::CompileCommand Cmd;
596 Cmd.Filename =
testPath(
"root/A.cc");
598 Cmd.CommandLine = {
"clang++",
testPath(
"root/A.cc")};
601 OverlayCDB CDB(
nullptr);
602 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
605 ASSERT_TRUE(Idx.blockUntilIdleForTest());
607 EXPECT_THAT(Storage.keys(),
611 EXPECT_NE(ShardHeader,
nullptr);
612 EXPECT_TRUE(ShardHeader->Symbols->empty());
617 OverlayCDB CDB(
nullptr);
618 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
621 ASSERT_TRUE(Idx.blockUntilIdleForTest());
623 EXPECT_EQ(CacheHits, 3U);
626 FS.Files[
testPath(
"root/B.h")] = R
"cpp(
633 OverlayCDB CDB(
nullptr);
634 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
637 ASSERT_TRUE(Idx.blockUntilIdleForTest());
639 EXPECT_EQ(CacheHits, 3U);
641 EXPECT_NE(ShardHeader,
nullptr);
642 EXPECT_THAT(*ShardHeader->Symbols,
643 Contains(AllOf(named(
"new_func"), declared(), Not(defined()))));
646TEST_F(BackgroundIndexTest, NoDotsInAbsPath) {
648 llvm::StringMap<std::string> Storage;
649 size_t CacheHits = 0;
650 MemoryShardStorage MSS(Storage, CacheHits);
654 ASSERT_TRUE(Idx.blockUntilIdleForTest());
656 tooling::CompileCommand Cmd;
657 FS.Files[testPath(
"root/A.cc")] =
"";
658 Cmd.Filename =
"../A.cc";
659 Cmd.Directory = testPath(
"root/build");
660 Cmd.CommandLine = {
"clang++",
"../A.cc"};
662 ASSERT_TRUE(Idx.blockUntilIdleForTest());
664 FS.Files[
testPath(
"root/B.cc")] =
"";
665 Cmd.Filename =
"./B.cc";
667 Cmd.CommandLine = {
"clang++",
"./B.cc"};
669 ASSERT_TRUE(Idx.blockUntilIdleForTest());
672 EXPECT_FALSE(AbsPath.contains(
"./")) << AbsPath;
673 EXPECT_FALSE(AbsPath.contains(
"../")) << AbsPath;
677TEST_F(BackgroundIndexTest, UncompilableFiles) {
679 llvm::StringMap<std::string> Storage;
680 size_t CacheHits = 0;
686 tooling::CompileCommand Cmd;
687 FS.Files[testPath(
"A.h")] =
"void foo();";
688 FS.Files[testPath(
"B.h")] =
"#include \"C.h\"\nasdf;";
689 FS.Files[testPath(
"C.h")] =
"";
690 FS.Files[testPath(
"A.cc")] = R
"cpp(
693 #include "not_found_header.h"
697 Cmd.Filename = "../A.cc";
698 Cmd.Directory = testPath(
"build");
699 Cmd.CommandLine = {
"clang++",
"../A.cc"};
701 ASSERT_TRUE(Idx.blockUntilIdleForTest());
703 EXPECT_THAT(Storage.keys(),
709 EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(named(
"foo")));
710 EXPECT_THAT(Shard->Sources->keys(),
711 UnorderedElementsAre(
"unittest:///A.cc",
"unittest:///A.h",
713 EXPECT_THAT(Shard->Sources->lookup(
"unittest:///A.cc"), hadErrors());
718 EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(named(
"foo")));
719 EXPECT_THAT(Shard->Sources->keys(),
720 UnorderedElementsAre(
"unittest:///A.h"));
721 EXPECT_THAT(Shard->Sources->lookup(
"unittest:///A.h"), hadErrors());
726 EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(named(
"asdf")));
727 EXPECT_THAT(Shard->Sources->keys(),
728 UnorderedElementsAre(
"unittest:///B.h",
"unittest:///C.h"));
729 EXPECT_THAT(Shard->Sources->lookup(
"unittest:///B.h"), hadErrors());
734 EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre());
735 EXPECT_THAT(Shard->Sources->keys(),
736 UnorderedElementsAre(
"unittest:///C.h"));
737 EXPECT_THAT(Shard->Sources->lookup(
"unittest:///C.h"), hadErrors());
741TEST_F(BackgroundIndexTest, CmdLineHash) {
743 llvm::StringMap<std::string> Storage;
744 size_t CacheHits = 0;
745 MemoryShardStorage MSS(Storage, CacheHits);
750 tooling::CompileCommand Cmd;
753 Cmd.Filename =
"../A.cc";
755 Cmd.CommandLine = {
"clang++",
"../A.cc",
"-fsyntax-only"};
757 ASSERT_TRUE(Idx.blockUntilIdleForTest());
759 EXPECT_THAT(Storage.keys(),
760 UnorderedElementsAre(testPath(
"A.cc"), testPath(
"A.h")));
762 EXPECT_FALSE(MSS.
loadShard(testPath(
"A.h"))->Cmd);
765 EXPECT_EQ(CmdStored.CommandLine, Cmd.CommandLine);
766 EXPECT_EQ(CmdStored.Directory, Cmd.Directory);
769TEST_F(BackgroundIndexTest, Reindex) {
771 llvm::StringMap<std::string> Storage;
772 size_t CacheHits = 0;
773 MemoryShardStorage MSS(Storage, CacheHits);
774 OverlayCDB CDB(
nullptr);
775 BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) {
return &MSS; },
779 FS.Files[
testPath(
"A.cc")] =
"int theOldFunction();";
780 tooling::CompileCommand Cmd;
781 Cmd.Filename =
"../A.cc";
783 Cmd.CommandLine = {
"clang++",
"../A.cc",
"-fsyntax-only"};
785 ASSERT_TRUE(Idx.blockUntilIdleForTest());
788 EXPECT_EQ(1u,
runFuzzyFind(Idx,
"theOldFunction").size());
789 EXPECT_EQ(0u,
runFuzzyFind(Idx,
"theNewFunction").size());
790 std::string OldShard = Storage.lookup(
testPath(
"A.cc"));
791 EXPECT_NE(
"", OldShard);
794 Cmd.CommandLine.push_back(
"-DFOO");
795 FS.Files[
testPath(
"A.cc")] =
"int theNewFunction();";
797 ASSERT_TRUE(Idx.blockUntilIdleForTest());
800 EXPECT_EQ(1u,
runFuzzyFind(Idx,
"theOldFunction").size());
801 EXPECT_EQ(0u,
runFuzzyFind(Idx,
"theNewFunction").size());
802 EXPECT_EQ(OldShard, Storage.lookup(
testPath(
"A.cc")));
805class BackgroundIndexRebuilderTest :
public testing::Test {
807 BackgroundIndexRebuilderTest()
808 : Source(IndexContents::All, true),
809 Target(std::make_unique<MemIndex>()),
810 Rebuilder(&Target, &Source, 10) {
812 TestSymbol.ID = SymbolID(
"foo");
816 bool checkRebuild(std::function<
void()> Action) {
818 VersionStorage.push_back(
"Sym" + std::to_string(++VersionCounter));
819 TestSymbol.Name = VersionStorage.back();
820 SymbolSlab::Builder SB;
821 SB.insert(TestSymbol);
822 Source.update(
"", std::make_unique<SymbolSlab>(std::move(SB).build()),
823 nullptr,
nullptr,
false);
827 std::string ReadName;
829 Req.
IDs.insert(TestSymbol.ID);
831 [&](
const Symbol &S) { ReadName = std::string(S.
Name); });
833 return ReadName == VersionStorage.back();
839 BackgroundIndexRebuilder Rebuilder;
841 unsigned VersionCounter = 0;
842 std::deque<std::string> VersionStorage;
845TEST_F(BackgroundIndexRebuilderTest, IndexingTUs) {
846 for (
unsigned I = 0; I < Rebuilder.TUsBeforeFirstBuild - 1; ++I)
847 EXPECT_FALSE(checkRebuild([&] { Rebuilder.indexedTU(); }));
848 EXPECT_TRUE(checkRebuild([&] { Rebuilder.indexedTU(); }));
849 for (
unsigned I = 0; I < Rebuilder.TUsBeforeRebuild - 1; ++I)
850 EXPECT_FALSE(checkRebuild([&] { Rebuilder.indexedTU(); }));
851 EXPECT_TRUE(checkRebuild([&] { Rebuilder.indexedTU(); }));
854TEST_F(BackgroundIndexRebuilderTest, LoadingShards) {
855 Rebuilder.startLoading();
856 Rebuilder.loadedShard(10);
857 Rebuilder.loadedShard(20);
858 EXPECT_TRUE(checkRebuild([&] { Rebuilder.doneLoading(); }));
861 Rebuilder.startLoading();
862 EXPECT_FALSE(checkRebuild([&] { Rebuilder.doneLoading(); }));
865 Rebuilder.startLoading();
866 Rebuilder.loadedShard(1);
867 Rebuilder.startLoading();
868 Rebuilder.loadedShard(1);
869 EXPECT_FALSE(checkRebuild([&] { Rebuilder.doneLoading(); }));
870 Rebuilder.loadedShard(1);
871 EXPECT_TRUE(checkRebuild([&] { Rebuilder.doneLoading(); }));
874 Rebuilder.startLoading();
875 for (
unsigned I = 0; I < 3 * Rebuilder.TUsBeforeRebuild; ++I)
876 EXPECT_FALSE(checkRebuild([&] { Rebuilder.indexedTU(); }));
878 EXPECT_TRUE(checkRebuild([&] { Rebuilder.doneLoading(); }));
881TEST(BackgroundQueueTest, Priority) {
886 std::atomic<unsigned> HiRan(0), LoRan(0);
888 BackgroundQueue::Task Hi([&] {
895 Q.
append(std::vector<BackgroundQueue::Task>(30, Lo));
896 for (
unsigned I = 0; I < 30; ++I)
899 AsyncTaskRunner ThreadPool;
900 for (
unsigned I = 0; I < 5; ++I)
901 ThreadPool.runAsync(
"worker", [&] { Q.work(); });
905 Q.
append(std::vector<BackgroundQueue::Task>(2, Hi));
909 EXPECT_GE(HiRan, 10u);
910 EXPECT_EQ(LoRan, 0u);
913TEST(BackgroundQueueTest, Boost) {
914 std::string Sequence;
916 BackgroundQueue::Task
A([&] { Sequence.push_back(
'A'); });
920 BackgroundQueue::Task
B([&] { Sequence.push_back(
'B'); });
927 Q.work([&] { Q.stop(); });
928 EXPECT_EQ(
"BA", Sequence) <<
"priority order";
936 EXPECT_EQ(
"AB", Sequence) <<
"A was boosted before enqueueing";
943 Q.work([&] { Q.stop(); });
944 EXPECT_EQ(
"AB", Sequence) <<
"A was boosted after enqueueing";
948TEST(BackgroundQueueTest, Duplicates) {
949 std::string Sequence;
950 BackgroundQueue::Task
A([&] { Sequence.push_back(
'A'); });
953 BackgroundQueue::Task
B([&] { Sequence.push_back(
'B'); });
958 Q.append({
A,
B,
A,
B});
961 if (!llvm::is_contained(Sequence,
' ')) {
962 Sequence.push_back(
' ');
963 Q.append({
A,
B,
A,
B});
970 EXPECT_EQ(
"ABB BB", Sequence);
973TEST(BackgroundQueueTest, Progress) {
974 using testing::AnyOf;
975 BackgroundQueue::Stats S;
976 BackgroundQueue Q([&](BackgroundQueue::Stats New) {
979 EXPECT_THAT(New.Enqueued, AnyOf(S.Enqueued, S.Enqueued + 1));
981 EXPECT_THAT(New.Completed, AnyOf(S.Completed, S.Completed + 1));
983 EXPECT_THAT(New.Active, AnyOf(S.Active - 1, S.Active, S.Active + 1));
985 EXPECT_GE(New.LastIdle, S.LastIdle);
987 EXPECT_LE(New.LastIdle, New.Completed);
989 EXPECT_EQ(New.LastIdle == New.Enqueued,
990 New.Completed == New.Enqueued && New.Active == 0u);
996 std::atomic<int> PingCount(0), PongCount(0);
997 BackgroundQueue::Task Pong([&] { ++PongCount; });
998 BackgroundQueue::Task Ping([&] {
1003 for (
int I = 0; I < 1000; ++I)
1006 AsyncTaskRunner ThreadPool;
1007 for (
unsigned I = 0; I < 5; ++I)
1008 ThreadPool.runAsync(
"worker", [&] { Q.work([&] { Q.stop(); }); });
1013 EXPECT_EQ(PingCount.load(), 1000);
1014 EXPECT_EQ(PongCount.load(), 1000);
1015 EXPECT_EQ(S.Active, 0u);
1016 EXPECT_EQ(S.Enqueued, 2000u);
1017 EXPECT_EQ(S.Completed, 2000u);
1018 EXPECT_EQ(S.LastIdle, 2000u);
1021TEST(BackgroundIndex, Profile) {
1023 MockCompilationDatabase CDB;
1024 BackgroundIndex Idx(FS, CDB, [](llvm::StringRef) {
return nullptr; },
1027 llvm::BumpPtrAllocator Alloc;
1028 MemoryTree MT(&Alloc);
1030 ASSERT_THAT(MT.children(),
1031 UnorderedElementsAre(Pair(
"slabs", _), Pair(
"index", _)));
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges.
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.
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)
llvm::StringMap< std::string > Files
Wraps another compilation database, and supports overriding the commands using an in-memory mapping.
bool setCompileCommand(PathRef File, std::optional< tooling::CompileCommand > CompilationCommand)
Sets or clears the compilation command for a particular file.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
::testing::Matcher< const RefSlab & > refsAre(std::vector<::testing::Matcher< Ref > > Matchers)
llvm::Expected< IndexFileIn > readIndexFile(llvm::StringRef Data, SymbolOrigin Origin)
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
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)
std::array< uint8_t, 8 > FileDigest
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::function< Context(PathRef)> ContextProvider
A work item on the thread pool's queue.
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 symbol occurrence in the source file.
Represents a relation between two symbols.
The class presents a C++ symbol, e.g.
llvm::StringRef Name
The unqualified name of the symbol, e.g. "bar" (for ns::bar).
SymbolID ID
The ID of the symbol.