10 #include "clang/Tooling/ArgumentsAdjusters.h"
11 #include "clang/Tooling/CompilationDatabase.h"
12 #include "llvm/Support/ScopedPrinter.h"
13 #include "llvm/Support/Threading.h"
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
20 using ::testing::AllOf;
21 using ::testing::Contains;
22 using ::testing::ElementsAre;
24 using ::testing::UnorderedElementsAre;
30 MATCHER_P(QName, N,
"") {
return (arg.Scope + arg.Name).str() == N; }
32 return !StringRef(arg.CanonicalDeclaration.FileURI).empty();
34 MATCHER(Defined,
"") {
return !StringRef(arg.Definition.FileURI).empty(); }
35 MATCHER_P(FileURI, F,
"") {
return StringRef(arg.Location.FileURI) == F; }
36 ::testing::Matcher<const RefSlab &>
37 RefsAre(std::vector<::testing::Matcher<Ref>> Matchers) {
38 return ElementsAre(::testing::Pair(_, UnorderedElementsAreArray(Matchers)));
43 arg.Digest ==
FileDigest{{0}} && arg.DirectIncludes.empty();
50 MATCHER_P(NumReferences, N,
"") {
return arg.References == N; }
53 mutable std::mutex StorageMu;
54 llvm::StringMap<std::string> &Storage;
59 : Storage(Storage), CacheHits(CacheHits) {}
62 std::lock_guard<std::mutex> Lock(StorageMu);
64 Storage[ShardIdentifier] = llvm::to_string(Shard);
65 return llvm::Error::success();
67 std::unique_ptr<IndexFileIn>
68 loadShard(llvm::StringRef ShardIdentifier)
const override {
69 std::lock_guard<std::mutex> Lock(StorageMu);
71 if (Storage.find(ShardIdentifier) == Storage.end()) {
76 ADD_FAILURE() <<
"Error while reading " << ShardIdentifier <<
':'
77 << IndexFile.takeError();
81 return std::make_unique<IndexFileIn>(std::move(*IndexFile));
95 llvm::StringMap<std::string> Storage;
100 [&](llvm::StringRef) {
return &MSS; });
102 tooling::CompileCommand Cmd;
103 Cmd.Filename =
testPath(
"root/A.cc");
105 Cmd.CommandLine = {
"clang++",
"-DA=1",
testPath(
"root/A.cc")};
106 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
108 ASSERT_TRUE(Idx.blockUntilIdleForTest());
115 std::vector<tooling::CompileCommand> Cmds;
116 for (std::string
Name : {
"foo",
"bar",
"baz"}) {
118 std::string Header =
Name +
".h";
120 FS.
Files[Header] =
"namespace " +
Name +
" { int one; }";
121 tooling::CompileCommand Cmd;
124 Cmd.CommandLine = {
"clang++",
Filename};
125 Cmds.push_back(std::move(Cmd));
130 auto ContextProvider = [](
PathRef P) {
132 if (P.endswith(
"foo.cpp"))
134 [](std::vector<std::string> &Argv) { Argv.push_back(
"-Done=two"); });
135 if (P.endswith(
"baz.cpp"))
140 llvm::StringMap<std::string> Storage;
141 size_t CacheHits = 0;
148 4,
nullptr, std::move(ContextProvider));
150 for (
auto &Cmd : Cmds) {
151 std::string FullPath =
testPath(Cmd.Filename);
152 CDB.setCompileCommand(FullPath, std::move(Cmd));
155 ASSERT_TRUE(Idx.blockUntilIdleForTest());
157 UnorderedElementsAre(QName(
"foo"), QName(
"foo::two"),
158 QName(
"bar"), QName(
"bar::one")));
174 "#include \"A.h\"\nvoid g() { (void)common; }";
185 llvm::StringMap<std::string> Storage;
186 size_t CacheHits = 0;
190 [&](llvm::StringRef) {
return &MSS; });
192 tooling::CompileCommand Cmd;
193 Cmd.Filename =
testPath(
"root/A.cc");
195 Cmd.CommandLine = {
"clang++",
"-DA=1",
testPath(
"root/A.cc")};
196 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
198 ASSERT_TRUE(Idx.blockUntilIdleForTest());
200 UnorderedElementsAre(AllOf(Named(
"common"), NumReferences(1U)),
201 AllOf(Named(
"A_CC"), NumReferences(0U)),
202 AllOf(Named(
"g"), NumReferences(0U)),
203 AllOf(Named(
"f_b"), Declared(),
204 Not(Defined()), NumReferences(0U))));
206 Cmd.Filename =
testPath(
"root/B.cc");
207 Cmd.CommandLine = {
"clang++", Cmd.Filename};
208 CDB.setCompileCommand(
testPath(
"root/B.cc"), Cmd);
210 ASSERT_TRUE(Idx.blockUntilIdleForTest());
213 UnorderedElementsAre(AllOf(Named(
"common"), NumReferences(5U)),
214 AllOf(Named(
"A_CC"), NumReferences(0U)),
215 AllOf(Named(
"g"), NumReferences(0U)),
216 AllOf(Named(
"f_b"), Declared(), Defined(),
217 NumReferences(1U))));
220 EXPECT_THAT(Syms, UnorderedElementsAre(Named(
"common")));
221 auto Common = *Syms.begin();
222 EXPECT_THAT(
getRefs(Idx, Common.ID),
223 RefsAre({FileURI(
"unittest:///root/A.h"),
224 FileURI(
"unittest:///root/A.cc"),
225 FileURI(
"unittest:///root/B.cc"),
226 FileURI(
"unittest:///root/B.cc"),
227 FileURI(
"unittest:///root/B.cc"),
228 FileURI(
"unittest:///root/B.cc")}));
238 std::string A_CC = "";
241 void g() { (void)common; }
242 class B_CC : public A_CC {};
245 llvm::StringMap<std::string> Storage;
246 size_t CacheHits = 0;
249 tooling::CompileCommand Cmd;
250 Cmd.Filename =
testPath(
"root/A.cc");
252 Cmd.CommandLine = {
"clang++",
testPath(
"root/A.cc")};
257 [&](llvm::StringRef) {
return &MSS; });
258 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
259 ASSERT_TRUE(Idx.blockUntilIdleForTest());
261 EXPECT_EQ(CacheHits, 0U);
262 EXPECT_EQ(Storage.size(), 2U);
267 [&](llvm::StringRef) {
return &MSS; });
268 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
269 ASSERT_TRUE(Idx.blockUntilIdleForTest());
271 EXPECT_EQ(CacheHits, 2U);
272 EXPECT_EQ(Storage.size(), 2U);
275 EXPECT_NE(ShardHeader,
nullptr);
277 *ShardHeader->Symbols,
278 UnorderedElementsAre(Named(
"common"), Named(
"A_CC"),
279 AllOf(Named(
"f_b"), Declared(), Not(Defined()))));
280 for (
const auto &
Ref : *ShardHeader->Refs)
281 EXPECT_THAT(
Ref.second,
282 UnorderedElementsAre(FileURI(
"unittest:///root/A.h")));
285 EXPECT_NE(ShardSource,
nullptr);
286 EXPECT_THAT(*ShardSource->Symbols,
287 UnorderedElementsAre(Named(
"g"), Named(
"B_CC")));
288 for (
const auto &
Ref : *ShardSource->Refs)
289 EXPECT_THAT(
Ref.second,
290 UnorderedElementsAre(FileURI(
"unittest:///root/A.cc")));
296 EXPECT_THAT(*ShardHeader->Relations,
299 EXPECT_EQ(ShardSource->Relations->size(), 0u);
311 std::string A_CC = "#include \"A.h\"\nvoid g() { (void)common; }";
314 llvm::StringMap<std::string> Storage;
315 size_t CacheHits = 0;
318 tooling::CompileCommand Cmd;
319 Cmd.Filename =
testPath(
"root/A.cc");
321 Cmd.CommandLine = {
"clang++",
testPath(
"root/A.cc")};
325 [&](llvm::StringRef) {
return &MSS; });
326 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
327 ASSERT_TRUE(Idx.blockUntilIdleForTest());
331 EXPECT_TRUE(ShardSource->Sources);
332 EXPECT_EQ(ShardSource->Sources->size(), 2U);
334 ShardSource->Sources->lookup(
"unittest:///root/A.cc").DirectIncludes,
335 UnorderedElementsAre(
"unittest:///root/A.h"));
336 EXPECT_NE(ShardSource->Sources->lookup(
"unittest:///root/A.cc").Digest,
338 EXPECT_THAT(ShardSource->Sources->lookup(
"unittest:///root/A.h"),
342 EXPECT_TRUE(ShardHeader->Sources);
343 EXPECT_EQ(ShardHeader->Sources->size(), 2U);
345 ShardHeader->Sources->lookup(
"unittest:///root/A.h").DirectIncludes,
346 UnorderedElementsAre(
"unittest:///root/B.h"));
347 EXPECT_NE(ShardHeader->Sources->lookup(
"unittest:///root/A.h").Digest,
349 EXPECT_THAT(ShardHeader->Sources->lookup(
"unittest:///root/B.h"),
361 "#include \"A.h\"\nvoid g() { (void)common; }";
363 llvm::StringMap<std::string> Storage;
364 size_t CacheHits = 0;
367 tooling::CompileCommand Cmd;
368 Cmd.Filename =
testPath(
"root/A.cc");
370 Cmd.CommandLine = {
"clang++",
testPath(
"root/A.cc")};
375 [&](llvm::StringRef) {
return &MSS; });
376 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
377 ASSERT_TRUE(Idx.blockUntilIdleForTest());
390 [&](llvm::StringRef) {
return &MSS; });
391 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
392 ASSERT_TRUE(Idx.blockUntilIdleForTest());
394 EXPECT_EQ(CacheHits, 2U);
398 EXPECT_NE(ShardHeader,
nullptr);
399 EXPECT_THAT(*ShardHeader->Symbols, Contains(Named(
"A_CCnew")));
403 "#include \"A.h\"\nvoid g() { (void)common; }\nvoid f_b() {}";
408 [&](llvm::StringRef) {
return &MSS; });
409 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
410 ASSERT_TRUE(Idx.blockUntilIdleForTest());
412 EXPECT_EQ(CacheHits, 2U);
416 EXPECT_NE(ShardHeader,
nullptr);
417 EXPECT_THAT(*ShardHeader->Symbols, Contains(Named(
"A_CCnew")));
419 EXPECT_NE(ShardSource,
nullptr);
420 EXPECT_THAT(*ShardSource->Symbols,
421 Contains(AllOf(Named(
"f_b"), Declared(), Defined())));
435 "#include \"B.h\"\nvoid g() { (void)common; }";
437 llvm::StringMap<std::string> Storage;
438 size_t CacheHits = 0;
441 tooling::CompileCommand Cmd;
442 Cmd.Filename =
testPath(
"root/A.cc");
444 Cmd.CommandLine = {
"clang++",
testPath(
"root/A.cc")};
449 [&](llvm::StringRef) {
return &MSS; });
450 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
451 ASSERT_TRUE(Idx.blockUntilIdleForTest());
453 EXPECT_THAT(Storage.keys(),
457 EXPECT_NE(ShardHeader,
nullptr);
458 EXPECT_TRUE(ShardHeader->Symbols->empty());
465 [&](llvm::StringRef) {
return &MSS; });
466 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
467 ASSERT_TRUE(Idx.blockUntilIdleForTest());
469 EXPECT_EQ(CacheHits, 3U);
481 [&](llvm::StringRef) {
return &MSS; });
482 CDB.setCompileCommand(
testPath(
"root/A.cc"), Cmd);
483 ASSERT_TRUE(Idx.blockUntilIdleForTest());
485 EXPECT_EQ(CacheHits, 3U);
487 EXPECT_NE(ShardHeader,
nullptr);
488 EXPECT_THAT(*ShardHeader->Symbols,
489 Contains(AllOf(Named(
"new_func"), Declared(), Not(Defined()))));
494 llvm::StringMap<std::string> Storage;
495 size_t CacheHits = 0;
499 [&](llvm::StringRef) {
return &MSS; });
500 ASSERT_TRUE(Idx.blockUntilIdleForTest());
502 tooling::CompileCommand Cmd;
504 Cmd.Filename =
"../A.cc";
505 Cmd.Directory =
testPath(
"root/build");
506 Cmd.CommandLine = {
"clang++",
"../A.cc"};
507 CDB.setCompileCommand(
testPath(
"root/build/../A.cc"), Cmd);
508 ASSERT_TRUE(Idx.blockUntilIdleForTest());
511 Cmd.Filename =
"./B.cc";
513 Cmd.CommandLine = {
"clang++",
"./B.cc"};
514 CDB.setCompileCommand(
testPath(
"root/./B.cc"), Cmd);
515 ASSERT_TRUE(Idx.blockUntilIdleForTest());
518 EXPECT_FALSE(AbsPath.contains(
"./")) << AbsPath;
519 EXPECT_FALSE(AbsPath.contains(
"../")) << AbsPath;
525 llvm::StringMap<std::string> Storage;
526 size_t CacheHits = 0;
530 [&](llvm::StringRef) {
return &MSS; });
532 tooling::CompileCommand Cmd;
539 #include "not_found_header.h"
543 Cmd.Filename = "../A.cc";
545 Cmd.CommandLine = {
"clang++",
"../A.cc"};
546 CDB.setCompileCommand(
testPath(
"build/../A.cc"), Cmd);
547 ASSERT_TRUE(Idx.blockUntilIdleForTest());
554 EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(Named(
"foo")));
555 EXPECT_THAT(Shard->Sources->keys(),
556 UnorderedElementsAre(
"unittest:///A.cc",
"unittest:///A.h",
558 EXPECT_THAT(Shard->Sources->lookup(
"unittest:///A.cc"), HadErrors());
563 EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(Named(
"foo")));
564 EXPECT_THAT(Shard->Sources->keys(),
565 UnorderedElementsAre(
"unittest:///A.h"));
566 EXPECT_THAT(Shard->Sources->lookup(
"unittest:///A.h"), HadErrors());
571 EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(Named(
"asdf")));
572 EXPECT_THAT(Shard->Sources->keys(),
573 UnorderedElementsAre(
"unittest:///B.h",
"unittest:///C.h"));
574 EXPECT_THAT(Shard->Sources->lookup(
"unittest:///B.h"), HadErrors());
579 EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre());
580 EXPECT_THAT(Shard->Sources->keys(),
581 UnorderedElementsAre(
"unittest:///C.h"));
582 EXPECT_THAT(Shard->Sources->lookup(
"unittest:///C.h"), HadErrors());
588 llvm::StringMap<std::string> Storage;
589 size_t CacheHits = 0;
593 [&](llvm::StringRef) {
return &MSS; });
595 tooling::CompileCommand Cmd;
598 Cmd.Filename =
"../A.cc";
600 Cmd.CommandLine = {
"clang++",
"../A.cc",
"-fsyntax-only"};
601 CDB.setCompileCommand(
testPath(
"build/../A.cc"), Cmd);
602 ASSERT_TRUE(Idx.blockUntilIdleForTest());
604 EXPECT_THAT(Storage.keys(), ElementsAre(
testPath(
"A.cc"),
testPath(
"A.h")));
610 EXPECT_EQ(CmdStored.CommandLine, Cmd.CommandLine);
611 EXPECT_EQ(CmdStored.Directory, Cmd.Directory);
616 Cmd.CommandLine = {
"clang++",
"../A.cc",
"-Dfoo",
"-fsyntax-only"};
617 CDB.setCompileCommand(
testPath(
"build/../A.cc"), Cmd);
618 ASSERT_TRUE(Idx.blockUntilIdleForTest());
624 EXPECT_EQ(CmdStored.CommandLine, Cmd.CommandLine);
625 EXPECT_EQ(CmdStored.Directory, Cmd.Directory);
645 Source.
update(
"", std::make_unique<SymbolSlab>(std::move(SB).build()),
646 nullptr,
nullptr,
false);
650 std::string ReadName;
654 [&](
const Symbol &S) { ReadName = std::string(S.
Name); });
669 for (
unsigned I = 0; I < Rebuilder.TUsBeforeFirstBuild - 1; ++I)
670 EXPECT_FALSE(checkRebuild([&] { Rebuilder.indexedTU(); }));
671 EXPECT_TRUE(checkRebuild([&] { Rebuilder.indexedTU(); }));
672 for (
unsigned I = 0; I < Rebuilder.TUsBeforeRebuild - 1; ++I)
673 EXPECT_FALSE(checkRebuild([&] { Rebuilder.indexedTU(); }));
674 EXPECT_TRUE(checkRebuild([&] { Rebuilder.indexedTU(); }));
678 Rebuilder.startLoading();
679 Rebuilder.loadedShard(10);
680 Rebuilder.loadedShard(20);
681 EXPECT_TRUE(checkRebuild([&] { Rebuilder.doneLoading(); }));
684 Rebuilder.startLoading();
685 EXPECT_FALSE(checkRebuild([&] { Rebuilder.doneLoading(); }));
688 Rebuilder.startLoading();
689 Rebuilder.loadedShard(1);
690 Rebuilder.startLoading();
691 Rebuilder.loadedShard(1);
692 EXPECT_FALSE(checkRebuild([&] { Rebuilder.doneLoading(); }));
693 Rebuilder.loadedShard(1);
694 EXPECT_TRUE(checkRebuild([&] { Rebuilder.doneLoading(); }));
697 Rebuilder.startLoading();
698 for (
unsigned I = 0; I < 3 * Rebuilder.TUsBeforeRebuild; ++I)
699 EXPECT_FALSE(checkRebuild([&] { Rebuilder.indexedTU(); }));
701 EXPECT_TRUE(checkRebuild([&] { Rebuilder.doneLoading(); }));
704 TEST(BackgroundQueueTest, Priority) {
709 std::atomic<unsigned> HiRan(0), LoRan(0);
718 Q.
append(std::vector<BackgroundQueue::Task>(30, Lo));
719 for (
unsigned I = 0; I < 30; ++I)
723 for (
unsigned I = 0; I < 5; ++I)
724 ThreadPool.
runAsync(
"worker", [&] { Q.work(); });
728 Q.
append(std::vector<BackgroundQueue::Task>(2, Hi));
732 EXPECT_GE(HiRan, 10u);
733 EXPECT_EQ(LoRan, 0u);
736 TEST(BackgroundQueueTest, Boost) {
737 std::string Sequence;
751 EXPECT_EQ(
"BA", Sequence) <<
"priority order";
759 EXPECT_EQ(
"AB", Sequence) <<
"A was boosted before enqueueing";
767 EXPECT_EQ(
"AB", Sequence) <<
"A was boosted after enqueueing";
771 TEST(BackgroundQueueTest, Progress) {
772 using testing::AnyOf;
783 EXPECT_GE(New.LastIdle, S.
LastIdle);
785 EXPECT_LE(New.LastIdle, New.Completed);
787 EXPECT_EQ(New.LastIdle == New.Enqueued,
788 New.Completed == New.Enqueued && New.Active == 0u);
794 std::atomic<int> PingCount(0), PongCount(0);
801 for (
int I = 0; I < 1000; ++I)
805 for (
unsigned I = 0; I < 5; ++I)
806 ThreadPool.
runAsync(
"worker", [&] { Q.work([&] { Q.stop(); }); });
811 EXPECT_EQ(PingCount.load(), 1000);
812 EXPECT_EQ(PongCount.load(), 1000);
813 EXPECT_EQ(S.Active, 0u);
814 EXPECT_EQ(S.Enqueued, 2000u);
815 EXPECT_EQ(S.Completed, 2000u);
816 EXPECT_EQ(S.LastIdle, 2000u);