22#include "clang/Tooling/Tooling.h"
23#include "llvm/ADT/ScopeExit.h"
24#include "llvm/ADT/StringRef.h"
25#include "llvm/Support/Chrono.h"
26#include "llvm/Support/CommandLine.h"
27#include "llvm/Support/FileSystem.h"
28#include "llvm/Support/Process.h"
29#include "llvm/Support/VirtualFileSystem.h"
30#include "llvm/Support/raw_ostream.h"
31#include "llvm/TargetParser/Host.h"
32#include "gmock/gmock.h"
33#include "gtest/gtest.h"
38MATCHER_P(named, Name,
"") {
return arg.Name == Name; }
42 GlobalScanningCounterProjectModules(
43 std::unique_ptr<ProjectModules> Underlying, std::atomic<unsigned> &Count)
44 : Underlying(std::move(Underlying)), Count(Count) {}
46 std::vector<std::string> getRequiredModules(
PathRef File)
override {
47 return Underlying->getRequiredModules(
File);
50 std::string getModuleNameForSource(
PathRef File)
override {
51 return Underlying->getModuleNameForSource(
File);
54 void setCommandMangler(CommandMangler Mangler)
override {
55 Underlying->setCommandMangler(std::move(Mangler));
58 std::string getSourceForModuleName(llvm::StringRef ModuleName,
59 PathRef RequiredSrcFile)
override {
61 return Underlying->getSourceForModuleName(ModuleName, RequiredSrcFile);
64 ModuleNameState getModuleNameState(llvm::StringRef ModuleName)
override {
65 return Underlying->getModuleNameState(ModuleName);
69 std::unique_ptr<ProjectModules> Underlying;
70 std::atomic<unsigned> &Count;
75 PerFileModulesCompilationDatabase(StringRef TestDir,
const ThreadsafeFS &TFS)
76 : Directory(TestDir), TFS(TFS),
77 ToolingCDB(std::make_shared<IndexedCompilationDatabase>(*this)) {}
79 void addFile(llvm::StringRef
Path, llvm::StringRef Contents,
80 std::vector<std::string> ExtraFlags = {}) {
81 ASSERT_FALSE(llvm::sys::path::is_absolute(
Path));
83 SmallString<256> AbsPath(Directory);
84 llvm::sys::path::append(AbsPath,
Path);
86 ASSERT_FALSE(llvm::sys::fs::create_directories(
87 llvm::sys::path::parent_path(AbsPath)));
90 llvm::raw_fd_ostream OS(AbsPath, EC);
94 std::vector<std::string>
CommandLine = {
"clang",
"-std=c++20",
"-c"};
99 Directory, std::string(AbsPath), std::move(
CommandLine),
"");
100 Files.push_back(std::string(AbsPath));
103 std::optional<tooling::CompileCommand>
106 if (It == Commands.end())
108 tooling::CompileCommand Cmd = It->second;
109 if (llvm::any_of(Cmd.CommandLine, [](llvm::StringRef Arg) {
110 return Arg.starts_with(
"@");
112 auto FS = llvm::vfs::getRealFileSystem();
113 auto Tokenizer = llvm::Triple(llvm::sys::getProcessTriple()).isOSWindows()
114 ? llvm::cl::TokenizeWindowsCommandLine
115 : llvm::cl::TokenizeGNUCommandLine;
116 tooling::addExpandedResponseFiles(Cmd.CommandLine, Cmd.Directory,
122 std::optional<ProjectInfo> getProjectInfo(
PathRef)
const override {
123 return ProjectInfo{std::string(Directory)};
131 class IndexedCompilationDatabase :
public tooling::CompilationDatabase {
133 IndexedCompilationDatabase(
const PerFileModulesCompilationDatabase &CDB)
136 std::vector<tooling::CompileCommand>
137 getCompileCommands(StringRef FilePath)
const override {
138 if (
auto Cmd = CDB.getCompileCommand(FilePath))
143 std::vector<std::string> getAllFiles()
const override {
return CDB.Files; }
146 const PerFileModulesCompilationDatabase &CDB;
149 std::string Directory;
150 const ThreadsafeFS &TFS;
151 llvm::StringMap<tooling::CompileCommand> Commands;
152 std::vector<std::string> Files;
153 std::shared_ptr<IndexedCompilationDatabase> ToolingCDB;
156class ModuleUnitRootCompilationDatabase
157 :
public PerFileModulesCompilationDatabase {
159 ModuleUnitRootCompilationDatabase(StringRef TestDir,
const ThreadsafeFS &TFS)
160 : PerFileModulesCompilationDatabase(TestDir, TFS) {}
162 std::optional<ProjectInfo> getProjectInfo(
PathRef File)
const override {
165 llvm::SmallString<256> Root(
File);
166 llvm::sys::path::remove_filename(Root);
167 return ProjectInfo{std::string(Root)};
173 MockDirectoryCompilationDatabase(StringRef TestDir,
const ThreadsafeFS &TFS)
174 : MockCompilationDatabase(TestDir),
175 MockedCDBPtr(std::make_shared<MockClangCompilationDatabase>(*this)),
176 TFS(TFS), GlobalScanningCount(0) {
177 this->ExtraClangFlags.push_back(
"-std=c++20");
178 this->ExtraClangFlags.push_back(
"-c");
181 void addFile(llvm::StringRef
Path, llvm::StringRef Contents);
184 return std::make_unique<GlobalScanningCounterProjectModules>(
186 GlobalScanningCount);
189 unsigned getGlobalScanningCount()
const {
return GlobalScanningCount; }
192 class MockClangCompilationDatabase :
public tooling::CompilationDatabase {
194 MockClangCompilationDatabase(MockDirectoryCompilationDatabase &MCDB)
197 std::vector<tooling::CompileCommand>
198 getCompileCommands(StringRef FilePath)
const override {
199 std::optional<tooling::CompileCommand> Cmd =
200 MCDB.getCompileCommand(FilePath);
205 std::vector<std::string> getAllFiles()
const override {
return Files; }
207 void AddFile(StringRef
File) { Files.push_back(
File.str()); }
210 MockDirectoryCompilationDatabase &MCDB;
211 std::vector<std::string> Files;
214 std::shared_ptr<MockClangCompilationDatabase> MockedCDBPtr;
215 const ThreadsafeFS &TFS;
217 mutable std::atomic<unsigned> GlobalScanningCount;
221void MockDirectoryCompilationDatabase::addFile(llvm::StringRef
Path,
222 llvm::StringRef Contents) {
223 ASSERT_FALSE(llvm::sys::path::is_absolute(Path));
226 llvm::sys::path::append(AbsPath, Path);
229 llvm::sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath)));
232 llvm::raw_fd_ostream OS(AbsPath, EC);
236 MockedCDBPtr->AddFile(Path);
239class PrerequisiteModulesTests :
public ::testing::Test {
241 void SetUp()
override {
242 ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory(
"modules-test", TestDir));
245 void TearDown()
override {
246 ASSERT_FALSE(llvm::sys::fs::remove_directories(TestDir));
252 std::string getFullPath(llvm::StringRef Path) {
253 SmallString<128> Result(TestDir);
254 llvm::sys::path::append(Result, Path);
255 EXPECT_TRUE(llvm::sys::fs::exists(Result.str()));
256 return Result.str().str();
259 ParseInputs getInputs(llvm::StringRef FileName,
260 const GlobalCompilationDatabase &CDB) {
261 std::string FullPathName = getFullPath(FileName);
264 std::optional<tooling::CompileCommand> Cmd =
265 CDB.getCompileCommand(FullPathName);
267 Inputs.CompileCommand = std::move(*Cmd);
270 if (
auto Contents = FS.
view(TestDir)->getBufferForFile(FullPathName))
271 Inputs.Contents = Contents->get()->getBuffer().str();
276 SmallString<256> TestDir;
281 DiagnosticConsumer DiagConsumer;
284TEST_F(PrerequisiteModulesTests, NonModularTest) {
285 MockDirectoryCompilationDatabase CDB(TestDir, FS);
287 CDB.addFile(
"foo.h", R
"cpp(
291 CDB.addFile("NonModular.cpp", R
"cpp(
298 ModulesBuilder Builder(CDB);
301 auto NonModularInfo =
302 Builder.buildPrerequisiteModulesFor(getFullPath(
"NonModular.cpp"), FS);
303 EXPECT_TRUE(NonModularInfo);
305 HeaderSearchOptions HSOpts;
306 NonModularInfo->adjustHeaderSearchOptions(HSOpts);
307 EXPECT_TRUE(HSOpts.PrebuiltModuleFiles.empty());
311 EXPECT_TRUE(NonModularInfo->canReuse(*Invocation, FS.view(TestDir)));
314TEST_F(PrerequisiteModulesTests, ModuleWithoutDepTest) {
315 MockDirectoryCompilationDatabase CDB(TestDir, FS);
317 CDB.addFile(
"foo.h", R
"cpp(
321 CDB.addFile("M.cppm", R
"cpp(
327 ModulesBuilder Builder(CDB);
329 auto MInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"M.cppm"), FS);
333 HeaderSearchOptions HSOpts;
334 MInfo->adjustHeaderSearchOptions(HSOpts);
335 EXPECT_TRUE(HSOpts.PrebuiltModuleFiles.empty());
339 EXPECT_TRUE(MInfo->canReuse(*Invocation, FS.view(TestDir)));
342TEST_F(PrerequisiteModulesTests, ModuleWithArgumentPatch) {
343 MockDirectoryCompilationDatabase CDB(TestDir, FS);
345 CDB.ExtraClangFlags.push_back(
"-invalid-unknown-flag");
347 CDB.addFile(
"Dep.cppm", R
"cpp(
351 CDB.addFile("M.cppm", R
"cpp(
358 auto ProjectModules = CDB.getProjectModules(getFullPath(
"M.cppm"));
360 ProjectModules->getRequiredModules(getFullPath(
"M.cppm")).empty());
363 ProjectModules->setCommandMangler([](tooling::CompileCommand &Command,
365 auto const It = llvm::find(Command.CommandLine,
"-invalid-unknown-flag");
366 Command.CommandLine.erase(It);
372 ProjectModules->getRequiredModules(getFullPath(
"M.cppm")).empty());
375TEST_F(PrerequisiteModulesTests, ModuleWithDepTest) {
376 MockDirectoryCompilationDatabase CDB(TestDir, FS);
378 CDB.addFile(
"foo.h", R
"cpp(
382 CDB.addFile("M.cppm", R
"cpp(
388 CDB.addFile("N.cppm", R
"cpp(
394 CDB.addFile("N-part.cppm", R
"cpp(
395// Different module name with filename intentionally.
399 ModulesBuilder Builder(CDB);
401 auto NInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"N.cppm"), FS);
404 ParseInputs NInput = getInputs(
"N.cppm", CDB);
405 std::unique_ptr<CompilerInvocation> Invocation =
408 EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
414 HeaderSearchOptions HSOpts;
415 NInfo->adjustHeaderSearchOptions(HSOpts);
417 EXPECT_TRUE(HSOpts.PrebuiltModuleFiles.count(
"M"));
418 EXPECT_TRUE(HSOpts.PrebuiltModuleFiles.count(
"N:Part"));
425 HeaderSearchOptions HSOpts;
426 HSOpts.PrebuiltModuleFiles[
"M"] =
"incorrect_path";
427 HSOpts.PrebuiltModuleFiles[
"N:Part"] =
"incorrect_path";
428 NInfo->adjustHeaderSearchOptions(HSOpts);
430 EXPECT_TRUE(StringRef(HSOpts.PrebuiltModuleFiles[
"M"]).ends_with(
".pcm"));
432 StringRef(HSOpts.PrebuiltModuleFiles[
"N:Part"]).ends_with(
".pcm"));
436TEST_F(PrerequisiteModulesTests, ReusabilityTest) {
437 MockDirectoryCompilationDatabase CDB(TestDir, FS);
439 CDB.addFile(
"foo.h", R
"cpp(
443 CDB.addFile("M.cppm", R
"cpp(
449 CDB.addFile("N.cppm", R
"cpp(
455 CDB.addFile("N-part.cppm", R
"cpp(
456// Different module name with filename intentionally.
460 ModulesBuilder Builder(CDB);
462 auto NInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"N.cppm"), FS);
466 ParseInputs NInput = getInputs(
"N.cppm", CDB);
467 std::unique_ptr<CompilerInvocation> Invocation =
469 EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
473 CDB.addFile(
"L.cppm", R
"cpp(
479 EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
481 CDB.addFile("bar.h", R
"cpp(
483inline void bar(int) {}
485 EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
490 CDB.addFile(
"M.cppm", R
"cpp(
496 EXPECT_FALSE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
498 NInfo = Builder.buildPrerequisiteModulesFor(getFullPath("N.cppm"), FS);
499 EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
501 CDB.addFile(
"foo.h", R
"cpp(
503inline void foo(int) {}
505 EXPECT_FALSE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
507 NInfo = Builder.buildPrerequisiteModulesFor(getFullPath("N.cppm"), FS);
508 EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
511 CDB.addFile(
"N-part.cppm", R
"cpp(
513// Intentioned to make it uncompilable.
514export int NPart = 4LIdjwldijaw
516 EXPECT_FALSE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
517 NInfo = Builder.buildPrerequisiteModulesFor(getFullPath("N.cppm"), FS);
519 EXPECT_FALSE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
521 CDB.addFile(
"N-part.cppm", R
"cpp(
523export int NPart = 43;
526 EXPECT_FALSE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
527 NInfo = Builder.buildPrerequisiteModulesFor(getFullPath("N.cppm"), FS);
529 EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
533 CDB.addFile(
"N-part.cppm", R
"cpp(
535export int NPart = 43;
537 EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
539 CDB.addFile("N.cppm", R
"cpp(
547 EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
550TEST_F(PrerequisiteModulesTests, CanReuseWithTransitiveNamedModuleImports) {
551 MockDirectoryCompilationDatabase CDB(TestDir, FS);
553 CDB.addFile(
"N.cppm", R
"cpp(
555export inline constexpr int n = 1;
558 CDB.addFile("M.cppm", R
"cpp(
561export inline constexpr int m = n + 1;
564 CDB.addFile("A.cppm", R
"cpp(
567export inline constexpr int a = m + 1;
570 CDB.addFile("Use.cpp", R
"cpp(
572int use() { return a; }
575 ModulesBuilder Builder(CDB);
577 auto UseInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"Use.cpp"), FS);
578 ASSERT_TRUE(UseInfo);
580 HeaderSearchOptions HSOpts;
581 UseInfo->adjustHeaderSearchOptions(HSOpts);
582 EXPECT_TRUE(HSOpts.PrebuiltModuleFiles.count(
"A"));
583 EXPECT_TRUE(HSOpts.PrebuiltModuleFiles.count(
"M"));
584 EXPECT_TRUE(HSOpts.PrebuiltModuleFiles.count(
"N"));
588 ASSERT_TRUE(Invocation);
590 EXPECT_TRUE(UseInfo->canReuse(*Invocation, FS.view(TestDir)));
594TEST_F(PrerequisiteModulesTests, ParsedASTTest) {
595 MockDirectoryCompilationDatabase CDB(TestDir, FS);
597 CDB.addFile(
"A.cppm", R
"cpp(
602 CDB.addFile("Use.cpp", R
"cpp(
606 ModulesBuilder Builder(CDB);
608 ParseInputs Use = getInputs("Use.cpp", CDB);
609 Use.ModulesManager = &Builder;
611 std::unique_ptr<CompilerInvocation> CI =
619 EXPECT_TRUE(
Preamble->RequiredModules);
626 EXPECT_TRUE(
D.isFromASTFile());
630TEST_F(PrerequisiteModulesTests, CodeCompleteTest) {
631 MockDirectoryCompilationDatabase CDB(TestDir, FS);
633 CDB.addFile(
"A.cppm", R
"cpp(
638 llvm::StringLiteral UserContents = R"cpp(
645 CDB.addFile("Use.cpp", UserContents);
646 Annotations Test(UserContents);
648 ModulesBuilder Builder(CDB);
650 ParseInputs Use = getInputs(
"Use.cpp", CDB);
651 Use.ModulesManager = &Builder;
653 std::unique_ptr<CompilerInvocation> CI =
661 EXPECT_TRUE(
Preamble->RequiredModules);
663 auto Result =
codeComplete(getFullPath(
"Use.cpp"), Test.point(),
665 EXPECT_FALSE(Result.Completions.empty());
666 EXPECT_EQ(Result.Completions[0].Name,
"printA");
669TEST_F(PrerequisiteModulesTests, SignatureHelpTest) {
670 MockDirectoryCompilationDatabase CDB(TestDir, FS);
672 CDB.addFile(
"A.cppm", R
"cpp(
674export void printA(int a);
677 llvm::StringLiteral UserContents = R"cpp(
684 CDB.addFile("Use.cpp", UserContents);
685 Annotations Test(UserContents);
687 ModulesBuilder Builder(CDB);
689 ParseInputs Use = getInputs(
"Use.cpp", CDB);
690 Use.ModulesManager = &Builder;
692 std::unique_ptr<CompilerInvocation> CI =
700 EXPECT_TRUE(
Preamble->RequiredModules);
704 EXPECT_FALSE(Result.signatures.empty());
705 EXPECT_EQ(Result.signatures[0].label,
"printA(int a) -> void");
706 EXPECT_EQ(Result.signatures[0].parameters[0].labelString,
"int a");
709TEST_F(PrerequisiteModulesTests, ReusablePrerequisiteModulesTest) {
710 MockDirectoryCompilationDatabase CDB(TestDir, FS);
712 CDB.addFile(
"M.cppm", R
"cpp(
716 CDB.addFile("A.cppm", R
"cpp(
719export int A = 43 + M;
721 CDB.addFile("B.cppm", R
"cpp(
724export int B = 44 + M;
727 ModulesBuilder Builder(CDB);
729 auto AInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
731 auto BInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"B.cppm"), FS);
733 HeaderSearchOptions HSOptsA(TestDir);
734 HeaderSearchOptions HSOptsB(TestDir);
735 AInfo->adjustHeaderSearchOptions(HSOptsA);
736 BInfo->adjustHeaderSearchOptions(HSOptsB);
738 EXPECT_FALSE(HSOptsA.PrebuiltModuleFiles.empty());
739 EXPECT_FALSE(HSOptsB.PrebuiltModuleFiles.empty());
742 EXPECT_EQ(HSOptsA.PrebuiltModuleFiles, HSOptsB.PrebuiltModuleFiles);
745 CDB.addFile(
"M.cppm", R
"cpp(
747export constexpr int M = 43;
750 ParseInputs AUse = getInputs("A.cppm", CDB);
751 AUse.ModulesManager = &Builder;
752 std::unique_ptr<CompilerInvocation> AInvocation =
754 EXPECT_FALSE(AInfo->canReuse(*AInvocation, FS.view(TestDir)));
756 ParseInputs BUse = getInputs(
"B.cppm", CDB);
757 AUse.ModulesManager = &Builder;
758 std::unique_ptr<CompilerInvocation> BInvocation =
760 EXPECT_FALSE(BInfo->canReuse(*BInvocation, FS.view(TestDir)));
763 Builder.buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
765 Builder.buildPrerequisiteModulesFor(getFullPath(
"B.cppm"), FS);
766 EXPECT_TRUE(NewAInfo);
767 EXPECT_TRUE(NewBInfo);
768 HeaderSearchOptions NewHSOptsA(TestDir);
769 HeaderSearchOptions NewHSOptsB(TestDir);
770 NewAInfo->adjustHeaderSearchOptions(NewHSOptsA);
771 NewBInfo->adjustHeaderSearchOptions(NewHSOptsB);
773 EXPECT_FALSE(NewHSOptsA.PrebuiltModuleFiles.empty());
774 EXPECT_FALSE(NewHSOptsB.PrebuiltModuleFiles.empty());
776 EXPECT_EQ(NewHSOptsA.PrebuiltModuleFiles, NewHSOptsB.PrebuiltModuleFiles);
779 EXPECT_TRUE(NewAInfo->canReuse(*AInvocation, FS.view(TestDir)));
780 EXPECT_TRUE(NewBInfo->canReuse(*BInvocation, FS.view(TestDir)));
783TEST_F(PrerequisiteModulesTests, ScanningCacheTest) {
784 MockDirectoryCompilationDatabase CDB(TestDir, FS);
786 CDB.addFile(
"M.cppm", R
"cpp(
789 CDB.addFile("A.cppm", R
"cpp(
793 CDB.addFile("B.cppm", R
"cpp(
798 ModulesBuilder Builder(CDB);
800 Builder.buildPrerequisiteModulesFor(getFullPath("A.cppm"), FS);
801 Builder.buildPrerequisiteModulesFor(getFullPath(
"B.cppm"), FS);
802 EXPECT_EQ(CDB.getGlobalScanningCount(), 1u);
808TEST_F(PrerequisiteModulesTests, CanReuseWithHeadersInModuleUnit) {
809 MockDirectoryCompilationDatabase CDB(TestDir, FS);
812 CDB.addFile(
"header1.h", R
"cpp(
813inline int getValue() { return 42; }
817 CDB.addFile(
"M.cppm", R
"cpp(
821export int m_value = getValue();
825 CDB.addFile(
"N.cppm", R
"cpp(
832 CDB.addFile(
"N-part.cppm", R
"cpp(
836 ModulesBuilder Builder(CDB);
839 auto NInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"N.cppm"), FS);
842 ParseInputs NInput = getInputs(
"N.cppm", CDB);
843 std::unique_ptr<CompilerInvocation> Invocation =
847 EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
851 CDB.addFile(
"header1.h", R
"cpp(
852inline int getValue() { return 43; }
854 EXPECT_FALSE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
857 NInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"N.cppm"), FS);
859 EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
862 CDB.addFile(
"M.cppm", R
"cpp(
866export int m_value = getValue();
867export int m_new_value = 10;
869 EXPECT_FALSE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
872 NInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"N.cppm"), FS);
874 EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));
877TEST_F(PrerequisiteModulesTests, PrebuiltModuleFileTest) {
878 MockDirectoryCompilationDatabase CDB(TestDir, FS);
880 CDB.addFile(
"M.cppm", R
"cpp(
884 CDB.addFile("U.cpp", R
"cpp(
889 ModulesBuilder Builder(CDB);
891 Builder.buildPrerequisiteModulesFor(getFullPath(
"U.cpp"), FS);
892 HeaderSearchOptions HS(TestDir);
893 ModuleInfo->adjustHeaderSearchOptions(HS);
895 CDB.ExtraClangFlags.push_back(
"-fmodule-file=M=" +
896 HS.PrebuiltModuleFiles[
"M"]);
897 ModulesBuilder Builder2(CDB);
899 Builder2.buildPrerequisiteModulesFor(getFullPath(
"U.cpp"), FS);
900 HeaderSearchOptions HS2(TestDir);
901 ModuleInfo2->adjustHeaderSearchOptions(HS2);
903 EXPECT_EQ(HS.PrebuiltModuleFiles, HS2.PrebuiltModuleFiles);
910TEST_F(PrerequisiteModulesTests, PrebuiltModuleFileWithRelativePath) {
911 MockDirectoryCompilationDatabase CDB(TestDir, FS);
913 CDB.addFile(
"M.cppm", R
"cpp(
915export int m_value = 42;
918 CDB.addFile("U.cpp", R
"cpp(
920int use() { return m_value; }
924 ModulesBuilder Builder(CDB);
926 Builder.buildPrerequisiteModulesFor(getFullPath(
"U.cpp"), FS);
927 ASSERT_TRUE(ModuleInfo);
929 HeaderSearchOptions HS(TestDir);
930 ModuleInfo->adjustHeaderSearchOptions(HS);
931 ASSERT_EQ(HS.PrebuiltModuleFiles.count(
"M"), 1u);
934 std::string OriginalBMPath = HS.PrebuiltModuleFiles[
"M"];
935 ASSERT_TRUE(llvm::sys::path::is_absolute(OriginalBMPath));
936 ASSERT_TRUE(llvm::sys::fs::exists(OriginalBMPath));
939 SmallString<256> BMSubDir(TestDir);
940 llvm::sys::path::append(BMSubDir,
"prebuilt_modules");
941 ASSERT_FALSE(llvm::sys::fs::create_directories(BMSubDir));
943 SmallString<256> NewBMPath(BMSubDir);
944 llvm::sys::path::append(NewBMPath,
"M.pcm");
947 ASSERT_FALSE(llvm::sys::fs::copy_file(OriginalBMPath, NewBMPath));
948 ASSERT_TRUE(llvm::sys::fs::exists(NewBMPath));
951 std::string RelativeBMPath =
952 llvm::StringRef(NewBMPath).drop_front(TestDir.size() + 1).str();
953 ASSERT_FALSE(RelativeBMPath.empty());
954 ASSERT_TRUE(llvm::sys::path::is_relative(RelativeBMPath));
957 MockDirectoryCompilationDatabase CDBWithRelativePath(TestDir, FS);
959 CDBWithRelativePath.addFile(
"M.cppm", R
"cpp(
961export int m_value = 42;
964 CDBWithRelativePath.addFile("U.cpp", R
"cpp(
966int use() { return m_value; }
970 CDBWithRelativePath.ExtraClangFlags.push_back(
"-fmodule-file=M=" +
974 ModulesBuilder BuilderWithRelativePath(CDBWithRelativePath);
975 auto ModuleInfo2 = BuilderWithRelativePath.buildPrerequisiteModulesFor(
976 getFullPath(
"U.cpp"), FS);
977 ASSERT_TRUE(ModuleInfo2);
979 HeaderSearchOptions HS2(TestDir);
980 ModuleInfo2->adjustHeaderSearchOptions(HS2);
983 ASSERT_EQ(HS2.PrebuiltModuleFiles.count(
"M"), 1u);
984 EXPECT_EQ(HS2.PrebuiltModuleFiles[
"M"], std::string(NewBMPath))
985 <<
"Expected absolute path: " << NewBMPath
986 <<
"\nGot: " << HS2.PrebuiltModuleFiles[
"M"]
987 <<
"\nRelative path used: " << RelativeBMPath;
990TEST_F(PrerequisiteModulesTests,
991 UniqueModuleNameStateResolvedFromCompileCommands) {
992 PerFileModulesCompilationDatabase CDB(TestDir, FS);
994 SmallString<256> MPcm(TestDir);
995 llvm::sys::path::append(MPcm,
"build",
"M.pcm");
997 CDB.addFile(
"M.cppm", R
"cpp(
1001 {"--precompile",
"-o", std::string(MPcm)});
1002 CDB.addFile(
"A.cpp", R
"cpp(
1004int useA() { return value; }
1006 {"-fmodule-file=M=" + std::string(MPcm)});
1007 CDB.addFile(
"B.cpp", R
"cpp(
1009int useB() { return value; }
1011 {"-fmodule-file=M=" + std::string(MPcm)});
1013 auto ProjectModules = CDB.getProjectModules(getFullPath(
"A.cpp"));
1014 ASSERT_TRUE(ProjectModules);
1016 EXPECT_EQ(ProjectModules->getModuleNameState(
"M"),
1020TEST_F(PrerequisiteModulesTests,
1021 DuplicateModuleNamesResolvedFromCompileCommands) {
1022 PerFileModulesCompilationDatabase CDB(TestDir, FS);
1024 SmallString<256> APcm(TestDir);
1025 llvm::sys::path::append(APcm,
"build",
"a",
"M.pcm");
1026 SmallString<256> BPcm(TestDir);
1027 llvm::sys::path::append(BPcm,
"build",
"b",
"M.pcm");
1029 CDB.addFile(
"a/M.cppm", R
"cpp(
1031export int onlyA = 1;
1033 {"--precompile",
"-o", std::string(APcm)});
1034 CDB.addFile(
"b/M.cppm", R
"cpp(
1036export int onlyB = 2;
1038 {"--precompile",
"-o", std::string(BPcm)});
1039 CDB.addFile(
"a/Use.cpp", R
"cpp(
1041int useA() { return onlyA; }
1043 {"-fmodule-file=M=" + std::string(APcm)});
1044 CDB.addFile(
"b/Use.cpp", R
"cpp(
1046int useB() { return onlyB; }
1048 {"-fmodule-file=M=" + std::string(BPcm)});
1050 auto ProjectModules = CDB.getProjectModules(getFullPath(
"a/Use.cpp"));
1051 ASSERT_TRUE(ProjectModules);
1052 EXPECT_EQ(ProjectModules->getModuleNameState(
"M"),
1056 ProjectModules->getSourceForModuleName(
"M", getFullPath(
"a/Use.cpp")),
1057 getFullPath(
"a/M.cppm"));
1059 ProjectModules->getSourceForModuleName(
"M", getFullPath(
"b/Use.cpp")),
1060 getFullPath(
"b/M.cppm"));
1063TEST_F(PrerequisiteModulesTests,
1064 DuplicateModuleNamesResolvedFromResponseFiles) {
1065 PerFileModulesCompilationDatabase CDB(TestDir, FS);
1067 SmallString<256> APcm(TestDir);
1068 llvm::sys::path::append(APcm,
"build",
"a",
"M.pcm");
1069 SmallString<256> BPcm(TestDir);
1070 llvm::sys::path::append(BPcm,
"build",
"b",
"M.pcm");
1072 SmallString<256> RspDir(TestDir);
1073 llvm::sys::path::append(RspDir,
"build",
"rsp");
1074 ASSERT_FALSE(llvm::sys::fs::create_directories(RspDir));
1076 SmallString<256> AMRsp(RspDir);
1077 llvm::sys::path::append(AMRsp,
"a-m.rsp");
1080 llvm::raw_fd_ostream OS(AMRsp, EC);
1082 OS <<
"-x c++-module -fmodule-output=" << APcm;
1086 SmallString<256> BMRsp(RspDir);
1087 llvm::sys::path::append(BMRsp,
"b-m.rsp");
1090 llvm::raw_fd_ostream OS(BMRsp, EC);
1092 OS <<
"-x c++-module -fmodule-output=" << BPcm;
1096 SmallString<256> AUseRsp(RspDir);
1097 llvm::sys::path::append(AUseRsp,
"a-use.rsp");
1100 llvm::raw_fd_ostream OS(AUseRsp, EC);
1102 OS <<
"-fmodule-file=M=" << APcm;
1106 SmallString<256> BUseRsp(RspDir);
1107 llvm::sys::path::append(BUseRsp,
"b-use.rsp");
1110 llvm::raw_fd_ostream OS(BUseRsp, EC);
1112 OS <<
"-fmodule-file=M=" << BPcm;
1116 CDB.addFile(
"a/M.cppm", R
"cpp(
1118export int onlyA = 1;
1120 {"@" + std::string(AMRsp)});
1121 CDB.addFile(
"b/M.cppm", R
"cpp(
1123export int onlyB = 2;
1125 {"@" + std::string(BMRsp)});
1126 CDB.addFile(
"a/Use.cpp", R
"cpp(
1128int useA() { return onlyA; }
1130 {"@" + std::string(AUseRsp)});
1131 CDB.addFile(
"b/Use.cpp", R
"cpp(
1133int useB() { return onlyB; }
1135 {"@" + std::string(BUseRsp)});
1137 auto ProjectModules = CDB.getProjectModules(getFullPath(
"a/Use.cpp"));
1138 ASSERT_TRUE(ProjectModules);
1139 EXPECT_EQ(ProjectModules->getModuleNameState(
"M"),
1143 ProjectModules->getSourceForModuleName(
"M", getFullPath(
"a/Use.cpp")),
1144 getFullPath(
"a/M.cppm"));
1146 ProjectModules->getSourceForModuleName(
"M", getFullPath(
"b/Use.cpp")),
1147 getFullPath(
"b/M.cppm"));
1150TEST_F(PrerequisiteModulesTests, DuplicateModuleNamesKeepSeparateBMICache) {
1151 PerFileModulesCompilationDatabase CDB(TestDir, FS);
1153 SmallString<256> APcm(TestDir);
1154 llvm::sys::path::append(APcm,
"build",
"a",
"M.pcm");
1155 SmallString<256> BPcm(TestDir);
1156 llvm::sys::path::append(BPcm,
"build",
"b",
"M.pcm");
1158 CDB.addFile(
"a/M.cppm", R
"cpp(
1160export int onlyA = 1;
1162 {"--precompile",
"-o", std::string(APcm)});
1163 CDB.addFile(
"b/M.cppm", R
"cpp(
1165export int onlyB = 2;
1167 {"--precompile",
"-o", std::string(BPcm)});
1168 CDB.addFile(
"a/Use.cpp", R
"cpp(
1170int useA() { return onlyA; }
1172 {"-fmodule-file=M=" + std::string(APcm)});
1173 CDB.addFile(
"b/Use.cpp", R
"cpp(
1175int useB() { return onlyB; }
1177 {"-fmodule-file=M=" + std::string(BPcm)});
1179 ModulesBuilder Builder(CDB);
1182 Builder.buildPrerequisiteModulesFor(getFullPath(
"a/Use.cpp"), FS);
1184 Builder.buildPrerequisiteModulesFor(getFullPath(
"b/Use.cpp"), FS);
1188 HeaderSearchOptions HSA(TestDir);
1189 HeaderSearchOptions HSB(TestDir);
1190 AInfo->adjustHeaderSearchOptions(HSA);
1191 BInfo->adjustHeaderSearchOptions(HSB);
1192 ASSERT_EQ(HSA.PrebuiltModuleFiles.count(
"M"), 1u);
1193 ASSERT_EQ(HSB.PrebuiltModuleFiles.count(
"M"), 1u);
1194 EXPECT_NE(HSA.PrebuiltModuleFiles[
"M"], HSB.PrebuiltModuleFiles[
"M"]);
1196 auto UseA = getInputs(
"a/Use.cpp", CDB);
1197 UseA.ModulesManager = &Builder;
1200 auto PreambleA =
buildPreamble(getFullPath(
"a/Use.cpp"), *CIA, UseA,
1202 ASSERT_TRUE(PreambleA);
1203 auto ASTA =
ParsedAST::build(getFullPath(
"a/Use.cpp"), UseA, std::move(CIA),
1206 EXPECT_TRUE(
findDecl(*ASTA,
"onlyA").isFromASTFile());
1208 auto UseB = getInputs(
"b/Use.cpp", CDB);
1209 UseB.ModulesManager = &Builder;
1212 auto PreambleB =
buildPreamble(getFullPath(
"b/Use.cpp"), *CIB, UseB,
1214 ASSERT_TRUE(PreambleB);
1215 auto ASTB =
ParsedAST::build(getFullPath(
"b/Use.cpp"), UseB, std::move(CIB),
1218 EXPECT_TRUE(
findDecl(*ASTB,
"onlyB").isFromASTFile());
1221TEST_F(PrerequisiteModulesTests, PersistentModuleCacheReusedAcrossBuilders) {
1222 MockDirectoryCompilationDatabase CDB(TestDir, FS);
1224 CDB.addFile(
"M.cppm", R
"cpp(
1226export int MValue = 43;
1228 CDB.addFile("A.cppm", R
"cpp(
1231export int AValue = MValue;
1234 std::string FirstPCMPath;
1236 ModulesBuilder Builder(CDB);
1237 auto AInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
1239 HeaderSearchOptions HS(TestDir);
1240 AInfo->adjustHeaderSearchOptions(HS);
1241 ASSERT_EQ(HS.PrebuiltModuleFiles.count(
"M"), 1u);
1242 FirstPCMPath = HS.PrebuiltModuleFiles[
"M"];
1243 EXPECT_TRUE(llvm::sys::fs::exists(FirstPCMPath));
1244 EXPECT_TRUE(StringRef(FirstPCMPath).contains(
".cache/clangd/modules"));
1247 EXPECT_FALSE(llvm::sys::fs::exists(FirstPCMPath));
1251 ModulesBuilder Builder(CDB);
1252 auto AInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
1254 HeaderSearchOptions HS(TestDir);
1255 AInfo->adjustHeaderSearchOptions(HS);
1256 ASSERT_EQ(HS.PrebuiltModuleFiles.count(
"M"), 1u);
1257 EXPECT_TRUE(llvm::sys::fs::exists(HS.PrebuiltModuleFiles[
"M"]));
1258 EXPECT_TRUE(StringRef(HS.PrebuiltModuleFiles[
"M"]).contains(
"M-"));
1260 ParseInputs AUse = getInputs(
"A.cppm", CDB);
1261 AUse.ModulesManager = &Builder;
1263 ASSERT_TRUE(Invocation);
1264 EXPECT_TRUE(AInfo->canReuse(*Invocation, FS.view(TestDir)));
1267TEST_F(PrerequisiteModulesTests,
1268 PersistentModuleCacheRebuildsAfterDeletingStalePCM) {
1269 MockDirectoryCompilationDatabase CDB(TestDir, FS);
1271 CDB.addFile(
"M.cppm", R
"cpp(
1273export int MValue = 43;
1275 CDB.addFile("A.cppm", R
"cpp(
1278export int AValue = MValue;
1281 ModulesBuilder Builder(CDB);
1282 auto AInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
1284 HeaderSearchOptions HS(TestDir);
1285 AInfo->adjustHeaderSearchOptions(HS);
1286 ASSERT_EQ(HS.PrebuiltModuleFiles.count(
"M"), 1u);
1287 std::string PCMPath = HS.PrebuiltModuleFiles[
"M"];
1290 llvm::raw_fd_ostream OS(PCMPath, EC);
1297 Builder.buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
1298 ASSERT_TRUE(NewAInfo);
1299 HeaderSearchOptions NewHS(TestDir);
1300 NewAInfo->adjustHeaderSearchOptions(NewHS);
1301 ASSERT_EQ(NewHS.PrebuiltModuleFiles.count(
"M"), 1u);
1302 EXPECT_TRUE(llvm::sys::fs::exists(NewHS.PrebuiltModuleFiles[
"M"]));
1303 EXPECT_TRUE(StringRef(NewHS.PrebuiltModuleFiles[
"M"]).contains(
"M-"));
1305 ParseInputs AUse = getInputs(
"A.cppm", CDB);
1306 AUse.ModulesManager = &Builder;
1308 ASSERT_TRUE(Invocation);
1309 EXPECT_TRUE(NewAInfo->canReuse(*Invocation, FS.view(TestDir)));
1312TEST_F(PrerequisiteModulesTests, PersistentModuleCacheCreatesSourceHashLock) {
1313 MockDirectoryCompilationDatabase CDB(TestDir, FS);
1315 CDB.addFile(
"M.cppm", R
"cpp(
1317export int MValue = 43;
1319 CDB.addFile("A.cppm", R
"cpp(
1322export int AValue = MValue;
1325 ModulesBuilder Builder(CDB);
1326 auto AInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
1329 HeaderSearchOptions HS(TestDir);
1330 AInfo->adjustHeaderSearchOptions(HS);
1331 ASSERT_EQ(HS.PrebuiltModuleFiles.count(
"M"), 1u);
1333 llvm::SmallString<256> PCMPath(HS.PrebuiltModuleFiles[
"M"]);
1334 llvm::sys::path::remove_filename(PCMPath);
1335 llvm::SmallString<256> SourceHashDir(PCMPath);
1336 llvm::sys::path::remove_filename(SourceHashDir);
1337 llvm::SmallString<256> CacheRoot(SourceHashDir);
1338 llvm::sys::path::remove_filename(CacheRoot);
1342 llvm::StringRef SourceDirectoryName =
1343 llvm::sys::path::filename(SourceHashDir);
1345 llvm::StringRef SourceHash = SourceDirectoryName.rsplit(
'-').second;
1346 llvm::SmallString<256> LockPath(CacheRoot);
1347 llvm::sys::path::append(LockPath,
".locks", SourceHash);
1349 EXPECT_TRUE(llvm::sys::fs::exists(LockPath));
1352TEST_F(PrerequisiteModulesTests,
1353 PersistentModuleCacheGCRemovesOldStablePublishedModule) {
1354 PerFileModulesCompilationDatabase CDB(TestDir, FS);
1356 CDB.addFile(
"M.cppm", R
"cpp(
1358export int MValue = 43;
1360 CDB.addFile("A.cppm", R
"cpp(
1363export int AValue = MValue;
1366 llvm::SmallString<256> OrphanPCMPath;
1368 ModulesBuilder Builder(CDB);
1369 auto AInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
1371 HeaderSearchOptions HS(TestDir);
1372 AInfo->adjustHeaderSearchOptions(HS);
1373 ASSERT_EQ(HS.PrebuiltModuleFiles.count(
"M"), 1u);
1375 OrphanPCMPath = HS.PrebuiltModuleFiles[
"M"];
1376 llvm::sys::path::remove_filename(OrphanPCMPath);
1377 llvm::sys::path::append(OrphanPCMPath,
"Orphan.pcm");
1380 llvm::raw_fd_ostream OS(OrphanPCMPath, EC);
1384 EXPECT_TRUE(llvm::sys::fs::exists(OrphanPCMPath));
1387 ASSERT_FALSE(llvm::sys::fs::openFileForWrite(OrphanPCMPath, FD,
1388 llvm::sys::fs::CD_OpenExisting,
1389 llvm::sys::fs::OF_None));
1390 auto CloseFD = llvm::scope_exit(
1391 [&] { llvm::sys::Process::SafelyCloseFileDescriptor(FD); });
1392 llvm::sys::TimePoint<> OldTime =
1393 std::chrono::system_clock::now() - std::chrono::hours(24 * 5);
1394 ASSERT_FALSE(llvm::sys::fs::setLastAccessAndModificationTime(FD, OldTime));
1397 ModulesBuilder Builder(CDB);
1398 auto AInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
1400 EXPECT_FALSE(llvm::sys::fs::exists(OrphanPCMPath));
1403TEST_F(PrerequisiteModulesTests,
1404 PersistentModuleCacheGCKeepsRecentStablePublishedModule) {
1405 PerFileModulesCompilationDatabase CDB(TestDir, FS);
1407 CDB.addFile(
"M.cppm", R
"cpp(
1409export int MValue = 43;
1411 CDB.addFile("A.cppm", R
"cpp(
1414export int AValue = MValue;
1417 llvm::SmallString<256> OrphanPCMPath;
1419 ModulesBuilder Builder(CDB);
1420 auto AInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
1422 HeaderSearchOptions HS(TestDir);
1423 AInfo->adjustHeaderSearchOptions(HS);
1424 ASSERT_EQ(HS.PrebuiltModuleFiles.count(
"M"), 1u);
1426 OrphanPCMPath = HS.PrebuiltModuleFiles[
"M"];
1427 llvm::sys::path::remove_filename(OrphanPCMPath);
1428 llvm::sys::path::append(OrphanPCMPath,
"Orphan.pcm");
1431 llvm::raw_fd_ostream OS(OrphanPCMPath, EC);
1435 EXPECT_TRUE(llvm::sys::fs::exists(OrphanPCMPath));
1438 ModulesBuilder Builder(CDB);
1439 auto AInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
1441 EXPECT_TRUE(llvm::sys::fs::exists(OrphanPCMPath));
1444TEST_F(PrerequisiteModulesTests,
1445 PersistentModuleCacheGCRemovesOldVersionedModuleFile) {
1446 PerFileModulesCompilationDatabase CDB(TestDir, FS);
1448 CDB.addFile(
"M.cppm", R
"cpp(
1450export int MValue = 43;
1452 CDB.addFile("A.cppm", R
"cpp(
1455export int AValue = MValue;
1458 llvm::SmallString<256> OldVersionedPCMPath;
1460 ModulesBuilder Builder(CDB);
1461 auto AInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
1463 HeaderSearchOptions HS(TestDir);
1464 AInfo->adjustHeaderSearchOptions(HS);
1465 ASSERT_EQ(HS.PrebuiltModuleFiles.count(
"M"), 1u);
1467 OldVersionedPCMPath = HS.PrebuiltModuleFiles[
"M"];
1468 ASSERT_TRUE(llvm::sys::fs::exists(OldVersionedPCMPath));
1471 ASSERT_FALSE(llvm::sys::fs::openFileForWrite(OldVersionedPCMPath, FD,
1472 llvm::sys::fs::CD_OpenExisting,
1473 llvm::sys::fs::OF_None));
1474 auto CloseFD = llvm::scope_exit(
1475 [&] { llvm::sys::Process::SafelyCloseFileDescriptor(FD); });
1476 llvm::sys::TimePoint<> OldTime =
1477 std::chrono::system_clock::now() - std::chrono::hours(24 * 5);
1478 ASSERT_FALSE(llvm::sys::fs::setLastAccessAndModificationTime(FD, OldTime));
1481 ModulesBuilder Builder(CDB);
1482 auto AInfo = Builder.buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
1484 EXPECT_FALSE(llvm::sys::fs::exists(OldVersionedPCMPath));
1487TEST_F(PrerequisiteModulesTests,
1488 PersistentModuleCacheGCKeepsRecentVersionedModuleFile) {
1489 PerFileModulesCompilationDatabase CDB(TestDir, FS);
1491 CDB.addFile(
"M.cppm", R
"cpp(
1493export int MValue = 43;
1495 CDB.addFile("A.cppm", R
"cpp(
1498export int AValue = MValue;
1501 auto FirstBuilder = std::make_unique<ModulesBuilder>(CDB);
1503 FirstBuilder->buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
1505 HeaderSearchOptions HS(TestDir);
1506 AInfo->adjustHeaderSearchOptions(HS);
1507 ASSERT_EQ(HS.PrebuiltModuleFiles.count(
"M"), 1u);
1508 llvm::StringRef CopyOnReadPCMPath = HS.PrebuiltModuleFiles[
"M"];
1509 ASSERT_TRUE(llvm::sys::fs::exists(CopyOnReadPCMPath));
1511 ModulesBuilder SecondBuilder(CDB);
1513 SecondBuilder.buildPrerequisiteModulesFor(getFullPath(
"A.cppm"), FS);
1514 ASSERT_TRUE(SecondInfo);
1515 EXPECT_TRUE(llvm::sys::fs::exists(CopyOnReadPCMPath));
1518TEST_F(PrerequisiteModulesTests,
1519 PersistentModuleCacheIgnoresRequiredSourceForOnDiskPath) {
1520 ModuleUnitRootCompilationDatabase CDB(TestDir, FS);
1522 CDB.addFile(
"shared/M.cppm", R
"cpp(
1524export int MValue = 43;
1526 CDB.addFile("projA/A.cppm", R
"cpp(
1529export int AValue = MValue;
1531 CDB.addFile("projB/B.cppm", R
"cpp(
1534export int BValue = MValue;
1537 ModulesBuilder Builder(CDB);
1540 Builder.buildPrerequisiteModulesFor(getFullPath(
"projA/A.cppm"), FS);
1542 Builder.buildPrerequisiteModulesFor(getFullPath(
"projB/B.cppm"), FS);
1546 HeaderSearchOptions HSA(TestDir);
1547 HeaderSearchOptions HSB(TestDir);
1548 AInfo->adjustHeaderSearchOptions(HSA);
1549 BInfo->adjustHeaderSearchOptions(HSB);
1550 ASSERT_EQ(HSA.PrebuiltModuleFiles.count(
"M"), 1u);
1551 ASSERT_EQ(HSB.PrebuiltModuleFiles.count(
"M"), 1u);
1552 EXPECT_TRUE(llvm::sys::fs::exists(HSA.PrebuiltModuleFiles[
"M"]));
1553 EXPECT_TRUE(llvm::sys::fs::exists(HSB.PrebuiltModuleFiles[
"M"]));
1555 llvm::SmallString<256> ExpectedRoot(getFullPath(
"shared/M.cppm"));
1556 llvm::sys::path::remove_filename(ExpectedRoot);
1557 llvm::sys::path::append(ExpectedRoot,
".cache",
"clangd",
"modules");
1559 StringRef(HSA.PrebuiltModuleFiles[
"M"]).starts_with(ExpectedRoot));
1560 EXPECT_TRUE(StringRef(HSA.PrebuiltModuleFiles[
"M"]).contains(
"M.cppm-"));
1562 StringRef(HSB.PrebuiltModuleFiles[
"M"]).starts_with(ExpectedRoot));
1563 EXPECT_TRUE(StringRef(HSB.PrebuiltModuleFiles[
"M"]).contains(
"M.cppm-"));
1566TEST_F(PrerequisiteModulesTests, ModuleImportThroughInclude) {
1567 MockDirectoryCompilationDatabase CDB(TestDir, FS);
1569 Annotations UseCpp(R
"cpp(
1570#include "Header.hpp"
1577 CDB.addFile("M.cppm", R
"cpp(
1579export struct TypeFromModule {};
1582 CDB.addFile("Header.hpp", R
"cpp(
1584struct TypeFromHeader {};
1587 CDB.addFile("Use.cpp", UseCpp.code());
1589 ModulesBuilder Builder(CDB);
1591 auto Inputs = getInputs(
"Use.cpp", CDB);
1592 Inputs.ModulesManager = &Builder;
1593 Inputs.Opts.SkipPreambleBuild =
true;
1602 EXPECT_EQ(
Preamble->Preamble.getBounds().Size, 0u);
1607 EXPECT_TRUE(
AST->getDiagnostics().empty());
1609 auto Result =
codeComplete(getFullPath(
"Use.cpp"), UseCpp.point(),
1611 EXPECT_THAT(Result.Completions,
1612 testing::UnorderedElementsAre(named(
"TypeFromModule"),
1613 named(
"TypeFromHeader")));
static cl::opt< std::string > Directory(cl::Positional, cl::Required, cl::desc("<Search Root Directory>"))
Provides compilation arguments used for parsing C and C++ files.
static std::optional< ParsedAST > build(llvm::StringRef Filename, const ParseInputs &Inputs, std::unique_ptr< clang::CompilerInvocation > CI, llvm::ArrayRef< Diag > CompilerInvocationDiags, std::shared_ptr< const PreambleData > Preamble)
Attempts to run Clang and store the parsed AST.
An interface to query the modules information in the project.
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > view(std::nullopt_t CWD) const
Obtain a vfs::FileSystem with an arbitrary initial working directory.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
std::string maybeCaseFoldPath(PathRef Path)
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, std::vector< std::string > *CC1Args)
Builds compiler invocation that could be used to build AST or preamble.
std::shared_ptr< const PreambleData > buildPreamble(PathRef FileName, CompilerInvocation CI, const ParseInputs &Inputs, bool StoreInMemory, PreambleParsedCallback PreambleCallback, PreambleBuildStats *Stats)
Build a preamble for the new inputs unless an old one can be reused.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
std::string Path
A typedef to represent a file path.
CodeCompleteResult codeComplete(PathRef FileName, Position Pos, const PreambleData *Preamble, const ParseInputs &ParseInput, CodeCompleteOptions Opts, SpeculativeFuzzyFind *SpecFuzzyFind)
Gets code completions at a specified Pos in FileName.
SignatureHelp signatureHelp(PathRef FileName, Position Pos, const PreambleData &Preamble, const ParseInputs &ParseInput, MarkupKind DocumentationFormat)
Get signature help at a specified Pos in FileName.
std::unique_ptr< ProjectModules > getProjectModules(std::shared_ptr< const clang::tooling::CompilationDatabase > CDB, const ThreadsafeFS &TFS)
Creates the project-modules facade used by clangd.