[lld-macho] Remove unneeded functions from BPSectionOrderer. NFC
[llvm-project.git] / clang / lib / Tooling / DependencyScanning / ModuleDepCollector.cpp
blob2e97cac0796ceea9c30746a954b5e1e185d6199f
1 //===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
11 #include "clang/Basic/MakeSupport.h"
12 #include "clang/Frontend/CompilerInstance.h"
13 #include "clang/Lex/Preprocessor.h"
14 #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/Support/BLAKE3.h"
17 #include "llvm/Support/StringSaver.h"
18 #include <optional>
20 using namespace clang;
21 using namespace tooling;
22 using namespace dependencies;
24 void ModuleDeps::forEachFileDep(llvm::function_ref<void(StringRef)> Cb) const {
25 SmallString<0> PathBuf;
26 PathBuf.reserve(256);
27 for (StringRef FileDep : FileDeps) {
28 auto ResolvedFileDep =
29 ASTReader::ResolveImportedPath(PathBuf, FileDep, FileDepsBaseDir);
30 Cb(*ResolvedFileDep);
34 const std::vector<std::string> &ModuleDeps::getBuildArguments() {
35 assert(!std::holds_alternative<std::monostate>(BuildInfo) &&
36 "Using uninitialized ModuleDeps");
37 if (const auto *CI = std::get_if<CowCompilerInvocation>(&BuildInfo))
38 BuildInfo = CI->getCC1CommandLine();
39 return std::get<std::vector<std::string>>(BuildInfo);
42 static void
43 optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, ASTReader &Reader,
44 const serialization::ModuleFile &MF,
45 const PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap,
46 ScanningOptimizations OptimizeArgs) {
47 if (any(OptimizeArgs & ScanningOptimizations::HeaderSearch)) {
48 // Only preserve search paths that were used during the dependency scan.
49 std::vector<HeaderSearchOptions::Entry> Entries;
50 std::swap(Opts.UserEntries, Entries);
52 llvm::BitVector SearchPathUsage(Entries.size());
53 llvm::DenseSet<const serialization::ModuleFile *> Visited;
54 std::function<void(const serialization::ModuleFile *)> VisitMF =
55 [&](const serialization::ModuleFile *MF) {
56 SearchPathUsage |= MF->SearchPathUsage;
57 Visited.insert(MF);
58 for (const serialization::ModuleFile *Import : MF->Imports)
59 if (!Visited.contains(Import))
60 VisitMF(Import);
62 VisitMF(&MF);
64 if (SearchPathUsage.size() != Entries.size())
65 llvm::report_fatal_error(
66 "Inconsistent search path options between modules detected");
68 for (auto Idx : SearchPathUsage.set_bits())
69 Opts.UserEntries.push_back(std::move(Entries[Idx]));
71 if (any(OptimizeArgs & ScanningOptimizations::VFS)) {
72 std::vector<std::string> VFSOverlayFiles;
73 std::swap(Opts.VFSOverlayFiles, VFSOverlayFiles);
75 llvm::BitVector VFSUsage(VFSOverlayFiles.size());
76 llvm::DenseSet<const serialization::ModuleFile *> Visited;
77 std::function<void(const serialization::ModuleFile *)> VisitMF =
78 [&](const serialization::ModuleFile *MF) {
79 Visited.insert(MF);
80 if (MF->Kind == serialization::MK_ImplicitModule) {
81 VFSUsage |= MF->VFSUsage;
82 // We only need to recurse into implicit modules. Other module types
83 // will have the correct set of VFSs for anything they depend on.
84 for (const serialization::ModuleFile *Import : MF->Imports)
85 if (!Visited.contains(Import))
86 VisitMF(Import);
87 } else {
88 // This is not an implicitly built module, so it may have different
89 // VFS options. Fall back to a string comparison instead.
90 auto VFSMap = PrebuiltModuleVFSMap.find(MF->FileName);
91 if (VFSMap == PrebuiltModuleVFSMap.end())
92 return;
93 for (std::size_t I = 0, E = VFSOverlayFiles.size(); I != E; ++I) {
94 if (VFSMap->second.contains(VFSOverlayFiles[I]))
95 VFSUsage[I] = true;
99 VisitMF(&MF);
101 if (VFSUsage.size() != VFSOverlayFiles.size())
102 llvm::report_fatal_error(
103 "Inconsistent -ivfsoverlay options between modules detected");
105 for (auto Idx : VFSUsage.set_bits())
106 Opts.VFSOverlayFiles.push_back(std::move(VFSOverlayFiles[Idx]));
110 static void optimizeDiagnosticOpts(DiagnosticOptions &Opts,
111 bool IsSystemModule) {
112 // If this is not a system module or -Wsystem-headers was passed, don't
113 // optimize.
114 if (!IsSystemModule)
115 return;
116 bool Wsystem_headers = false;
117 for (StringRef Opt : Opts.Warnings) {
118 bool isPositive = !Opt.consume_front("no-");
119 if (Opt == "system-headers")
120 Wsystem_headers = isPositive;
122 if (Wsystem_headers)
123 return;
125 // Remove all warning flags. System modules suppress most, but not all,
126 // warnings.
127 Opts.Warnings.clear();
128 Opts.UndefPrefixes.clear();
129 Opts.Remarks.clear();
132 static std::vector<std::string> splitString(std::string S, char Separator) {
133 SmallVector<StringRef> Segments;
134 StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false);
135 std::vector<std::string> Result;
136 Result.reserve(Segments.size());
137 for (StringRef Segment : Segments)
138 Result.push_back(Segment.str());
139 return Result;
142 void ModuleDepCollector::addOutputPaths(CowCompilerInvocation &CI,
143 ModuleDeps &Deps) {
144 CI.getMutFrontendOpts().OutputFile =
145 Controller.lookupModuleOutput(Deps.ID, ModuleOutputKind::ModuleFile);
146 if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty())
147 CI.getMutDiagnosticOpts().DiagnosticSerializationFile =
148 Controller.lookupModuleOutput(
149 Deps.ID, ModuleOutputKind::DiagnosticSerializationFile);
150 if (!CI.getDependencyOutputOpts().OutputFile.empty()) {
151 CI.getMutDependencyOutputOpts().OutputFile = Controller.lookupModuleOutput(
152 Deps.ID, ModuleOutputKind::DependencyFile);
153 CI.getMutDependencyOutputOpts().Targets =
154 splitString(Controller.lookupModuleOutput(
155 Deps.ID, ModuleOutputKind::DependencyTargets),
156 '\0');
157 if (!CI.getDependencyOutputOpts().OutputFile.empty() &&
158 CI.getDependencyOutputOpts().Targets.empty()) {
159 // Fallback to -o as dependency target, as in the driver.
160 SmallString<128> Target;
161 quoteMakeTarget(CI.getFrontendOpts().OutputFile, Target);
162 CI.getMutDependencyOutputOpts().Targets.push_back(std::string(Target));
167 void dependencies::resetBenignCodeGenOptions(frontend::ActionKind ProgramAction,
168 const LangOptions &LangOpts,
169 CodeGenOptions &CGOpts) {
170 // TODO: Figure out better way to set options to their default value.
171 if (ProgramAction == frontend::GenerateModule) {
172 CGOpts.MainFileName.clear();
173 CGOpts.DwarfDebugFlags.clear();
175 if (ProgramAction == frontend::GeneratePCH ||
176 (ProgramAction == frontend::GenerateModule && !LangOpts.ModulesCodegen)) {
177 CGOpts.DebugCompilationDir.clear();
178 CGOpts.CoverageCompilationDir.clear();
179 CGOpts.CoverageDataFile.clear();
180 CGOpts.CoverageNotesFile.clear();
181 CGOpts.ProfileInstrumentUsePath.clear();
182 CGOpts.SampleProfileFile.clear();
183 CGOpts.ProfileRemappingFile.clear();
187 static CowCompilerInvocation
188 makeCommonInvocationForModuleBuild(CompilerInvocation CI) {
189 CI.resetNonModularOptions();
190 CI.clearImplicitModuleBuildOptions();
192 // The scanner takes care to avoid passing non-affecting module maps to the
193 // explicit compiles. No need to do extra work just to find out there are no
194 // module map files to prune.
195 CI.getHeaderSearchOpts().ModulesPruneNonAffectingModuleMaps = false;
197 // Remove options incompatible with explicit module build or are likely to
198 // differ between identical modules discovered from different translation
199 // units.
200 CI.getFrontendOpts().Inputs.clear();
201 CI.getFrontendOpts().OutputFile.clear();
202 // LLVM options are not going to affect the AST
203 CI.getFrontendOpts().LLVMArgs.clear();
205 resetBenignCodeGenOptions(frontend::GenerateModule, CI.getLangOpts(),
206 CI.getCodeGenOpts());
208 // Map output paths that affect behaviour to "-" so their existence is in the
209 // context hash. The final path will be computed in addOutputPaths.
210 if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty())
211 CI.getDiagnosticOpts().DiagnosticSerializationFile = "-";
212 if (!CI.getDependencyOutputOpts().OutputFile.empty())
213 CI.getDependencyOutputOpts().OutputFile = "-";
214 CI.getDependencyOutputOpts().Targets.clear();
216 CI.getFrontendOpts().ProgramAction = frontend::GenerateModule;
217 CI.getFrontendOpts().ARCMTAction = FrontendOptions::ARCMT_None;
218 CI.getFrontendOpts().ObjCMTAction = FrontendOptions::ObjCMT_None;
219 CI.getFrontendOpts().MTMigrateDir.clear();
220 CI.getLangOpts().ModuleName.clear();
222 // Remove any macro definitions that are explicitly ignored.
223 if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) {
224 llvm::erase_if(
225 CI.getPreprocessorOpts().Macros,
226 [&CI](const std::pair<std::string, bool> &Def) {
227 StringRef MacroDef = Def.first;
228 return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains(
229 llvm::CachedHashString(MacroDef.split('=').first));
231 // Remove the now unused option.
232 CI.getHeaderSearchOpts().ModulesIgnoreMacros.clear();
235 return CI;
238 CowCompilerInvocation
239 ModuleDepCollector::getInvocationAdjustedForModuleBuildWithoutOutputs(
240 const ModuleDeps &Deps,
241 llvm::function_ref<void(CowCompilerInvocation &)> Optimize) const {
242 CowCompilerInvocation CI = CommonInvocation;
244 CI.getMutLangOpts().ModuleName = Deps.ID.ModuleName;
245 CI.getMutFrontendOpts().IsSystemModule = Deps.IsSystem;
247 // Inputs
248 InputKind ModuleMapInputKind(CI.getFrontendOpts().DashX.getLanguage(),
249 InputKind::Format::ModuleMap);
250 CI.getMutFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile,
251 ModuleMapInputKind);
253 auto CurrentModuleMapEntry =
254 ScanInstance.getFileManager().getOptionalFileRef(Deps.ClangModuleMapFile);
255 assert(CurrentModuleMapEntry && "module map file entry not found");
257 // Remove directly passed modulemap files. They will get added back if they
258 // were actually used.
259 CI.getMutFrontendOpts().ModuleMapFiles.clear();
261 auto DepModuleMapFiles = collectModuleMapFiles(Deps.ClangModuleDeps);
262 for (StringRef ModuleMapFile : Deps.ModuleMapFileDeps) {
263 // TODO: Track these as `FileEntryRef` to simplify the equality check below.
264 auto ModuleMapEntry =
265 ScanInstance.getFileManager().getOptionalFileRef(ModuleMapFile);
266 assert(ModuleMapEntry && "module map file entry not found");
268 // Don't report module maps describing eagerly-loaded dependency. This
269 // information will be deserialized from the PCM.
270 // TODO: Verify this works fine when modulemap for module A is eagerly
271 // loaded from A.pcm, and module map passed on the command line contains
272 // definition of a submodule: "explicit module A.Private { ... }".
273 if (EagerLoadModules && DepModuleMapFiles.contains(*ModuleMapEntry))
274 continue;
276 // Don't report module map file of the current module unless it also
277 // describes a dependency (for symmetry).
278 if (*ModuleMapEntry == *CurrentModuleMapEntry &&
279 !DepModuleMapFiles.contains(*ModuleMapEntry))
280 continue;
282 CI.getMutFrontendOpts().ModuleMapFiles.emplace_back(ModuleMapFile);
285 // Report the prebuilt modules this module uses.
286 for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps)
287 CI.getMutFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile);
289 // Add module file inputs from dependencies.
290 addModuleFiles(CI, Deps.ClangModuleDeps);
292 if (!CI.getDiagnosticOpts().SystemHeaderWarningsModules.empty()) {
293 // Apply -Wsystem-headers-in-module for the current module.
294 if (llvm::is_contained(CI.getDiagnosticOpts().SystemHeaderWarningsModules,
295 Deps.ID.ModuleName))
296 CI.getMutDiagnosticOpts().Warnings.push_back("system-headers");
297 // Remove the now unused option(s).
298 CI.getMutDiagnosticOpts().SystemHeaderWarningsModules.clear();
301 Optimize(CI);
303 return CI;
306 llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles(
307 ArrayRef<ModuleID> ClangModuleDeps) const {
308 llvm::DenseSet<const FileEntry *> ModuleMapFiles;
309 for (const ModuleID &MID : ClangModuleDeps) {
310 ModuleDeps *MD = ModuleDepsByID.lookup(MID);
311 assert(MD && "Inconsistent dependency info");
312 // TODO: Track ClangModuleMapFile as `FileEntryRef`.
313 auto FE = ScanInstance.getFileManager().getOptionalFileRef(
314 MD->ClangModuleMapFile);
315 assert(FE && "Missing module map file that was previously found");
316 ModuleMapFiles.insert(*FE);
318 return ModuleMapFiles;
321 void ModuleDepCollector::addModuleMapFiles(
322 CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
323 if (EagerLoadModules)
324 return; // Only pcm is needed for eager load.
326 for (const ModuleID &MID : ClangModuleDeps) {
327 ModuleDeps *MD = ModuleDepsByID.lookup(MID);
328 assert(MD && "Inconsistent dependency info");
329 CI.getFrontendOpts().ModuleMapFiles.push_back(MD->ClangModuleMapFile);
333 void ModuleDepCollector::addModuleFiles(
334 CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
335 for (const ModuleID &MID : ClangModuleDeps) {
336 std::string PCMPath =
337 Controller.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile);
338 if (EagerLoadModules)
339 CI.getFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
340 else
341 CI.getHeaderSearchOpts().PrebuiltModuleFiles.insert(
342 {MID.ModuleName, std::move(PCMPath)});
346 void ModuleDepCollector::addModuleFiles(
347 CowCompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
348 for (const ModuleID &MID : ClangModuleDeps) {
349 std::string PCMPath =
350 Controller.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile);
351 if (EagerLoadModules)
352 CI.getMutFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
353 else
354 CI.getMutHeaderSearchOpts().PrebuiltModuleFiles.insert(
355 {MID.ModuleName, std::move(PCMPath)});
359 static bool needsModules(FrontendInputFile FIF) {
360 switch (FIF.getKind().getLanguage()) {
361 case Language::Unknown:
362 case Language::Asm:
363 case Language::LLVM_IR:
364 return false;
365 default:
366 return true;
370 void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) {
371 CI.clearImplicitModuleBuildOptions();
372 resetBenignCodeGenOptions(CI.getFrontendOpts().ProgramAction,
373 CI.getLangOpts(), CI.getCodeGenOpts());
375 if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) {
376 Preprocessor &PP = ScanInstance.getPreprocessor();
377 if (Module *CurrentModule = PP.getCurrentModuleImplementation())
378 if (OptionalFileEntryRef CurrentModuleMap =
379 PP.getHeaderSearchInfo()
380 .getModuleMap()
381 .getModuleMapFileForUniquing(CurrentModule))
382 CI.getFrontendOpts().ModuleMapFiles.emplace_back(
383 CurrentModuleMap->getNameAsRequested());
385 SmallVector<ModuleID> DirectDeps;
386 for (const auto &KV : ModularDeps)
387 if (DirectModularDeps.contains(KV.first))
388 DirectDeps.push_back(KV.second->ID);
390 // TODO: Report module maps the same way it's done for modular dependencies.
391 addModuleMapFiles(CI, DirectDeps);
393 addModuleFiles(CI, DirectDeps);
395 for (const auto &KV : DirectPrebuiltModularDeps)
396 CI.getFrontendOpts().ModuleFiles.push_back(KV.second.PCMFile);
400 static std::string getModuleContextHash(const ModuleDeps &MD,
401 const CowCompilerInvocation &CI,
402 bool EagerLoadModules,
403 llvm::vfs::FileSystem &VFS) {
404 llvm::HashBuilder<llvm::TruncatedBLAKE3<16>, llvm::endianness::native>
405 HashBuilder;
406 SmallString<32> Scratch;
408 // Hash the compiler version and serialization version to ensure the module
409 // will be readable.
410 HashBuilder.add(getClangFullRepositoryVersion());
411 HashBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR);
412 llvm::ErrorOr<std::string> CWD = VFS.getCurrentWorkingDirectory();
413 if (CWD)
414 HashBuilder.add(*CWD);
416 // Hash the BuildInvocation without any input files.
417 SmallString<0> ArgVec;
418 ArgVec.reserve(4096);
419 CI.generateCC1CommandLine([&](const Twine &Arg) {
420 Arg.toVector(ArgVec);
421 ArgVec.push_back('\0');
423 HashBuilder.add(ArgVec);
425 // Hash the module dependencies. These paths may differ even if the invocation
426 // is identical if they depend on the contents of the files in the TU -- for
427 // example, case-insensitive paths to modulemap files. Usually such a case
428 // would indicate a missed optimization to canonicalize, but it may be
429 // difficult to canonicalize all cases when there is a VFS.
430 for (const auto &ID : MD.ClangModuleDeps) {
431 HashBuilder.add(ID.ModuleName);
432 HashBuilder.add(ID.ContextHash);
435 HashBuilder.add(EagerLoadModules);
437 llvm::BLAKE3Result<16> Hash = HashBuilder.final();
438 std::array<uint64_t, 2> Words;
439 static_assert(sizeof(Hash) == sizeof(Words), "Hash must match Words");
440 std::memcpy(Words.data(), Hash.data(), sizeof(Hash));
441 return toString(llvm::APInt(sizeof(Words) * 8, Words), 36, /*Signed=*/false);
444 void ModuleDepCollector::associateWithContextHash(
445 const CowCompilerInvocation &CI, ModuleDeps &Deps) {
446 Deps.ID.ContextHash = getModuleContextHash(
447 Deps, CI, EagerLoadModules, ScanInstance.getVirtualFileSystem());
448 bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second;
449 (void)Inserted;
450 assert(Inserted && "duplicate module mapping");
453 void ModuleDepCollectorPP::LexedFileChanged(FileID FID,
454 LexedFileChangeReason Reason,
455 SrcMgr::CharacteristicKind FileType,
456 FileID PrevFID,
457 SourceLocation Loc) {
458 if (Reason != LexedFileChangeReason::EnterFile)
459 return;
461 // This has to be delayed as the context hash can change at the start of
462 // `CompilerInstance::ExecuteAction`.
463 if (MDC.ContextHash.empty()) {
464 MDC.ContextHash = MDC.ScanInstance.getInvocation().getModuleHash();
465 MDC.Consumer.handleContextHash(MDC.ContextHash);
468 SourceManager &SM = MDC.ScanInstance.getSourceManager();
470 // Dependency generation really does want to go all the way to the
471 // file entry for a source location to find out what is depended on.
472 // We do not want #line markers to affect dependency generation!
473 if (std::optional<StringRef> Filename = SM.getNonBuiltinFilenameForID(FID))
474 MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*Filename));
477 void ModuleDepCollectorPP::InclusionDirective(
478 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
479 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
480 StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
481 bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
482 if (!File && !ModuleImported) {
483 // This is a non-modular include that HeaderSearch failed to find. Add it
484 // here as `FileChanged` will never see it.
485 MDC.addFileDep(FileName);
487 handleImport(SuggestedModule);
490 void ModuleDepCollectorPP::moduleImport(SourceLocation ImportLoc,
491 ModuleIdPath Path,
492 const Module *Imported) {
493 if (MDC.ScanInstance.getPreprocessor().isInImportingCXXNamedModules()) {
494 P1689ModuleInfo RequiredModule;
495 RequiredModule.ModuleName = Path[0].first->getName().str();
496 RequiredModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule;
497 MDC.RequiredStdCXXModules.push_back(RequiredModule);
498 return;
501 handleImport(Imported);
504 void ModuleDepCollectorPP::handleImport(const Module *Imported) {
505 if (!Imported)
506 return;
508 const Module *TopLevelModule = Imported->getTopLevelModule();
510 if (MDC.isPrebuiltModule(TopLevelModule))
511 MDC.DirectPrebuiltModularDeps.insert(
512 {TopLevelModule, PrebuiltModuleDep{TopLevelModule}});
513 else
514 MDC.DirectModularDeps.insert(TopLevelModule);
517 void ModuleDepCollectorPP::EndOfMainFile() {
518 FileID MainFileID = MDC.ScanInstance.getSourceManager().getMainFileID();
519 MDC.MainFile = std::string(MDC.ScanInstance.getSourceManager()
520 .getFileEntryRefForID(MainFileID)
521 ->getName());
523 auto &PP = MDC.ScanInstance.getPreprocessor();
524 if (PP.isInNamedModule()) {
525 P1689ModuleInfo ProvidedModule;
526 ProvidedModule.ModuleName = PP.getNamedModuleName();
527 ProvidedModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule;
528 ProvidedModule.IsStdCXXModuleInterface = PP.isInNamedInterfaceUnit();
529 // Don't put implementation (non partition) unit as Provide.
530 // Put the module as required instead. Since the implementation
531 // unit will import the primary module implicitly.
532 if (PP.isInImplementationUnit())
533 MDC.RequiredStdCXXModules.push_back(ProvidedModule);
534 else
535 MDC.ProvidedStdCXXModule = ProvidedModule;
538 if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
539 MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude);
541 for (const Module *M :
542 MDC.ScanInstance.getPreprocessor().getAffectingClangModules())
543 if (!MDC.isPrebuiltModule(M))
544 MDC.DirectModularDeps.insert(M);
546 for (const Module *M : MDC.DirectModularDeps)
547 handleTopLevelModule(M);
549 MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts);
551 if (MDC.IsStdModuleP1689Format)
552 MDC.Consumer.handleProvidedAndRequiredStdCXXModules(
553 MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules);
555 for (auto &&I : MDC.ModularDeps)
556 MDC.Consumer.handleModuleDependency(*I.second);
558 for (const Module *M : MDC.DirectModularDeps) {
559 auto It = MDC.ModularDeps.find(M);
560 // Only report direct dependencies that were successfully handled.
561 if (It != MDC.ModularDeps.end())
562 MDC.Consumer.handleDirectModuleDependency(It->second->ID);
565 for (auto &&I : MDC.FileDeps)
566 MDC.Consumer.handleFileDependency(I);
568 for (auto &&I : MDC.DirectPrebuiltModularDeps)
569 MDC.Consumer.handlePrebuiltModuleDependency(I.second);
572 std::optional<ModuleID>
573 ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
574 assert(M == M->getTopLevelModule() && "Expected top level module!");
576 // A top-level module might not be actually imported as a module when
577 // -fmodule-name is used to compile a translation unit that imports this
578 // module. In that case it can be skipped. The appropriate header
579 // dependencies will still be reported as expected.
580 if (!M->getASTFile())
581 return {};
583 // If this module has been handled already, just return its ID.
584 if (auto ModI = MDC.ModularDeps.find(M); ModI != MDC.ModularDeps.end())
585 return ModI->second->ID;
587 auto OwnedMD = std::make_unique<ModuleDeps>();
588 ModuleDeps &MD = *OwnedMD;
590 MD.ID.ModuleName = M->getFullModuleName();
591 MD.IsSystem = M->IsSystem;
592 // For modules which use export_as link name, the linked product that of the
593 // corresponding export_as-named module.
594 if (!M->UseExportAsModuleLinkName)
595 MD.LinkLibraries = M->LinkLibraries;
597 ModuleMap &ModMapInfo =
598 MDC.ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
600 if (auto ModuleMap = ModMapInfo.getModuleMapFileForUniquing(M)) {
601 SmallString<128> Path = ModuleMap->getNameAsRequested();
602 ModMapInfo.canonicalizeModuleMapPath(Path);
603 MD.ClangModuleMapFile = std::string(Path);
606 serialization::ModuleFile *MF =
607 MDC.ScanInstance.getASTReader()->getModuleManager().lookup(
608 *M->getASTFile());
609 MD.FileDepsBaseDir = MF->BaseDirectory;
610 MDC.ScanInstance.getASTReader()->visitInputFileInfos(
611 *MF, /*IncludeSystem=*/true,
612 [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
613 // The __inferred_module.map file is an insignificant implementation
614 // detail of implicitly-built modules. The PCM will also report the
615 // actual on-disk module map file that allowed inferring the module,
616 // which is what we need for building the module explicitly
617 // Let's ignore this file.
618 if (IFI.UnresolvedImportedFilename.ends_with("__inferred_module.map"))
619 return;
620 MDC.addFileDep(MD, IFI.UnresolvedImportedFilename);
623 llvm::DenseSet<const Module *> SeenDeps;
624 addAllSubmodulePrebuiltDeps(M, MD, SeenDeps);
625 addAllSubmoduleDeps(M, MD, SeenDeps);
626 addAllAffectingClangModules(M, MD, SeenDeps);
628 SmallString<0> PathBuf;
629 PathBuf.reserve(256);
630 MDC.ScanInstance.getASTReader()->visitInputFileInfos(
631 *MF, /*IncludeSystem=*/true,
632 [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
633 if (!(IFI.TopLevel && IFI.ModuleMap))
634 return;
635 if (IFI.UnresolvedImportedFilenameAsRequested.ends_with(
636 "__inferred_module.map"))
637 return;
638 auto ResolvedFilenameAsRequested = ASTReader::ResolveImportedPath(
639 PathBuf, IFI.UnresolvedImportedFilenameAsRequested,
640 MF->BaseDirectory);
641 MD.ModuleMapFileDeps.emplace_back(*ResolvedFilenameAsRequested);
644 CowCompilerInvocation CI =
645 MDC.getInvocationAdjustedForModuleBuildWithoutOutputs(
646 MD, [&](CowCompilerInvocation &BuildInvocation) {
647 if (any(MDC.OptimizeArgs & (ScanningOptimizations::HeaderSearch |
648 ScanningOptimizations::VFS)))
649 optimizeHeaderSearchOpts(BuildInvocation.getMutHeaderSearchOpts(),
650 *MDC.ScanInstance.getASTReader(), *MF,
651 MDC.PrebuiltModuleVFSMap,
652 MDC.OptimizeArgs);
653 if (any(MDC.OptimizeArgs & ScanningOptimizations::SystemWarnings))
654 optimizeDiagnosticOpts(
655 BuildInvocation.getMutDiagnosticOpts(),
656 BuildInvocation.getFrontendOpts().IsSystemModule);
659 MDC.associateWithContextHash(CI, MD);
661 // Finish the compiler invocation. Requires dependencies and the context hash.
662 MDC.addOutputPaths(CI, MD);
664 MD.BuildInfo = std::move(CI);
666 MDC.ModularDeps.insert({M, std::move(OwnedMD)});
668 return MD.ID;
671 static void forEachSubmoduleSorted(const Module *M,
672 llvm::function_ref<void(const Module *)> F) {
673 // Submodule order depends on order of header includes for inferred submodules
674 // we don't care about the exact order, so sort so that it's consistent across
675 // TUs to improve sharing.
676 SmallVector<const Module *> Submodules(M->submodules());
677 llvm::stable_sort(Submodules, [](const Module *A, const Module *B) {
678 return A->Name < B->Name;
680 for (const Module *SubM : Submodules)
681 F(SubM);
684 void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps(
685 const Module *M, ModuleDeps &MD,
686 llvm::DenseSet<const Module *> &SeenSubmodules) {
687 addModulePrebuiltDeps(M, MD, SeenSubmodules);
689 forEachSubmoduleSorted(M, [&](const Module *SubM) {
690 addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules);
694 void ModuleDepCollectorPP::addModulePrebuiltDeps(
695 const Module *M, ModuleDeps &MD,
696 llvm::DenseSet<const Module *> &SeenSubmodules) {
697 for (const Module *Import : M->Imports)
698 if (Import->getTopLevelModule() != M->getTopLevelModule())
699 if (MDC.isPrebuiltModule(Import->getTopLevelModule()))
700 if (SeenSubmodules.insert(Import->getTopLevelModule()).second)
701 MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule());
704 void ModuleDepCollectorPP::addAllSubmoduleDeps(
705 const Module *M, ModuleDeps &MD,
706 llvm::DenseSet<const Module *> &AddedModules) {
707 addModuleDep(M, MD, AddedModules);
709 forEachSubmoduleSorted(M, [&](const Module *SubM) {
710 addAllSubmoduleDeps(SubM, MD, AddedModules);
714 void ModuleDepCollectorPP::addModuleDep(
715 const Module *M, ModuleDeps &MD,
716 llvm::DenseSet<const Module *> &AddedModules) {
717 for (const Module *Import : M->Imports) {
718 if (Import->getTopLevelModule() != M->getTopLevelModule() &&
719 !MDC.isPrebuiltModule(Import)) {
720 if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule()))
721 if (AddedModules.insert(Import->getTopLevelModule()).second)
722 MD.ClangModuleDeps.push_back(*ImportID);
727 void ModuleDepCollectorPP::addAllAffectingClangModules(
728 const Module *M, ModuleDeps &MD,
729 llvm::DenseSet<const Module *> &AddedModules) {
730 addAffectingClangModule(M, MD, AddedModules);
732 for (const Module *SubM : M->submodules())
733 addAllAffectingClangModules(SubM, MD, AddedModules);
736 void ModuleDepCollectorPP::addAffectingClangModule(
737 const Module *M, ModuleDeps &MD,
738 llvm::DenseSet<const Module *> &AddedModules) {
739 for (const Module *Affecting : M->AffectingClangModules) {
740 assert(Affecting == Affecting->getTopLevelModule() &&
741 "Not quite import not top-level module");
742 if (Affecting != M->getTopLevelModule() &&
743 !MDC.isPrebuiltModule(Affecting)) {
744 if (auto ImportID = handleTopLevelModule(Affecting))
745 if (AddedModules.insert(Affecting).second)
746 MD.ClangModuleDeps.push_back(*ImportID);
751 ModuleDepCollector::ModuleDepCollector(
752 std::unique_ptr<DependencyOutputOptions> Opts,
753 CompilerInstance &ScanInstance, DependencyConsumer &C,
754 DependencyActionController &Controller, CompilerInvocation OriginalCI,
755 PrebuiltModuleVFSMapT PrebuiltModuleVFSMap,
756 ScanningOptimizations OptimizeArgs, bool EagerLoadModules,
757 bool IsStdModuleP1689Format)
758 : ScanInstance(ScanInstance), Consumer(C), Controller(Controller),
759 PrebuiltModuleVFSMap(std::move(PrebuiltModuleVFSMap)),
760 Opts(std::move(Opts)),
761 CommonInvocation(
762 makeCommonInvocationForModuleBuild(std::move(OriginalCI))),
763 OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules),
764 IsStdModuleP1689Format(IsStdModuleP1689Format) {}
766 void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) {
767 PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this));
770 void ModuleDepCollector::attachToASTReader(ASTReader &R) {}
772 bool ModuleDepCollector::isPrebuiltModule(const Module *M) {
773 std::string Name(M->getTopLevelModuleName());
774 const auto &PrebuiltModuleFiles =
775 ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles;
776 auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name);
777 if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end())
778 return false;
779 assert("Prebuilt module came from the expected AST file" &&
780 PrebuiltModuleFileIt->second == M->getASTFile()->getName());
781 return true;
784 static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path,
785 SmallVectorImpl<char> &Storage) {
786 if (llvm::sys::path::is_absolute(Path) &&
787 !llvm::sys::path::is_style_windows(llvm::sys::path::Style::native))
788 return Path;
789 Storage.assign(Path.begin(), Path.end());
790 CI.getFileManager().makeAbsolutePath(Storage);
791 llvm::sys::path::make_preferred(Storage);
792 return StringRef(Storage.data(), Storage.size());
795 void ModuleDepCollector::addFileDep(StringRef Path) {
796 if (IsStdModuleP1689Format) {
797 // Within P1689 format, we don't want all the paths to be absolute path
798 // since it may violate the traditional make style dependencies info.
799 FileDeps.emplace_back(Path);
800 return;
803 llvm::SmallString<256> Storage;
804 Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
805 FileDeps.emplace_back(Path);
808 void ModuleDepCollector::addFileDep(ModuleDeps &MD, StringRef Path) {
809 MD.FileDeps.emplace_back(Path);