xref: /llvm-project/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp (revision 9d4837f47c48c634d4a0ac799188e1f5332495ef)
133a745e6SMichael Spencer //===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ -*-===//
233a745e6SMichael Spencer //
3c874dd53SChristopher Di Bella // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c874dd53SChristopher Di Bella // See https://llvm.org/LICENSE.txt for license information.
5c874dd53SChristopher Di Bella // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
633a745e6SMichael Spencer //
733a745e6SMichael Spencer //===----------------------------------------------------------------------===//
833a745e6SMichael Spencer 
933a745e6SMichael Spencer #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
1033a745e6SMichael Spencer 
113ce78cbdSBen Langmuir #include "clang/Basic/MakeSupport.h"
1233a745e6SMichael Spencer #include "clang/Frontend/CompilerInstance.h"
1333a745e6SMichael Spencer #include "clang/Lex/Preprocessor.h"
1433a745e6SMichael Spencer #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
15dc5cbba3SBen Langmuir #include "llvm/ADT/STLExtras.h"
1602871701SBen Langmuir #include "llvm/Support/BLAKE3.h"
170a92e09cSJan Svoboda #include "llvm/Support/StringSaver.h"
18a1580d7bSKazu Hirata #include <optional>
1933a745e6SMichael Spencer 
2033a745e6SMichael Spencer using namespace clang;
2133a745e6SMichael Spencer using namespace tooling;
2233a745e6SMichael Spencer using namespace dependencies;
2333a745e6SMichael Spencer 
24*9d4837f4SJan Svoboda void ModuleDeps::forEachFileDep(llvm::function_ref<void(StringRef)> Cb) const {
25*9d4837f4SJan Svoboda   SmallString<0> PathBuf;
26*9d4837f4SJan Svoboda   PathBuf.reserve(256);
27*9d4837f4SJan Svoboda   for (StringRef FileDep : FileDeps) {
28*9d4837f4SJan Svoboda     auto ResolvedFileDep =
29*9d4837f4SJan Svoboda         ASTReader::ResolveImportedPath(PathBuf, FileDep, FileDepsBaseDir);
30*9d4837f4SJan Svoboda     Cb(*ResolvedFileDep);
31*9d4837f4SJan Svoboda   }
32*9d4837f4SJan Svoboda }
33*9d4837f4SJan Svoboda 
343b1a6865SJan Svoboda const std::vector<std::string> &ModuleDeps::getBuildArguments() {
353b1a6865SJan Svoboda   assert(!std::holds_alternative<std::monostate>(BuildInfo) &&
363b1a6865SJan Svoboda          "Using uninitialized ModuleDeps");
373b1a6865SJan Svoboda   if (const auto *CI = std::get_if<CowCompilerInvocation>(&BuildInfo))
383b1a6865SJan Svoboda     BuildInfo = CI->getCC1CommandLine();
393b1a6865SJan Svoboda   return std::get<std::vector<std::string>>(BuildInfo);
403b1a6865SJan Svoboda }
413b1a6865SJan Svoboda 
42de3b2c29SMichael Spencer static void
43de3b2c29SMichael Spencer optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, ASTReader &Reader,
447847e445SMichael Spencer                          const serialization::ModuleFile &MF,
45de3b2c29SMichael Spencer                          const PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap,
467847e445SMichael Spencer                          ScanningOptimizations OptimizeArgs) {
477847e445SMichael Spencer   if (any(OptimizeArgs & ScanningOptimizations::HeaderSearch)) {
486a1f50b8SJan Svoboda     // Only preserve search paths that were used during the dependency scan.
497847e445SMichael Spencer     std::vector<HeaderSearchOptions::Entry> Entries;
507847e445SMichael Spencer     std::swap(Opts.UserEntries, Entries);
51d73daa91SJan Svoboda 
52d73daa91SJan Svoboda     llvm::BitVector SearchPathUsage(Entries.size());
53d73daa91SJan Svoboda     llvm::DenseSet<const serialization::ModuleFile *> Visited;
54d73daa91SJan Svoboda     std::function<void(const serialization::ModuleFile *)> VisitMF =
55d73daa91SJan Svoboda         [&](const serialization::ModuleFile *MF) {
56d73daa91SJan Svoboda           SearchPathUsage |= MF->SearchPathUsage;
57d73daa91SJan Svoboda           Visited.insert(MF);
58d73daa91SJan Svoboda           for (const serialization::ModuleFile *Import : MF->Imports)
59d73daa91SJan Svoboda             if (!Visited.contains(Import))
60d73daa91SJan Svoboda               VisitMF(Import);
61d73daa91SJan Svoboda         };
62d73daa91SJan Svoboda     VisitMF(&MF);
63d73daa91SJan Svoboda 
647847e445SMichael Spencer     if (SearchPathUsage.size() != Entries.size())
657847e445SMichael Spencer       llvm::report_fatal_error(
667847e445SMichael Spencer           "Inconsistent search path options between modules detected");
677847e445SMichael Spencer 
68d73daa91SJan Svoboda     for (auto Idx : SearchPathUsage.set_bits())
697847e445SMichael Spencer       Opts.UserEntries.push_back(std::move(Entries[Idx]));
707847e445SMichael Spencer   }
717847e445SMichael Spencer   if (any(OptimizeArgs & ScanningOptimizations::VFS)) {
727847e445SMichael Spencer     std::vector<std::string> VFSOverlayFiles;
737847e445SMichael Spencer     std::swap(Opts.VFSOverlayFiles, VFSOverlayFiles);
747847e445SMichael Spencer 
757847e445SMichael Spencer     llvm::BitVector VFSUsage(VFSOverlayFiles.size());
767847e445SMichael Spencer     llvm::DenseSet<const serialization::ModuleFile *> Visited;
777847e445SMichael Spencer     std::function<void(const serialization::ModuleFile *)> VisitMF =
787847e445SMichael Spencer         [&](const serialization::ModuleFile *MF) {
797847e445SMichael Spencer           Visited.insert(MF);
80de3b2c29SMichael Spencer           if (MF->Kind == serialization::MK_ImplicitModule) {
81de3b2c29SMichael Spencer             VFSUsage |= MF->VFSUsage;
82de3b2c29SMichael Spencer             // We only need to recurse into implicit modules. Other module types
83de3b2c29SMichael Spencer             // will have the correct set of VFSs for anything they depend on.
847847e445SMichael Spencer             for (const serialization::ModuleFile *Import : MF->Imports)
857847e445SMichael Spencer               if (!Visited.contains(Import))
867847e445SMichael Spencer                 VisitMF(Import);
87de3b2c29SMichael Spencer           } else {
88de3b2c29SMichael Spencer             // This is not an implicitly built module, so it may have different
89de3b2c29SMichael Spencer             // VFS options. Fall back to a string comparison instead.
90de3b2c29SMichael Spencer             auto VFSMap = PrebuiltModuleVFSMap.find(MF->FileName);
91de3b2c29SMichael Spencer             if (VFSMap == PrebuiltModuleVFSMap.end())
92de3b2c29SMichael Spencer               return;
93de3b2c29SMichael Spencer             for (std::size_t I = 0, E = VFSOverlayFiles.size(); I != E; ++I) {
94de3b2c29SMichael Spencer               if (VFSMap->second.contains(VFSOverlayFiles[I]))
95de3b2c29SMichael Spencer                 VFSUsage[I] = true;
96de3b2c29SMichael Spencer             }
97de3b2c29SMichael Spencer           }
987847e445SMichael Spencer         };
997847e445SMichael Spencer     VisitMF(&MF);
1007847e445SMichael Spencer 
1017847e445SMichael Spencer     if (VFSUsage.size() != VFSOverlayFiles.size())
1027847e445SMichael Spencer       llvm::report_fatal_error(
1037847e445SMichael Spencer           "Inconsistent -ivfsoverlay options between modules detected");
1047847e445SMichael Spencer 
1057847e445SMichael Spencer     for (auto Idx : VFSUsage.set_bits())
1067847e445SMichael Spencer       Opts.VFSOverlayFiles.push_back(std::move(VFSOverlayFiles[Idx]));
1077847e445SMichael Spencer   }
1086a1f50b8SJan Svoboda }
1096a1f50b8SJan Svoboda 
110731152e1SMichael Spencer static void optimizeDiagnosticOpts(DiagnosticOptions &Opts,
111731152e1SMichael Spencer                                    bool IsSystemModule) {
112731152e1SMichael Spencer   // If this is not a system module or -Wsystem-headers was passed, don't
113731152e1SMichael Spencer   // optimize.
114731152e1SMichael Spencer   if (!IsSystemModule)
115731152e1SMichael Spencer     return;
116731152e1SMichael Spencer   bool Wsystem_headers = false;
117731152e1SMichael Spencer   for (StringRef Opt : Opts.Warnings) {
118731152e1SMichael Spencer     bool isPositive = !Opt.consume_front("no-");
119731152e1SMichael Spencer     if (Opt == "system-headers")
120731152e1SMichael Spencer       Wsystem_headers = isPositive;
121731152e1SMichael Spencer   }
122731152e1SMichael Spencer   if (Wsystem_headers)
123731152e1SMichael Spencer     return;
124731152e1SMichael Spencer 
125731152e1SMichael Spencer   // Remove all warning flags. System modules suppress most, but not all,
126731152e1SMichael Spencer   // warnings.
127731152e1SMichael Spencer   Opts.Warnings.clear();
128731152e1SMichael Spencer   Opts.UndefPrefixes.clear();
129731152e1SMichael Spencer   Opts.Remarks.clear();
130731152e1SMichael Spencer }
131731152e1SMichael Spencer 
1325482432bSBen Langmuir static std::vector<std::string> splitString(std::string S, char Separator) {
1335482432bSBen Langmuir   SmallVector<StringRef> Segments;
1345482432bSBen Langmuir   StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false);
1355482432bSBen Langmuir   std::vector<std::string> Result;
1365482432bSBen Langmuir   Result.reserve(Segments.size());
1375482432bSBen Langmuir   for (StringRef Segment : Segments)
1385482432bSBen Langmuir     Result.push_back(Segment.str());
1395482432bSBen Langmuir   return Result;
1405482432bSBen Langmuir }
1415482432bSBen Langmuir 
1429208065aSJan Svoboda void ModuleDepCollector::addOutputPaths(CowCompilerInvocation &CI,
143e8febb23SBen Langmuir                                         ModuleDeps &Deps) {
1449208065aSJan Svoboda   CI.getMutFrontendOpts().OutputFile =
145296ba5bbSBen Langmuir       Controller.lookupModuleOutput(Deps.ID, ModuleOutputKind::ModuleFile);
1465482432bSBen Langmuir   if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty())
1479208065aSJan Svoboda     CI.getMutDiagnosticOpts().DiagnosticSerializationFile =
148296ba5bbSBen Langmuir         Controller.lookupModuleOutput(
1495482432bSBen Langmuir             Deps.ID, ModuleOutputKind::DiagnosticSerializationFile);
1505482432bSBen Langmuir   if (!CI.getDependencyOutputOpts().OutputFile.empty()) {
1519208065aSJan Svoboda     CI.getMutDependencyOutputOpts().OutputFile = Controller.lookupModuleOutput(
152296ba5bbSBen Langmuir         Deps.ID, ModuleOutputKind::DependencyFile);
1539208065aSJan Svoboda     CI.getMutDependencyOutputOpts().Targets =
154296ba5bbSBen Langmuir         splitString(Controller.lookupModuleOutput(
1555482432bSBen Langmuir                         Deps.ID, ModuleOutputKind::DependencyTargets),
1565482432bSBen Langmuir                     '\0');
1575482432bSBen Langmuir     if (!CI.getDependencyOutputOpts().OutputFile.empty() &&
1585482432bSBen Langmuir         CI.getDependencyOutputOpts().Targets.empty()) {
1595482432bSBen Langmuir       // Fallback to -o as dependency target, as in the driver.
1605482432bSBen Langmuir       SmallString<128> Target;
1615482432bSBen Langmuir       quoteMakeTarget(CI.getFrontendOpts().OutputFile, Target);
1629208065aSJan Svoboda       CI.getMutDependencyOutputOpts().Targets.push_back(std::string(Target));
1635482432bSBen Langmuir     }
1645482432bSBen Langmuir   }
1655482432bSBen Langmuir }
1665482432bSBen Langmuir 
16763310243SArgyrios Kyrtzidis void dependencies::resetBenignCodeGenOptions(frontend::ActionKind ProgramAction,
16863310243SArgyrios Kyrtzidis                                              const LangOptions &LangOpts,
16963310243SArgyrios Kyrtzidis                                              CodeGenOptions &CGOpts) {
17063310243SArgyrios Kyrtzidis   // TODO: Figure out better way to set options to their default value.
17163310243SArgyrios Kyrtzidis   if (ProgramAction == frontend::GenerateModule) {
17263310243SArgyrios Kyrtzidis     CGOpts.MainFileName.clear();
17363310243SArgyrios Kyrtzidis     CGOpts.DwarfDebugFlags.clear();
17463310243SArgyrios Kyrtzidis   }
17563310243SArgyrios Kyrtzidis   if (ProgramAction == frontend::GeneratePCH ||
17663310243SArgyrios Kyrtzidis       (ProgramAction == frontend::GenerateModule && !LangOpts.ModulesCodegen)) {
17763310243SArgyrios Kyrtzidis     CGOpts.DebugCompilationDir.clear();
17863310243SArgyrios Kyrtzidis     CGOpts.CoverageCompilationDir.clear();
17963310243SArgyrios Kyrtzidis     CGOpts.CoverageDataFile.clear();
18063310243SArgyrios Kyrtzidis     CGOpts.CoverageNotesFile.clear();
18163310243SArgyrios Kyrtzidis     CGOpts.ProfileInstrumentUsePath.clear();
18263310243SArgyrios Kyrtzidis     CGOpts.SampleProfileFile.clear();
18363310243SArgyrios Kyrtzidis     CGOpts.ProfileRemappingFile.clear();
18463310243SArgyrios Kyrtzidis   }
18563310243SArgyrios Kyrtzidis }
18663310243SArgyrios Kyrtzidis 
1879208065aSJan Svoboda static CowCompilerInvocation
1889208065aSJan Svoboda makeCommonInvocationForModuleBuild(CompilerInvocation CI) {
1893708a148SBen Langmuir   CI.resetNonModularOptions();
1903708a148SBen Langmuir   CI.clearImplicitModuleBuildOptions();
1916da811fdSJan Svoboda 
1923ea5dff0SJan Svoboda   // The scanner takes care to avoid passing non-affecting module maps to the
1933ea5dff0SJan Svoboda   // explicit compiles. No need to do extra work just to find out there are no
1943ea5dff0SJan Svoboda   // module map files to prune.
1953ea5dff0SJan Svoboda   CI.getHeaderSearchOpts().ModulesPruneNonAffectingModuleMaps = false;
1963ea5dff0SJan Svoboda 
1975b6c0837SJan Svoboda   // Remove options incompatible with explicit module build or are likely to
1985b6c0837SJan Svoboda   // differ between identical modules discovered from different translation
1995b6c0837SJan Svoboda   // units.
2000a92e09cSJan Svoboda   CI.getFrontendOpts().Inputs.clear();
2010a92e09cSJan Svoboda   CI.getFrontendOpts().OutputFile.clear();
202e007551bSJuergen Ributzka   // LLVM options are not going to affect the AST
203e007551bSJuergen Ributzka   CI.getFrontendOpts().LLVMArgs.clear();
204060b2534SJan Svoboda 
20563310243SArgyrios Kyrtzidis   resetBenignCodeGenOptions(frontend::GenerateModule, CI.getLangOpts(),
20663310243SArgyrios Kyrtzidis                             CI.getCodeGenOpts());
207060b2534SJan Svoboda 
2085482432bSBen Langmuir   // Map output paths that affect behaviour to "-" so their existence is in the
2095482432bSBen Langmuir   // context hash. The final path will be computed in addOutputPaths.
2105482432bSBen Langmuir   if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty())
2115482432bSBen Langmuir     CI.getDiagnosticOpts().DiagnosticSerializationFile = "-";
2125482432bSBen Langmuir   if (!CI.getDependencyOutputOpts().OutputFile.empty())
2135482432bSBen Langmuir     CI.getDependencyOutputOpts().OutputFile = "-";
2146626f6feSBen Langmuir   CI.getDependencyOutputOpts().Targets.clear();
2150a92e09cSJan Svoboda 
2160a92e09cSJan Svoboda   CI.getFrontendOpts().ProgramAction = frontend::GenerateModule;
217ffa2a647SMichael Spencer   CI.getFrontendOpts().ARCMTAction = FrontendOptions::ARCMT_None;
218ffa2a647SMichael Spencer   CI.getFrontendOpts().ObjCMTAction = FrontendOptions::ObjCMT_None;
219ffa2a647SMichael Spencer   CI.getFrontendOpts().MTMigrateDir.clear();
2209208065aSJan Svoboda   CI.getLangOpts().ModuleName.clear();
2219208065aSJan Svoboda 
2229208065aSJan Svoboda   // Remove any macro definitions that are explicitly ignored.
2239208065aSJan Svoboda   if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) {
2249208065aSJan Svoboda     llvm::erase_if(
2259208065aSJan Svoboda         CI.getPreprocessorOpts().Macros,
2269208065aSJan Svoboda         [&CI](const std::pair<std::string, bool> &Def) {
2279208065aSJan Svoboda           StringRef MacroDef = Def.first;
2289208065aSJan Svoboda           return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains(
2299208065aSJan Svoboda               llvm::CachedHashString(MacroDef.split('=').first));
2309208065aSJan Svoboda         });
2319208065aSJan Svoboda     // Remove the now unused option.
2329208065aSJan Svoboda     CI.getHeaderSearchOpts().ModulesIgnoreMacros.clear();
2339208065aSJan Svoboda   }
2349208065aSJan Svoboda 
2359208065aSJan Svoboda   return CI;
2369208065aSJan Svoboda }
2379208065aSJan Svoboda 
2389208065aSJan Svoboda CowCompilerInvocation
2399208065aSJan Svoboda ModuleDepCollector::getInvocationAdjustedForModuleBuildWithoutOutputs(
2409208065aSJan Svoboda     const ModuleDeps &Deps,
2419208065aSJan Svoboda     llvm::function_ref<void(CowCompilerInvocation &)> Optimize) const {
2429208065aSJan Svoboda   CowCompilerInvocation CI = CommonInvocation;
2439208065aSJan Svoboda 
2449208065aSJan Svoboda   CI.getMutLangOpts().ModuleName = Deps.ID.ModuleName;
2459208065aSJan Svoboda   CI.getMutFrontendOpts().IsSystemModule = Deps.IsSystem;
2460a92e09cSJan Svoboda 
2475482432bSBen Langmuir   // Inputs
2485482432bSBen Langmuir   InputKind ModuleMapInputKind(CI.getFrontendOpts().DashX.getLanguage(),
2495482432bSBen Langmuir                                InputKind::Format::ModuleMap);
2509208065aSJan Svoboda   CI.getMutFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile,
2515482432bSBen Langmuir                                               ModuleMapInputKind);
25220fa87c7SJan Svoboda 
25320fa87c7SJan Svoboda   auto CurrentModuleMapEntry =
254b1aea98cSJan Svoboda       ScanInstance.getFileManager().getOptionalFileRef(Deps.ClangModuleMapFile);
25520fa87c7SJan Svoboda   assert(CurrentModuleMapEntry && "module map file entry not found");
25620fa87c7SJan Svoboda 
257c003d851SMichael Spencer   // Remove directly passed modulemap files. They will get added back if they
258c003d851SMichael Spencer   // were actually used.
259c003d851SMichael Spencer   CI.getMutFrontendOpts().ModuleMapFiles.clear();
260c003d851SMichael Spencer 
26120fa87c7SJan Svoboda   auto DepModuleMapFiles = collectModuleMapFiles(Deps.ClangModuleDeps);
26220fa87c7SJan Svoboda   for (StringRef ModuleMapFile : Deps.ModuleMapFileDeps) {
26305ec16d9SBen Langmuir     // TODO: Track these as `FileEntryRef` to simplify the equality check below.
264b1aea98cSJan Svoboda     auto ModuleMapEntry =
265b1aea98cSJan Svoboda         ScanInstance.getFileManager().getOptionalFileRef(ModuleMapFile);
26605ec16d9SBen Langmuir     assert(ModuleMapEntry && "module map file entry not found");
26705ec16d9SBen Langmuir 
26820fa87c7SJan Svoboda     // Don't report module maps describing eagerly-loaded dependency. This
26920fa87c7SJan Svoboda     // information will be deserialized from the PCM.
27020fa87c7SJan Svoboda     // TODO: Verify this works fine when modulemap for module A is eagerly
27120fa87c7SJan Svoboda     // loaded from A.pcm, and module map passed on the command line contains
27220fa87c7SJan Svoboda     // definition of a submodule: "explicit module A.Private { ... }".
27305ec16d9SBen Langmuir     if (EagerLoadModules && DepModuleMapFiles.contains(*ModuleMapEntry))
27420fa87c7SJan Svoboda       continue;
27520fa87c7SJan Svoboda 
27620fa87c7SJan Svoboda     // Don't report module map file of the current module unless it also
27720fa87c7SJan Svoboda     // describes a dependency (for symmetry).
27820fa87c7SJan Svoboda     if (*ModuleMapEntry == *CurrentModuleMapEntry &&
27905ec16d9SBen Langmuir         !DepModuleMapFiles.contains(*ModuleMapEntry))
28020fa87c7SJan Svoboda       continue;
28120fa87c7SJan Svoboda 
2829208065aSJan Svoboda     CI.getMutFrontendOpts().ModuleMapFiles.emplace_back(ModuleMapFile);
28320fa87c7SJan Svoboda   }
2845482432bSBen Langmuir 
2855482432bSBen Langmuir   // Report the prebuilt modules this module uses.
2865482432bSBen Langmuir   for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps)
2879208065aSJan Svoboda     CI.getMutFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile);
2885482432bSBen Langmuir 
28943854fa2SBen Langmuir   // Add module file inputs from dependencies.
29043854fa2SBen Langmuir   addModuleFiles(CI, Deps.ClangModuleDeps);
29143854fa2SBen Langmuir 
2929208065aSJan Svoboda   if (!CI.getDiagnosticOpts().SystemHeaderWarningsModules.empty()) {
293dc5cbba3SBen Langmuir     // Apply -Wsystem-headers-in-module for the current module.
294dc5cbba3SBen Langmuir     if (llvm::is_contained(CI.getDiagnosticOpts().SystemHeaderWarningsModules,
295dc5cbba3SBen Langmuir                            Deps.ID.ModuleName))
2969208065aSJan Svoboda       CI.getMutDiagnosticOpts().Warnings.push_back("system-headers");
297dc5cbba3SBen Langmuir     // Remove the now unused option(s).
2989208065aSJan Svoboda     CI.getMutDiagnosticOpts().SystemHeaderWarningsModules.clear();
2999208065aSJan Svoboda   }
300dc5cbba3SBen Langmuir 
3016a1f50b8SJan Svoboda   Optimize(CI);
3026a1f50b8SJan Svoboda 
3030a92e09cSJan Svoboda   return CI;
3040a92e09cSJan Svoboda }
3050a92e09cSJan Svoboda 
30605ec16d9SBen Langmuir llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles(
30720fa87c7SJan Svoboda     ArrayRef<ModuleID> ClangModuleDeps) const {
30805ec16d9SBen Langmuir   llvm::DenseSet<const FileEntry *> ModuleMapFiles;
30920fa87c7SJan Svoboda   for (const ModuleID &MID : ClangModuleDeps) {
31020fa87c7SJan Svoboda     ModuleDeps *MD = ModuleDepsByID.lookup(MID);
31120fa87c7SJan Svoboda     assert(MD && "Inconsistent dependency info");
31205ec16d9SBen Langmuir     // TODO: Track ClangModuleMapFile as `FileEntryRef`.
313b1aea98cSJan Svoboda     auto FE = ScanInstance.getFileManager().getOptionalFileRef(
314b1aea98cSJan Svoboda         MD->ClangModuleMapFile);
31505ec16d9SBen Langmuir     assert(FE && "Missing module map file that was previously found");
31605ec16d9SBen Langmuir     ModuleMapFiles.insert(*FE);
31720fa87c7SJan Svoboda   }
31820fa87c7SJan Svoboda   return ModuleMapFiles;
31920fa87c7SJan Svoboda }
32020fa87c7SJan Svoboda 
321c0a55121SBen Langmuir void ModuleDepCollector::addModuleMapFiles(
322c0a55121SBen Langmuir     CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
323c0a55121SBen Langmuir   if (EagerLoadModules)
324c0a55121SBen Langmuir     return; // Only pcm is needed for eager load.
325c0a55121SBen Langmuir 
326c0a55121SBen Langmuir   for (const ModuleID &MID : ClangModuleDeps) {
327c0a55121SBen Langmuir     ModuleDeps *MD = ModuleDepsByID.lookup(MID);
328c0a55121SBen Langmuir     assert(MD && "Inconsistent dependency info");
329c0a55121SBen Langmuir     CI.getFrontendOpts().ModuleMapFiles.push_back(MD->ClangModuleMapFile);
330c0a55121SBen Langmuir   }
331c0a55121SBen Langmuir }
332c0a55121SBen Langmuir 
333c0a55121SBen Langmuir void ModuleDepCollector::addModuleFiles(
334c0a55121SBen Langmuir     CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
335c0a55121SBen Langmuir   for (const ModuleID &MID : ClangModuleDeps) {
336c0a55121SBen Langmuir     std::string PCMPath =
337296ba5bbSBen Langmuir         Controller.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile);
338c0a55121SBen Langmuir     if (EagerLoadModules)
339c0a55121SBen Langmuir       CI.getFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
340c0a55121SBen Langmuir     else
341c0a55121SBen Langmuir       CI.getHeaderSearchOpts().PrebuiltModuleFiles.insert(
342c0a55121SBen Langmuir           {MID.ModuleName, std::move(PCMPath)});
343c0a55121SBen Langmuir   }
344c0a55121SBen Langmuir }
345c0a55121SBen Langmuir 
3469208065aSJan Svoboda void ModuleDepCollector::addModuleFiles(
3479208065aSJan Svoboda     CowCompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
3489208065aSJan Svoboda   for (const ModuleID &MID : ClangModuleDeps) {
3499208065aSJan Svoboda     std::string PCMPath =
3509208065aSJan Svoboda         Controller.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile);
3519208065aSJan Svoboda     if (EagerLoadModules)
3529208065aSJan Svoboda       CI.getMutFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
3539208065aSJan Svoboda     else
3549208065aSJan Svoboda       CI.getMutHeaderSearchOpts().PrebuiltModuleFiles.insert(
3559208065aSJan Svoboda           {MID.ModuleName, std::move(PCMPath)});
3569208065aSJan Svoboda   }
3579208065aSJan Svoboda }
3589208065aSJan Svoboda 
35983902c40SBen Langmuir static bool needsModules(FrontendInputFile FIF) {
36083902c40SBen Langmuir   switch (FIF.getKind().getLanguage()) {
36183902c40SBen Langmuir   case Language::Unknown:
36283902c40SBen Langmuir   case Language::Asm:
36383902c40SBen Langmuir   case Language::LLVM_IR:
36483902c40SBen Langmuir     return false;
36583902c40SBen Langmuir   default:
36683902c40SBen Langmuir     return true;
36783902c40SBen Langmuir   }
36883902c40SBen Langmuir }
36983902c40SBen Langmuir 
37083902c40SBen Langmuir void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) {
37183902c40SBen Langmuir   CI.clearImplicitModuleBuildOptions();
37263310243SArgyrios Kyrtzidis   resetBenignCodeGenOptions(CI.getFrontendOpts().ProgramAction,
37363310243SArgyrios Kyrtzidis                             CI.getLangOpts(), CI.getCodeGenOpts());
37483902c40SBen Langmuir 
37583902c40SBen Langmuir   if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) {
3769dc0b167SJan Svoboda     Preprocessor &PP = ScanInstance.getPreprocessor();
3779dc0b167SJan Svoboda     if (Module *CurrentModule = PP.getCurrentModuleImplementation())
378854c10f8SBenjamin Kramer       if (OptionalFileEntryRef CurrentModuleMap =
3799dc0b167SJan Svoboda               PP.getHeaderSearchInfo()
3809dc0b167SJan Svoboda                   .getModuleMap()
3819dc0b167SJan Svoboda                   .getModuleMapFileForUniquing(CurrentModule))
3829dc0b167SJan Svoboda         CI.getFrontendOpts().ModuleMapFiles.emplace_back(
38373dba2f6SBen Langmuir             CurrentModuleMap->getNameAsRequested());
3849dc0b167SJan Svoboda 
38583902c40SBen Langmuir     SmallVector<ModuleID> DirectDeps;
38683902c40SBen Langmuir     for (const auto &KV : ModularDeps)
387c75b331fSJan Svoboda       if (DirectModularDeps.contains(KV.first))
38883902c40SBen Langmuir         DirectDeps.push_back(KV.second->ID);
38983902c40SBen Langmuir 
39020fa87c7SJan Svoboda     // TODO: Report module maps the same way it's done for modular dependencies.
39183902c40SBen Langmuir     addModuleMapFiles(CI, DirectDeps);
39220fa87c7SJan Svoboda 
39383902c40SBen Langmuir     addModuleFiles(CI, DirectDeps);
39483902c40SBen Langmuir 
39583902c40SBen Langmuir     for (const auto &KV : DirectPrebuiltModularDeps)
39683902c40SBen Langmuir       CI.getFrontendOpts().ModuleFiles.push_back(KV.second.PCMFile);
39783902c40SBen Langmuir   }
39883902c40SBen Langmuir }
39983902c40SBen Langmuir 
400be795ee1SJan Svoboda static std::string getModuleContextHash(const ModuleDeps &MD,
4019208065aSJan Svoboda                                         const CowCompilerInvocation &CI,
40213386c60SMichael Spencer                                         bool EagerLoadModules,
40313386c60SMichael Spencer                                         llvm::vfs::FileSystem &VFS) {
404d7b18d50SKazu Hirata   llvm::HashBuilder<llvm::TruncatedBLAKE3<16>, llvm::endianness::native>
40502871701SBen Langmuir       HashBuilder;
40602871701SBen Langmuir   SmallString<32> Scratch;
40702871701SBen Langmuir 
40802871701SBen Langmuir   // Hash the compiler version and serialization version to ensure the module
40902871701SBen Langmuir   // will be readable.
41002871701SBen Langmuir   HashBuilder.add(getClangFullRepositoryVersion());
41102871701SBen Langmuir   HashBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR);
41213386c60SMichael Spencer   llvm::ErrorOr<std::string> CWD = VFS.getCurrentWorkingDirectory();
41313386c60SMichael Spencer   if (CWD)
41413386c60SMichael Spencer     HashBuilder.add(*CWD);
41502871701SBen Langmuir 
41602871701SBen Langmuir   // Hash the BuildInvocation without any input files.
4178fd56ea1SJan Svoboda   SmallString<0> ArgVec;
4188fd56ea1SJan Svoboda   ArgVec.reserve(4096);
4198fd56ea1SJan Svoboda   CI.generateCC1CommandLine([&](const Twine &Arg) {
4208fd56ea1SJan Svoboda     Arg.toVector(ArgVec);
4218fd56ea1SJan Svoboda     ArgVec.push_back('\0');
4228fd56ea1SJan Svoboda   });
4238fd56ea1SJan Svoboda   HashBuilder.add(ArgVec);
42402871701SBen Langmuir 
4255482432bSBen Langmuir   // Hash the module dependencies. These paths may differ even if the invocation
4265482432bSBen Langmuir   // is identical if they depend on the contents of the files in the TU -- for
4275482432bSBen Langmuir   // example, case-insensitive paths to modulemap files. Usually such a case
4285482432bSBen Langmuir   // would indicate a missed optimization to canonicalize, but it may be
4295482432bSBen Langmuir   // difficult to canonicalize all cases when there is a VFS.
43002871701SBen Langmuir   for (const auto &ID : MD.ClangModuleDeps) {
43102871701SBen Langmuir     HashBuilder.add(ID.ModuleName);
43202871701SBen Langmuir     HashBuilder.add(ID.ContextHash);
43302871701SBen Langmuir   }
43402871701SBen Langmuir 
435be795ee1SJan Svoboda   HashBuilder.add(EagerLoadModules);
436be795ee1SJan Svoboda 
43702871701SBen Langmuir   llvm::BLAKE3Result<16> Hash = HashBuilder.final();
43802871701SBen Langmuir   std::array<uint64_t, 2> Words;
43902871701SBen Langmuir   static_assert(sizeof(Hash) == sizeof(Words), "Hash must match Words");
44002871701SBen Langmuir   std::memcpy(Words.data(), Hash.data(), sizeof(Hash));
44102871701SBen Langmuir   return toString(llvm::APInt(sizeof(Words) * 8, Words), 36, /*Signed=*/false);
44202871701SBen Langmuir }
44302871701SBen Langmuir 
4449208065aSJan Svoboda void ModuleDepCollector::associateWithContextHash(
4459208065aSJan Svoboda     const CowCompilerInvocation &CI, ModuleDeps &Deps) {
44613386c60SMichael Spencer   Deps.ID.ContextHash = getModuleContextHash(
44713386c60SMichael Spencer       Deps, CI, EagerLoadModules, ScanInstance.getVirtualFileSystem());
448c0a55121SBen Langmuir   bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second;
449c0a55121SBen Langmuir   (void)Inserted;
450c0a55121SBen Langmuir   assert(Inserted && "duplicate module mapping");
451c0a55121SBen Langmuir }
452c0a55121SBen Langmuir 
4538711120eSBen Langmuir void ModuleDepCollectorPP::LexedFileChanged(FileID FID,
4548711120eSBen Langmuir                                             LexedFileChangeReason Reason,
45533a745e6SMichael Spencer                                             SrcMgr::CharacteristicKind FileType,
4568711120eSBen Langmuir                                             FileID PrevFID,
4578711120eSBen Langmuir                                             SourceLocation Loc) {
4588711120eSBen Langmuir   if (Reason != LexedFileChangeReason::EnterFile)
45933a745e6SMichael Spencer     return;
46033a745e6SMichael Spencer 
461356a4b43SMichael Spencer   // This has to be delayed as the context hash can change at the start of
462356a4b43SMichael Spencer   // `CompilerInstance::ExecuteAction`.
463356a4b43SMichael Spencer   if (MDC.ContextHash.empty()) {
464207e9fdeSJan Svoboda     MDC.ContextHash = MDC.ScanInstance.getInvocation().getModuleHash();
465356a4b43SMichael Spencer     MDC.Consumer.handleContextHash(MDC.ContextHash);
466356a4b43SMichael Spencer   }
467356a4b43SMichael Spencer 
468207e9fdeSJan Svoboda   SourceManager &SM = MDC.ScanInstance.getSourceManager();
46933a745e6SMichael Spencer 
47033a745e6SMichael Spencer   // Dependency generation really does want to go all the way to the
47133a745e6SMichael Spencer   // file entry for a source location to find out what is depended on.
47233a745e6SMichael Spencer   // We do not want #line markers to affect dependency generation!
4738711120eSBen Langmuir   if (std::optional<StringRef> Filename = SM.getNonBuiltinFilenameForID(FID))
474b4c6dc2eSBen Langmuir     MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*Filename));
47533a745e6SMichael Spencer }
47633a745e6SMichael Spencer 
47733a745e6SMichael Spencer void ModuleDepCollectorPP::InclusionDirective(
47833a745e6SMichael Spencer     SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
479854c10f8SBenjamin Kramer     bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
480da95d926SJan Svoboda     StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
481da95d926SJan Svoboda     bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
482da95d926SJan Svoboda   if (!File && !ModuleImported) {
48333a745e6SMichael Spencer     // This is a non-modular include that HeaderSearch failed to find. Add it
48433a745e6SMichael Spencer     // here as `FileChanged` will never see it.
485b4c6dc2eSBen Langmuir     MDC.addFileDep(FileName);
48633a745e6SMichael Spencer   }
487da95d926SJan Svoboda   handleImport(SuggestedModule);
488356a4b43SMichael Spencer }
48933a745e6SMichael Spencer 
490356a4b43SMichael Spencer void ModuleDepCollectorPP::moduleImport(SourceLocation ImportLoc,
491356a4b43SMichael Spencer                                         ModuleIdPath Path,
492356a4b43SMichael Spencer                                         const Module *Imported) {
493eb70b38fSChuanqi Xu   if (MDC.ScanInstance.getPreprocessor().isInImportingCXXNamedModules()) {
494eb70b38fSChuanqi Xu     P1689ModuleInfo RequiredModule;
495eb70b38fSChuanqi Xu     RequiredModule.ModuleName = Path[0].first->getName().str();
496eb70b38fSChuanqi Xu     RequiredModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule;
497eb70b38fSChuanqi Xu     MDC.RequiredStdCXXModules.push_back(RequiredModule);
498eb70b38fSChuanqi Xu     return;
499eb70b38fSChuanqi Xu   }
500eb70b38fSChuanqi Xu 
501356a4b43SMichael Spencer   handleImport(Imported);
502356a4b43SMichael Spencer }
503356a4b43SMichael Spencer 
504356a4b43SMichael Spencer void ModuleDepCollectorPP::handleImport(const Module *Imported) {
50533a745e6SMichael Spencer   if (!Imported)
50633a745e6SMichael Spencer     return;
50733a745e6SMichael Spencer 
508772e9f88SJan Svoboda   const Module *TopLevelModule = Imported->getTopLevelModule();
5094629554fSJan Svoboda 
5104629554fSJan Svoboda   if (MDC.isPrebuiltModule(TopLevelModule))
511c0a55121SBen Langmuir     MDC.DirectPrebuiltModularDeps.insert(
512c0a55121SBen Langmuir         {TopLevelModule, PrebuiltModuleDep{TopLevelModule}});
5134629554fSJan Svoboda   else
514c75b331fSJan Svoboda     MDC.DirectModularDeps.insert(TopLevelModule);
51533a745e6SMichael Spencer }
51633a745e6SMichael Spencer 
51733a745e6SMichael Spencer void ModuleDepCollectorPP::EndOfMainFile() {
518207e9fdeSJan Svoboda   FileID MainFileID = MDC.ScanInstance.getSourceManager().getMainFileID();
519207e9fdeSJan Svoboda   MDC.MainFile = std::string(MDC.ScanInstance.getSourceManager()
520b19fe81eSJan Svoboda                                  .getFileEntryRefForID(MainFileID)
521207e9fdeSJan Svoboda                                  ->getName());
52233a745e6SMichael Spencer 
523eb70b38fSChuanqi Xu   auto &PP = MDC.ScanInstance.getPreprocessor();
524eb70b38fSChuanqi Xu   if (PP.isInNamedModule()) {
525eb70b38fSChuanqi Xu     P1689ModuleInfo ProvidedModule;
526eb70b38fSChuanqi Xu     ProvidedModule.ModuleName = PP.getNamedModuleName();
527eb70b38fSChuanqi Xu     ProvidedModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule;
528eb70b38fSChuanqi Xu     ProvidedModule.IsStdCXXModuleInterface = PP.isInNamedInterfaceUnit();
529eb70b38fSChuanqi Xu     // Don't put implementation (non partition) unit as Provide.
530eb70b38fSChuanqi Xu     // Put the module as required instead. Since the implementation
531eb70b38fSChuanqi Xu     // unit will import the primary module implicitly.
532eb70b38fSChuanqi Xu     if (PP.isInImplementationUnit())
533eb70b38fSChuanqi Xu       MDC.RequiredStdCXXModules.push_back(ProvidedModule);
534eb70b38fSChuanqi Xu     else
535eb70b38fSChuanqi Xu       MDC.ProvidedStdCXXModule = ProvidedModule;
536eb70b38fSChuanqi Xu   }
537eb70b38fSChuanqi Xu 
538207e9fdeSJan Svoboda   if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
539b4c6dc2eSBen Langmuir     MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude);
5409223209bSJan Svoboda 
541002bfdd6SJan Svoboda   for (const Module *M :
542e8541e4bSChuanqi Xu        MDC.ScanInstance.getPreprocessor().getAffectingClangModules())
543002bfdd6SJan Svoboda     if (!MDC.isPrebuiltModule(M))
544c75b331fSJan Svoboda       MDC.DirectModularDeps.insert(M);
545002bfdd6SJan Svoboda 
546c75b331fSJan Svoboda   for (const Module *M : MDC.DirectModularDeps)
54733a745e6SMichael Spencer     handleTopLevelModule(M);
54833a745e6SMichael Spencer 
549f95ff816SJan Svoboda   MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts);
550f95ff816SJan Svoboda 
551eb70b38fSChuanqi Xu   if (MDC.IsStdModuleP1689Format)
552eb70b38fSChuanqi Xu     MDC.Consumer.handleProvidedAndRequiredStdCXXModules(
553eb70b38fSChuanqi Xu         MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules);
554eb70b38fSChuanqi Xu 
555772e9f88SJan Svoboda   for (auto &&I : MDC.ModularDeps)
556835fcf2aSBen Langmuir     MDC.Consumer.handleModuleDependency(*I.second);
55733a745e6SMichael Spencer 
558c75b331fSJan Svoboda   for (const Module *M : MDC.DirectModularDeps) {
559c75b331fSJan Svoboda     auto It = MDC.ModularDeps.find(M);
560c75b331fSJan Svoboda     // Only report direct dependencies that were successfully handled.
561c75b331fSJan Svoboda     if (It != MDC.ModularDeps.end())
562c7895f0dSKazu Hirata       MDC.Consumer.handleDirectModuleDependency(It->second->ID);
563c75b331fSJan Svoboda   }
564c75b331fSJan Svoboda 
565772e9f88SJan Svoboda   for (auto &&I : MDC.FileDeps)
566f95ff816SJan Svoboda     MDC.Consumer.handleFileDependency(I);
5674629554fSJan Svoboda 
568c0a55121SBen Langmuir   for (auto &&I : MDC.DirectPrebuiltModularDeps)
569c0a55121SBen Langmuir     MDC.Consumer.handlePrebuiltModuleDependency(I.second);
57033a745e6SMichael Spencer }
57133a745e6SMichael Spencer 
57296a54b22SJan Svoboda std::optional<ModuleID>
57396a54b22SJan Svoboda ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
57433a745e6SMichael Spencer   assert(M == M->getTopLevelModule() && "Expected top level module!");
57533a745e6SMichael Spencer 
57696a54b22SJan Svoboda   // A top-level module might not be actually imported as a module when
57796a54b22SJan Svoboda   // -fmodule-name is used to compile a translation unit that imports this
57896a54b22SJan Svoboda   // module. In that case it can be skipped. The appropriate header
57996a54b22SJan Svoboda   // dependencies will still be reported as expected.
58096a54b22SJan Svoboda   if (!M->getASTFile())
58196a54b22SJan Svoboda     return {};
58296a54b22SJan Svoboda 
583b9d5b0c2SJan Svoboda   // If this module has been handled already, just return its ID.
5845acd9d11SJan Svoboda   if (auto ModI = MDC.ModularDeps.find(M); ModI != MDC.ModularDeps.end())
5855acd9d11SJan Svoboda     return ModI->second->ID;
58633a745e6SMichael Spencer 
5875acd9d11SJan Svoboda   auto OwnedMD = std::make_unique<ModuleDeps>();
5885acd9d11SJan Svoboda   ModuleDeps &MD = *OwnedMD;
58933a745e6SMichael Spencer 
590b9d5b0c2SJan Svoboda   MD.ID.ModuleName = M->getFullModuleName();
591b9d5b0c2SJan Svoboda   MD.IsSystem = M->IsSystem;
59268eb3b20SArtem Chikin   // For modules which use export_as link name, the linked product that of the
59368eb3b20SArtem Chikin   // corresponding export_as-named module.
59468eb3b20SArtem Chikin   if (!M->UseExportAsModuleLinkName)
59568eb3b20SArtem Chikin     MD.LinkLibraries = M->LinkLibraries;
596b9d5b0c2SJan Svoboda 
597074fcec1SBen Langmuir   ModuleMap &ModMapInfo =
598074fcec1SBen Langmuir       MDC.ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
599074fcec1SBen Langmuir 
600da1a16aeSJan Svoboda   if (auto ModuleMap = ModMapInfo.getModuleMapFileForUniquing(M)) {
601074fcec1SBen Langmuir     SmallString<128> Path = ModuleMap->getNameAsRequested();
602074fcec1SBen Langmuir     ModMapInfo.canonicalizeModuleMapPath(Path);
60337e6e022SMichael Spencer     MD.ClangModuleMapFile = std::string(Path);
60437e6e022SMichael Spencer   }
605b9d5b0c2SJan Svoboda 
60633a745e6SMichael Spencer   serialization::ModuleFile *MF =
607207e9fdeSJan Svoboda       MDC.ScanInstance.getASTReader()->getModuleManager().lookup(
6080cb0a48cSJan Svoboda           *M->getASTFile());
609*9d4837f4SJan Svoboda   MD.FileDepsBaseDir = MF->BaseDirectory;
610dcd3a0c9SJan Svoboda   MDC.ScanInstance.getASTReader()->visitInputFileInfos(
611dcd3a0c9SJan Svoboda       *MF, /*IncludeSystem=*/true,
612dcd3a0c9SJan Svoboda       [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
613da1a16aeSJan Svoboda         // The __inferred_module.map file is an insignificant implementation
614da1a16aeSJan Svoboda         // detail of implicitly-built modules. The PCM will also report the
615da1a16aeSJan Svoboda         // actual on-disk module map file that allowed inferring the module,
616da1a16aeSJan Svoboda         // which is what we need for building the module explicitly
617da1a16aeSJan Svoboda         // Let's ignore this file.
618*9d4837f4SJan Svoboda         if (IFI.UnresolvedImportedFilename.ends_with("__inferred_module.map"))
6197defab08SMichael Spencer           return;
620*9d4837f4SJan Svoboda         MDC.addFileDep(MD, IFI.UnresolvedImportedFilename);
62133a745e6SMichael Spencer       });
62233a745e6SMichael Spencer 
623f35230aeSJan Svoboda   llvm::DenseSet<const Module *> SeenDeps;
624f35230aeSJan Svoboda   addAllSubmodulePrebuiltDeps(M, MD, SeenDeps);
625f35230aeSJan Svoboda   addAllSubmoduleDeps(M, MD, SeenDeps);
626e8541e4bSChuanqi Xu   addAllAffectingClangModules(M, MD, SeenDeps);
627f35230aeSJan Svoboda 
628*9d4837f4SJan Svoboda   SmallString<0> PathBuf;
629*9d4837f4SJan Svoboda   PathBuf.reserve(256);
630dcd3a0c9SJan Svoboda   MDC.ScanInstance.getASTReader()->visitInputFileInfos(
631dcd3a0c9SJan Svoboda       *MF, /*IncludeSystem=*/true,
632dcd3a0c9SJan Svoboda       [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
633dcd3a0c9SJan Svoboda         if (!(IFI.TopLevel && IFI.ModuleMap))
634a6ef3635SJan Svoboda           return;
635*9d4837f4SJan Svoboda         if (IFI.UnresolvedImportedFilenameAsRequested.ends_with(
636*9d4837f4SJan Svoboda                 "__inferred_module.map"))
637dcd3a0c9SJan Svoboda           return;
638*9d4837f4SJan Svoboda         auto ResolvedFilenameAsRequested = ASTReader::ResolveImportedPath(
639*9d4837f4SJan Svoboda             PathBuf, IFI.UnresolvedImportedFilenameAsRequested,
640*9d4837f4SJan Svoboda             MF->BaseDirectory);
641*9d4837f4SJan Svoboda         MD.ModuleMapFileDeps.emplace_back(*ResolvedFilenameAsRequested);
642a6ef3635SJan Svoboda       });
6434629554fSJan Svoboda 
6449208065aSJan Svoboda   CowCompilerInvocation CI =
6459208065aSJan Svoboda       MDC.getInvocationAdjustedForModuleBuildWithoutOutputs(
6469208065aSJan Svoboda           MD, [&](CowCompilerInvocation &BuildInvocation) {
6477847e445SMichael Spencer             if (any(MDC.OptimizeArgs & (ScanningOptimizations::HeaderSearch |
6487847e445SMichael Spencer                                         ScanningOptimizations::VFS)))
6499208065aSJan Svoboda               optimizeHeaderSearchOpts(BuildInvocation.getMutHeaderSearchOpts(),
6507847e445SMichael Spencer                                        *MDC.ScanInstance.getASTReader(), *MF,
651de3b2c29SMichael Spencer                                        MDC.PrebuiltModuleVFSMap,
6527847e445SMichael Spencer                                        MDC.OptimizeArgs);
653731152e1SMichael Spencer             if (any(MDC.OptimizeArgs & ScanningOptimizations::SystemWarnings))
654731152e1SMichael Spencer               optimizeDiagnosticOpts(
655731152e1SMichael Spencer                   BuildInvocation.getMutDiagnosticOpts(),
656731152e1SMichael Spencer                   BuildInvocation.getFrontendOpts().IsSystemModule);
6576a1f50b8SJan Svoboda           });
658b9d5b0c2SJan Svoboda 
659c0a55121SBen Langmuir   MDC.associateWithContextHash(CI, MD);
660c0a55121SBen Langmuir 
6615482432bSBen Langmuir   // Finish the compiler invocation. Requires dependencies and the context hash.
662e8febb23SBen Langmuir   MDC.addOutputPaths(CI, MD);
663e8febb23SBen Langmuir 
6643b1a6865SJan Svoboda   MD.BuildInfo = std::move(CI);
665e8febb23SBen Langmuir 
6665acd9d11SJan Svoboda   MDC.ModularDeps.insert({M, std::move(OwnedMD)});
6675acd9d11SJan Svoboda 
668b9d5b0c2SJan Svoboda   return MD.ID;
66933a745e6SMichael Spencer }
67033a745e6SMichael Spencer 
6714a3a9a5fSBen Langmuir static void forEachSubmoduleSorted(const Module *M,
6724a3a9a5fSBen Langmuir                                    llvm::function_ref<void(const Module *)> F) {
6734a3a9a5fSBen Langmuir   // Submodule order depends on order of header includes for inferred submodules
6744a3a9a5fSBen Langmuir   // we don't care about the exact order, so sort so that it's consistent across
6754a3a9a5fSBen Langmuir   // TUs to improve sharing.
67640136eceSStoorx   SmallVector<const Module *> Submodules(M->submodules());
6774a3a9a5fSBen Langmuir   llvm::stable_sort(Submodules, [](const Module *A, const Module *B) {
6784a3a9a5fSBen Langmuir     return A->Name < B->Name;
6794a3a9a5fSBen Langmuir   });
6804a3a9a5fSBen Langmuir   for (const Module *SubM : Submodules)
6814a3a9a5fSBen Langmuir     F(SubM);
6824a3a9a5fSBen Langmuir }
6834a3a9a5fSBen Langmuir 
68483c633eaSJan Svoboda void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps(
68583c633eaSJan Svoboda     const Module *M, ModuleDeps &MD,
68683c633eaSJan Svoboda     llvm::DenseSet<const Module *> &SeenSubmodules) {
68783c633eaSJan Svoboda   addModulePrebuiltDeps(M, MD, SeenSubmodules);
68883c633eaSJan Svoboda 
6894a3a9a5fSBen Langmuir   forEachSubmoduleSorted(M, [&](const Module *SubM) {
69083c633eaSJan Svoboda     addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules);
6914a3a9a5fSBen Langmuir   });
69283c633eaSJan Svoboda }
69383c633eaSJan Svoboda 
69483c633eaSJan Svoboda void ModuleDepCollectorPP::addModulePrebuiltDeps(
69583c633eaSJan Svoboda     const Module *M, ModuleDeps &MD,
69683c633eaSJan Svoboda     llvm::DenseSet<const Module *> &SeenSubmodules) {
6974629554fSJan Svoboda   for (const Module *Import : M->Imports)
6984629554fSJan Svoboda     if (Import->getTopLevelModule() != M->getTopLevelModule())
6993b8f536fSJan Svoboda       if (MDC.isPrebuiltModule(Import->getTopLevelModule()))
7003b8f536fSJan Svoboda         if (SeenSubmodules.insert(Import->getTopLevelModule()).second)
7013b8f536fSJan Svoboda           MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule());
7024629554fSJan Svoboda }
7034629554fSJan Svoboda 
704356a4b43SMichael Spencer void ModuleDepCollectorPP::addAllSubmoduleDeps(
705356a4b43SMichael Spencer     const Module *M, ModuleDeps &MD,
706356a4b43SMichael Spencer     llvm::DenseSet<const Module *> &AddedModules) {
707356a4b43SMichael Spencer   addModuleDep(M, MD, AddedModules);
70833a745e6SMichael Spencer 
7094a3a9a5fSBen Langmuir   forEachSubmoduleSorted(M, [&](const Module *SubM) {
710356a4b43SMichael Spencer     addAllSubmoduleDeps(SubM, MD, AddedModules);
7114a3a9a5fSBen Langmuir   });
71233a745e6SMichael Spencer }
71333a745e6SMichael Spencer 
714356a4b43SMichael Spencer void ModuleDepCollectorPP::addModuleDep(
715356a4b43SMichael Spencer     const Module *M, ModuleDeps &MD,
716356a4b43SMichael Spencer     llvm::DenseSet<const Module *> &AddedModules) {
71733a745e6SMichael Spencer   for (const Module *Import : M->Imports) {
7184629554fSJan Svoboda     if (Import->getTopLevelModule() != M->getTopLevelModule() &&
7194629554fSJan Svoboda         !MDC.isPrebuiltModule(Import)) {
72096a54b22SJan Svoboda       if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule()))
721356a4b43SMichael Spencer         if (AddedModules.insert(Import->getTopLevelModule()).second)
72296a54b22SJan Svoboda           MD.ClangModuleDeps.push_back(*ImportID);
72333a745e6SMichael Spencer     }
72433a745e6SMichael Spencer   }
72533a745e6SMichael Spencer }
72633a745e6SMichael Spencer 
727e8541e4bSChuanqi Xu void ModuleDepCollectorPP::addAllAffectingClangModules(
728002bfdd6SJan Svoboda     const Module *M, ModuleDeps &MD,
729002bfdd6SJan Svoboda     llvm::DenseSet<const Module *> &AddedModules) {
730e8541e4bSChuanqi Xu   addAffectingClangModule(M, MD, AddedModules);
731002bfdd6SJan Svoboda 
732002bfdd6SJan Svoboda   for (const Module *SubM : M->submodules())
733e8541e4bSChuanqi Xu     addAllAffectingClangModules(SubM, MD, AddedModules);
734002bfdd6SJan Svoboda }
735002bfdd6SJan Svoboda 
736e8541e4bSChuanqi Xu void ModuleDepCollectorPP::addAffectingClangModule(
737002bfdd6SJan Svoboda     const Module *M, ModuleDeps &MD,
738002bfdd6SJan Svoboda     llvm::DenseSet<const Module *> &AddedModules) {
739e8541e4bSChuanqi Xu   for (const Module *Affecting : M->AffectingClangModules) {
740002bfdd6SJan Svoboda     assert(Affecting == Affecting->getTopLevelModule() &&
741002bfdd6SJan Svoboda            "Not quite import not top-level module");
742002bfdd6SJan Svoboda     if (Affecting != M->getTopLevelModule() &&
743002bfdd6SJan Svoboda         !MDC.isPrebuiltModule(Affecting)) {
74496a54b22SJan Svoboda       if (auto ImportID = handleTopLevelModule(Affecting))
745002bfdd6SJan Svoboda         if (AddedModules.insert(Affecting).second)
74696a54b22SJan Svoboda           MD.ClangModuleDeps.push_back(*ImportID);
747002bfdd6SJan Svoboda     }
748002bfdd6SJan Svoboda   }
749002bfdd6SJan Svoboda }
750002bfdd6SJan Svoboda 
751356a4b43SMichael Spencer ModuleDepCollector::ModuleDepCollector(
752207e9fdeSJan Svoboda     std::unique_ptr<DependencyOutputOptions> Opts,
753207e9fdeSJan Svoboda     CompilerInstance &ScanInstance, DependencyConsumer &C,
754296ba5bbSBen Langmuir     DependencyActionController &Controller, CompilerInvocation OriginalCI,
755de3b2c29SMichael Spencer     PrebuiltModuleVFSMapT PrebuiltModuleVFSMap,
756fb07d9ccSMichael Spencer     ScanningOptimizations OptimizeArgs, bool EagerLoadModules,
757fb07d9ccSMichael Spencer     bool IsStdModuleP1689Format)
758296ba5bbSBen Langmuir     : ScanInstance(ScanInstance), Consumer(C), Controller(Controller),
759de3b2c29SMichael Spencer       PrebuiltModuleVFSMap(std::move(PrebuiltModuleVFSMap)),
7609208065aSJan Svoboda       Opts(std::move(Opts)),
7619208065aSJan Svoboda       CommonInvocation(
7629208065aSJan Svoboda           makeCommonInvocationForModuleBuild(std::move(OriginalCI))),
763296ba5bbSBen Langmuir       OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules),
764eb70b38fSChuanqi Xu       IsStdModuleP1689Format(IsStdModuleP1689Format) {}
76533a745e6SMichael Spencer 
76633a745e6SMichael Spencer void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) {
76724616664SJan Svoboda   PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this));
76833a745e6SMichael Spencer }
76933a745e6SMichael Spencer 
77033a745e6SMichael Spencer void ModuleDepCollector::attachToASTReader(ASTReader &R) {}
7714629554fSJan Svoboda 
7724629554fSJan Svoboda bool ModuleDepCollector::isPrebuiltModule(const Module *M) {
7734629554fSJan Svoboda   std::string Name(M->getTopLevelModuleName());
7744629554fSJan Svoboda   const auto &PrebuiltModuleFiles =
775207e9fdeSJan Svoboda       ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles;
7764629554fSJan Svoboda   auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name);
7774629554fSJan Svoboda   if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end())
7784629554fSJan Svoboda     return false;
7794629554fSJan Svoboda   assert("Prebuilt module came from the expected AST file" &&
7804629554fSJan Svoboda          PrebuiltModuleFileIt->second == M->getASTFile()->getName());
7814629554fSJan Svoboda   return true;
7824629554fSJan Svoboda }
783b4c6dc2eSBen Langmuir 
7848ab388e1SJan Svoboda static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path,
785b4c6dc2eSBen Langmuir                                           SmallVectorImpl<char> &Storage) {
7864d6483e9SJan Svoboda   if (llvm::sys::path::is_absolute(Path) &&
7874d6483e9SJan Svoboda       !llvm::sys::path::is_style_windows(llvm::sys::path::Style::native))
788b4c6dc2eSBen Langmuir     return Path;
789b4c6dc2eSBen Langmuir   Storage.assign(Path.begin(), Path.end());
790b4c6dc2eSBen Langmuir   CI.getFileManager().makeAbsolutePath(Storage);
7918ab388e1SJan Svoboda   llvm::sys::path::make_preferred(Storage);
792b4c6dc2eSBen Langmuir   return StringRef(Storage.data(), Storage.size());
793b4c6dc2eSBen Langmuir }
794b4c6dc2eSBen Langmuir 
795b4c6dc2eSBen Langmuir void ModuleDepCollector::addFileDep(StringRef Path) {
796e107c946SChuanqi Xu   if (IsStdModuleP1689Format) {
797e107c946SChuanqi Xu     // Within P1689 format, we don't want all the paths to be absolute path
798*9d4837f4SJan Svoboda     // since it may violate the traditional make style dependencies info.
799*9d4837f4SJan Svoboda     FileDeps.emplace_back(Path);
800e107c946SChuanqi Xu     return;
801e107c946SChuanqi Xu   }
802e107c946SChuanqi Xu 
803b4c6dc2eSBen Langmuir   llvm::SmallString<256> Storage;
8048ab388e1SJan Svoboda   Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
805*9d4837f4SJan Svoboda   FileDeps.emplace_back(Path);
806b4c6dc2eSBen Langmuir }
807b4c6dc2eSBen Langmuir 
808b4c6dc2eSBen Langmuir void ModuleDepCollector::addFileDep(ModuleDeps &MD, StringRef Path) {
809*9d4837f4SJan Svoboda   MD.FileDeps.emplace_back(Path);
810b4c6dc2eSBen Langmuir }
811