xref: /freebsd-src/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1480093f4SDimitry Andric //===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ -*-===//
2480093f4SDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric 
9480093f4SDimitry Andric #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
10480093f4SDimitry Andric 
11753f127fSDimitry Andric #include "clang/Basic/MakeSupport.h"
12480093f4SDimitry Andric #include "clang/Frontend/CompilerInstance.h"
13480093f4SDimitry Andric #include "clang/Lex/Preprocessor.h"
14480093f4SDimitry Andric #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
155f757f3fSDimitry Andric #include "llvm/ADT/STLExtras.h"
16bdd1243dSDimitry Andric #include "llvm/Support/BLAKE3.h"
17fe6060f1SDimitry Andric #include "llvm/Support/StringSaver.h"
18bdd1243dSDimitry Andric #include <optional>
19480093f4SDimitry Andric 
20480093f4SDimitry Andric using namespace clang;
21480093f4SDimitry Andric using namespace tooling;
22480093f4SDimitry Andric using namespace dependencies;
23480093f4SDimitry Andric 
245f757f3fSDimitry Andric const std::vector<std::string> &ModuleDeps::getBuildArguments() {
255f757f3fSDimitry Andric   assert(!std::holds_alternative<std::monostate>(BuildInfo) &&
265f757f3fSDimitry Andric          "Using uninitialized ModuleDeps");
275f757f3fSDimitry Andric   if (const auto *CI = std::get_if<CowCompilerInvocation>(&BuildInfo))
285f757f3fSDimitry Andric     BuildInfo = CI->getCC1CommandLine();
295f757f3fSDimitry Andric   return std::get<std::vector<std::string>>(BuildInfo);
305f757f3fSDimitry Andric }
315f757f3fSDimitry Andric 
32*0fca6ea1SDimitry Andric static void
33*0fca6ea1SDimitry Andric optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, ASTReader &Reader,
34*0fca6ea1SDimitry Andric                          const serialization::ModuleFile &MF,
35*0fca6ea1SDimitry Andric                          const PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap,
36*0fca6ea1SDimitry Andric                          ScanningOptimizations OptimizeArgs) {
37*0fca6ea1SDimitry Andric   if (any(OptimizeArgs & ScanningOptimizations::HeaderSearch)) {
38349cc55cSDimitry Andric     // Only preserve search paths that were used during the dependency scan.
39*0fca6ea1SDimitry Andric     std::vector<HeaderSearchOptions::Entry> Entries;
40*0fca6ea1SDimitry Andric     std::swap(Opts.UserEntries, Entries);
4181ad6265SDimitry Andric 
4281ad6265SDimitry Andric     llvm::BitVector SearchPathUsage(Entries.size());
4381ad6265SDimitry Andric     llvm::DenseSet<const serialization::ModuleFile *> Visited;
4481ad6265SDimitry Andric     std::function<void(const serialization::ModuleFile *)> VisitMF =
4581ad6265SDimitry Andric         [&](const serialization::ModuleFile *MF) {
4681ad6265SDimitry Andric           SearchPathUsage |= MF->SearchPathUsage;
4781ad6265SDimitry Andric           Visited.insert(MF);
4881ad6265SDimitry Andric           for (const serialization::ModuleFile *Import : MF->Imports)
4981ad6265SDimitry Andric             if (!Visited.contains(Import))
5081ad6265SDimitry Andric               VisitMF(Import);
5181ad6265SDimitry Andric         };
5281ad6265SDimitry Andric     VisitMF(&MF);
5381ad6265SDimitry Andric 
54*0fca6ea1SDimitry Andric     if (SearchPathUsage.size() != Entries.size())
55*0fca6ea1SDimitry Andric       llvm::report_fatal_error(
56*0fca6ea1SDimitry Andric           "Inconsistent search path options between modules detected");
57*0fca6ea1SDimitry Andric 
5881ad6265SDimitry Andric     for (auto Idx : SearchPathUsage.set_bits())
59*0fca6ea1SDimitry Andric       Opts.UserEntries.push_back(std::move(Entries[Idx]));
60*0fca6ea1SDimitry Andric   }
61*0fca6ea1SDimitry Andric   if (any(OptimizeArgs & ScanningOptimizations::VFS)) {
62*0fca6ea1SDimitry Andric     std::vector<std::string> VFSOverlayFiles;
63*0fca6ea1SDimitry Andric     std::swap(Opts.VFSOverlayFiles, VFSOverlayFiles);
64*0fca6ea1SDimitry Andric 
65*0fca6ea1SDimitry Andric     llvm::BitVector VFSUsage(VFSOverlayFiles.size());
66*0fca6ea1SDimitry Andric     llvm::DenseSet<const serialization::ModuleFile *> Visited;
67*0fca6ea1SDimitry Andric     std::function<void(const serialization::ModuleFile *)> VisitMF =
68*0fca6ea1SDimitry Andric         [&](const serialization::ModuleFile *MF) {
69*0fca6ea1SDimitry Andric           Visited.insert(MF);
70*0fca6ea1SDimitry Andric           if (MF->Kind == serialization::MK_ImplicitModule) {
71*0fca6ea1SDimitry Andric             VFSUsage |= MF->VFSUsage;
72*0fca6ea1SDimitry Andric             // We only need to recurse into implicit modules. Other module types
73*0fca6ea1SDimitry Andric             // will have the correct set of VFSs for anything they depend on.
74*0fca6ea1SDimitry Andric             for (const serialization::ModuleFile *Import : MF->Imports)
75*0fca6ea1SDimitry Andric               if (!Visited.contains(Import))
76*0fca6ea1SDimitry Andric                 VisitMF(Import);
77*0fca6ea1SDimitry Andric           } else {
78*0fca6ea1SDimitry Andric             // This is not an implicitly built module, so it may have different
79*0fca6ea1SDimitry Andric             // VFS options. Fall back to a string comparison instead.
80*0fca6ea1SDimitry Andric             auto VFSMap = PrebuiltModuleVFSMap.find(MF->FileName);
81*0fca6ea1SDimitry Andric             if (VFSMap == PrebuiltModuleVFSMap.end())
82*0fca6ea1SDimitry Andric               return;
83*0fca6ea1SDimitry Andric             for (std::size_t I = 0, E = VFSOverlayFiles.size(); I != E; ++I) {
84*0fca6ea1SDimitry Andric               if (VFSMap->second.contains(VFSOverlayFiles[I]))
85*0fca6ea1SDimitry Andric                 VFSUsage[I] = true;
86*0fca6ea1SDimitry Andric             }
87*0fca6ea1SDimitry Andric           }
88*0fca6ea1SDimitry Andric         };
89*0fca6ea1SDimitry Andric     VisitMF(&MF);
90*0fca6ea1SDimitry Andric 
91*0fca6ea1SDimitry Andric     if (VFSUsage.size() != VFSOverlayFiles.size())
92*0fca6ea1SDimitry Andric       llvm::report_fatal_error(
93*0fca6ea1SDimitry Andric           "Inconsistent -ivfsoverlay options between modules detected");
94*0fca6ea1SDimitry Andric 
95*0fca6ea1SDimitry Andric     for (auto Idx : VFSUsage.set_bits())
96*0fca6ea1SDimitry Andric       Opts.VFSOverlayFiles.push_back(std::move(VFSOverlayFiles[Idx]));
97*0fca6ea1SDimitry Andric   }
98349cc55cSDimitry Andric }
99349cc55cSDimitry Andric 
1005f757f3fSDimitry Andric static void optimizeDiagnosticOpts(DiagnosticOptions &Opts,
1015f757f3fSDimitry Andric                                    bool IsSystemModule) {
1025f757f3fSDimitry Andric   // If this is not a system module or -Wsystem-headers was passed, don't
1035f757f3fSDimitry Andric   // optimize.
1045f757f3fSDimitry Andric   if (!IsSystemModule)
1055f757f3fSDimitry Andric     return;
1065f757f3fSDimitry Andric   bool Wsystem_headers = false;
1075f757f3fSDimitry Andric   for (StringRef Opt : Opts.Warnings) {
1085f757f3fSDimitry Andric     bool isPositive = !Opt.consume_front("no-");
1095f757f3fSDimitry Andric     if (Opt == "system-headers")
1105f757f3fSDimitry Andric       Wsystem_headers = isPositive;
1115f757f3fSDimitry Andric   }
1125f757f3fSDimitry Andric   if (Wsystem_headers)
1135f757f3fSDimitry Andric     return;
1145f757f3fSDimitry Andric 
1155f757f3fSDimitry Andric   // Remove all warning flags. System modules suppress most, but not all,
1165f757f3fSDimitry Andric   // warnings.
1175f757f3fSDimitry Andric   Opts.Warnings.clear();
1185f757f3fSDimitry Andric   Opts.UndefPrefixes.clear();
1195f757f3fSDimitry Andric   Opts.Remarks.clear();
1205f757f3fSDimitry Andric }
1215f757f3fSDimitry Andric 
122753f127fSDimitry Andric static std::vector<std::string> splitString(std::string S, char Separator) {
123753f127fSDimitry Andric   SmallVector<StringRef> Segments;
124753f127fSDimitry Andric   StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false);
125753f127fSDimitry Andric   std::vector<std::string> Result;
126753f127fSDimitry Andric   Result.reserve(Segments.size());
127753f127fSDimitry Andric   for (StringRef Segment : Segments)
128753f127fSDimitry Andric     Result.push_back(Segment.str());
129753f127fSDimitry Andric   return Result;
130753f127fSDimitry Andric }
131753f127fSDimitry Andric 
1325f757f3fSDimitry Andric void ModuleDepCollector::addOutputPaths(CowCompilerInvocation &CI,
133bdd1243dSDimitry Andric                                         ModuleDeps &Deps) {
1345f757f3fSDimitry Andric   CI.getMutFrontendOpts().OutputFile =
13506c3fb27SDimitry Andric       Controller.lookupModuleOutput(Deps.ID, ModuleOutputKind::ModuleFile);
136bdd1243dSDimitry Andric   if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty())
1375f757f3fSDimitry Andric     CI.getMutDiagnosticOpts().DiagnosticSerializationFile =
13806c3fb27SDimitry Andric         Controller.lookupModuleOutput(
139bdd1243dSDimitry Andric             Deps.ID, ModuleOutputKind::DiagnosticSerializationFile);
140bdd1243dSDimitry Andric   if (!CI.getDependencyOutputOpts().OutputFile.empty()) {
1415f757f3fSDimitry Andric     CI.getMutDependencyOutputOpts().OutputFile = Controller.lookupModuleOutput(
14206c3fb27SDimitry Andric         Deps.ID, ModuleOutputKind::DependencyFile);
1435f757f3fSDimitry Andric     CI.getMutDependencyOutputOpts().Targets =
14406c3fb27SDimitry Andric         splitString(Controller.lookupModuleOutput(
145bdd1243dSDimitry Andric                         Deps.ID, ModuleOutputKind::DependencyTargets),
146bdd1243dSDimitry Andric                     '\0');
147bdd1243dSDimitry Andric     if (!CI.getDependencyOutputOpts().OutputFile.empty() &&
148bdd1243dSDimitry Andric         CI.getDependencyOutputOpts().Targets.empty()) {
149753f127fSDimitry Andric       // Fallback to -o as dependency target, as in the driver.
150753f127fSDimitry Andric       SmallString<128> Target;
151bdd1243dSDimitry Andric       quoteMakeTarget(CI.getFrontendOpts().OutputFile, Target);
1525f757f3fSDimitry Andric       CI.getMutDependencyOutputOpts().Targets.push_back(std::string(Target));
153bdd1243dSDimitry Andric     }
154753f127fSDimitry Andric   }
155753f127fSDimitry Andric }
156fe6060f1SDimitry Andric 
157*0fca6ea1SDimitry Andric void dependencies::resetBenignCodeGenOptions(frontend::ActionKind ProgramAction,
158*0fca6ea1SDimitry Andric                                              const LangOptions &LangOpts,
159*0fca6ea1SDimitry Andric                                              CodeGenOptions &CGOpts) {
160*0fca6ea1SDimitry Andric   // TODO: Figure out better way to set options to their default value.
161*0fca6ea1SDimitry Andric   if (ProgramAction == frontend::GenerateModule) {
162*0fca6ea1SDimitry Andric     CGOpts.MainFileName.clear();
163*0fca6ea1SDimitry Andric     CGOpts.DwarfDebugFlags.clear();
164*0fca6ea1SDimitry Andric   }
165*0fca6ea1SDimitry Andric   if (ProgramAction == frontend::GeneratePCH ||
166*0fca6ea1SDimitry Andric       (ProgramAction == frontend::GenerateModule && !LangOpts.ModulesCodegen)) {
167*0fca6ea1SDimitry Andric     CGOpts.DebugCompilationDir.clear();
168*0fca6ea1SDimitry Andric     CGOpts.CoverageCompilationDir.clear();
169*0fca6ea1SDimitry Andric     CGOpts.CoverageDataFile.clear();
170*0fca6ea1SDimitry Andric     CGOpts.CoverageNotesFile.clear();
171*0fca6ea1SDimitry Andric     CGOpts.ProfileInstrumentUsePath.clear();
172*0fca6ea1SDimitry Andric     CGOpts.SampleProfileFile.clear();
173*0fca6ea1SDimitry Andric     CGOpts.ProfileRemappingFile.clear();
174*0fca6ea1SDimitry Andric   }
175*0fca6ea1SDimitry Andric }
176*0fca6ea1SDimitry Andric 
1775f757f3fSDimitry Andric static CowCompilerInvocation
1785f757f3fSDimitry Andric makeCommonInvocationForModuleBuild(CompilerInvocation CI) {
179bdd1243dSDimitry Andric   CI.resetNonModularOptions();
180bdd1243dSDimitry Andric   CI.clearImplicitModuleBuildOptions();
181bdd1243dSDimitry Andric 
182*0fca6ea1SDimitry Andric   // The scanner takes care to avoid passing non-affecting module maps to the
183*0fca6ea1SDimitry Andric   // explicit compiles. No need to do extra work just to find out there are no
184*0fca6ea1SDimitry Andric   // module map files to prune.
185*0fca6ea1SDimitry Andric   CI.getHeaderSearchOpts().ModulesPruneNonAffectingModuleMaps = false;
186*0fca6ea1SDimitry Andric 
187bdd1243dSDimitry Andric   // Remove options incompatible with explicit module build or are likely to
188bdd1243dSDimitry Andric   // differ between identical modules discovered from different translation
189bdd1243dSDimitry Andric   // units.
190bdd1243dSDimitry Andric   CI.getFrontendOpts().Inputs.clear();
191bdd1243dSDimitry Andric   CI.getFrontendOpts().OutputFile.clear();
1925f757f3fSDimitry Andric   // LLVM options are not going to affect the AST
1935f757f3fSDimitry Andric   CI.getFrontendOpts().LLVMArgs.clear();
194bdd1243dSDimitry Andric 
195*0fca6ea1SDimitry Andric   resetBenignCodeGenOptions(frontend::GenerateModule, CI.getLangOpts(),
196*0fca6ea1SDimitry Andric                             CI.getCodeGenOpts());
197fe6060f1SDimitry Andric 
198bdd1243dSDimitry Andric   // Map output paths that affect behaviour to "-" so their existence is in the
199bdd1243dSDimitry Andric   // context hash. The final path will be computed in addOutputPaths.
200bdd1243dSDimitry Andric   if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty())
201bdd1243dSDimitry Andric     CI.getDiagnosticOpts().DiagnosticSerializationFile = "-";
202bdd1243dSDimitry Andric   if (!CI.getDependencyOutputOpts().OutputFile.empty())
203bdd1243dSDimitry Andric     CI.getDependencyOutputOpts().OutputFile = "-";
204bdd1243dSDimitry Andric   CI.getDependencyOutputOpts().Targets.clear();
205bdd1243dSDimitry Andric 
206bdd1243dSDimitry Andric   CI.getFrontendOpts().ProgramAction = frontend::GenerateModule;
20706c3fb27SDimitry Andric   CI.getFrontendOpts().ARCMTAction = FrontendOptions::ARCMT_None;
20806c3fb27SDimitry Andric   CI.getFrontendOpts().ObjCMTAction = FrontendOptions::ObjCMT_None;
20906c3fb27SDimitry Andric   CI.getFrontendOpts().MTMigrateDir.clear();
2105f757f3fSDimitry Andric   CI.getLangOpts().ModuleName.clear();
2115f757f3fSDimitry Andric 
2125f757f3fSDimitry Andric   // Remove any macro definitions that are explicitly ignored.
2135f757f3fSDimitry Andric   if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) {
2145f757f3fSDimitry Andric     llvm::erase_if(
2155f757f3fSDimitry Andric         CI.getPreprocessorOpts().Macros,
2165f757f3fSDimitry Andric         [&CI](const std::pair<std::string, bool> &Def) {
2175f757f3fSDimitry Andric           StringRef MacroDef = Def.first;
2185f757f3fSDimitry Andric           return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains(
2195f757f3fSDimitry Andric               llvm::CachedHashString(MacroDef.split('=').first));
2205f757f3fSDimitry Andric         });
2215f757f3fSDimitry Andric     // Remove the now unused option.
2225f757f3fSDimitry Andric     CI.getHeaderSearchOpts().ModulesIgnoreMacros.clear();
2235f757f3fSDimitry Andric   }
2245f757f3fSDimitry Andric 
2255f757f3fSDimitry Andric   return CI;
2265f757f3fSDimitry Andric }
2275f757f3fSDimitry Andric 
2285f757f3fSDimitry Andric CowCompilerInvocation
2295f757f3fSDimitry Andric ModuleDepCollector::getInvocationAdjustedForModuleBuildWithoutOutputs(
2305f757f3fSDimitry Andric     const ModuleDeps &Deps,
2315f757f3fSDimitry Andric     llvm::function_ref<void(CowCompilerInvocation &)> Optimize) const {
2325f757f3fSDimitry Andric   CowCompilerInvocation CI = CommonInvocation;
2335f757f3fSDimitry Andric 
2345f757f3fSDimitry Andric   CI.getMutLangOpts().ModuleName = Deps.ID.ModuleName;
2355f757f3fSDimitry Andric   CI.getMutFrontendOpts().IsSystemModule = Deps.IsSystem;
236bdd1243dSDimitry Andric 
237bdd1243dSDimitry Andric   // Inputs
238bdd1243dSDimitry Andric   InputKind ModuleMapInputKind(CI.getFrontendOpts().DashX.getLanguage(),
239bdd1243dSDimitry Andric                                InputKind::Format::ModuleMap);
2405f757f3fSDimitry Andric   CI.getMutFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile,
241bdd1243dSDimitry Andric                                               ModuleMapInputKind);
242bdd1243dSDimitry Andric 
243bdd1243dSDimitry Andric   auto CurrentModuleMapEntry =
244bdd1243dSDimitry Andric       ScanInstance.getFileManager().getFile(Deps.ClangModuleMapFile);
245bdd1243dSDimitry Andric   assert(CurrentModuleMapEntry && "module map file entry not found");
246bdd1243dSDimitry Andric 
247*0fca6ea1SDimitry Andric   // Remove directly passed modulemap files. They will get added back if they
248*0fca6ea1SDimitry Andric   // were actually used.
249*0fca6ea1SDimitry Andric   CI.getMutFrontendOpts().ModuleMapFiles.clear();
250*0fca6ea1SDimitry Andric 
251bdd1243dSDimitry Andric   auto DepModuleMapFiles = collectModuleMapFiles(Deps.ClangModuleDeps);
252bdd1243dSDimitry Andric   for (StringRef ModuleMapFile : Deps.ModuleMapFileDeps) {
253bdd1243dSDimitry Andric     // TODO: Track these as `FileEntryRef` to simplify the equality check below.
254bdd1243dSDimitry Andric     auto ModuleMapEntry = ScanInstance.getFileManager().getFile(ModuleMapFile);
255bdd1243dSDimitry Andric     assert(ModuleMapEntry && "module map file entry not found");
256bdd1243dSDimitry Andric 
257bdd1243dSDimitry Andric     // Don't report module maps describing eagerly-loaded dependency. This
258bdd1243dSDimitry Andric     // information will be deserialized from the PCM.
259bdd1243dSDimitry Andric     // TODO: Verify this works fine when modulemap for module A is eagerly
260bdd1243dSDimitry Andric     // loaded from A.pcm, and module map passed on the command line contains
261bdd1243dSDimitry Andric     // definition of a submodule: "explicit module A.Private { ... }".
262bdd1243dSDimitry Andric     if (EagerLoadModules && DepModuleMapFiles.contains(*ModuleMapEntry))
263bdd1243dSDimitry Andric       continue;
264bdd1243dSDimitry Andric 
265bdd1243dSDimitry Andric     // Don't report module map file of the current module unless it also
266bdd1243dSDimitry Andric     // describes a dependency (for symmetry).
267bdd1243dSDimitry Andric     if (*ModuleMapEntry == *CurrentModuleMapEntry &&
268bdd1243dSDimitry Andric         !DepModuleMapFiles.contains(*ModuleMapEntry))
269bdd1243dSDimitry Andric       continue;
270bdd1243dSDimitry Andric 
2715f757f3fSDimitry Andric     CI.getMutFrontendOpts().ModuleMapFiles.emplace_back(ModuleMapFile);
272bdd1243dSDimitry Andric   }
273bdd1243dSDimitry Andric 
274bdd1243dSDimitry Andric   // Report the prebuilt modules this module uses.
275bdd1243dSDimitry Andric   for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps)
2765f757f3fSDimitry Andric     CI.getMutFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile);
277bdd1243dSDimitry Andric 
278bdd1243dSDimitry Andric   // Add module file inputs from dependencies.
279bdd1243dSDimitry Andric   addModuleFiles(CI, Deps.ClangModuleDeps);
280bdd1243dSDimitry Andric 
2815f757f3fSDimitry Andric   if (!CI.getDiagnosticOpts().SystemHeaderWarningsModules.empty()) {
2825f757f3fSDimitry Andric     // Apply -Wsystem-headers-in-module for the current module.
2835f757f3fSDimitry Andric     if (llvm::is_contained(CI.getDiagnosticOpts().SystemHeaderWarningsModules,
2845f757f3fSDimitry Andric                            Deps.ID.ModuleName))
2855f757f3fSDimitry Andric       CI.getMutDiagnosticOpts().Warnings.push_back("system-headers");
2865f757f3fSDimitry Andric     // Remove the now unused option(s).
2875f757f3fSDimitry Andric     CI.getMutDiagnosticOpts().SystemHeaderWarningsModules.clear();
288bdd1243dSDimitry Andric   }
289bdd1243dSDimitry Andric 
290bdd1243dSDimitry Andric   Optimize(CI);
291bdd1243dSDimitry Andric 
292bdd1243dSDimitry Andric   return CI;
293bdd1243dSDimitry Andric }
294bdd1243dSDimitry Andric 
295bdd1243dSDimitry Andric llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles(
296bdd1243dSDimitry Andric     ArrayRef<ModuleID> ClangModuleDeps) const {
297bdd1243dSDimitry Andric   llvm::DenseSet<const FileEntry *> ModuleMapFiles;
298bdd1243dSDimitry Andric   for (const ModuleID &MID : ClangModuleDeps) {
299bdd1243dSDimitry Andric     ModuleDeps *MD = ModuleDepsByID.lookup(MID);
300bdd1243dSDimitry Andric     assert(MD && "Inconsistent dependency info");
301bdd1243dSDimitry Andric     // TODO: Track ClangModuleMapFile as `FileEntryRef`.
302bdd1243dSDimitry Andric     auto FE = ScanInstance.getFileManager().getFile(MD->ClangModuleMapFile);
303bdd1243dSDimitry Andric     assert(FE && "Missing module map file that was previously found");
304bdd1243dSDimitry Andric     ModuleMapFiles.insert(*FE);
305bdd1243dSDimitry Andric   }
306bdd1243dSDimitry Andric   return ModuleMapFiles;
307bdd1243dSDimitry Andric }
308bdd1243dSDimitry Andric 
309bdd1243dSDimitry Andric void ModuleDepCollector::addModuleMapFiles(
310bdd1243dSDimitry Andric     CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
311bdd1243dSDimitry Andric   if (EagerLoadModules)
312bdd1243dSDimitry Andric     return; // Only pcm is needed for eager load.
313bdd1243dSDimitry Andric 
314bdd1243dSDimitry Andric   for (const ModuleID &MID : ClangModuleDeps) {
315bdd1243dSDimitry Andric     ModuleDeps *MD = ModuleDepsByID.lookup(MID);
316bdd1243dSDimitry Andric     assert(MD && "Inconsistent dependency info");
317bdd1243dSDimitry Andric     CI.getFrontendOpts().ModuleMapFiles.push_back(MD->ClangModuleMapFile);
318bdd1243dSDimitry Andric   }
319bdd1243dSDimitry Andric }
320bdd1243dSDimitry Andric 
321bdd1243dSDimitry Andric void ModuleDepCollector::addModuleFiles(
322bdd1243dSDimitry Andric     CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
323bdd1243dSDimitry Andric   for (const ModuleID &MID : ClangModuleDeps) {
324bdd1243dSDimitry Andric     std::string PCMPath =
32506c3fb27SDimitry Andric         Controller.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile);
326bdd1243dSDimitry Andric     if (EagerLoadModules)
327bdd1243dSDimitry Andric       CI.getFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
328bdd1243dSDimitry Andric     else
329bdd1243dSDimitry Andric       CI.getHeaderSearchOpts().PrebuiltModuleFiles.insert(
330bdd1243dSDimitry Andric           {MID.ModuleName, std::move(PCMPath)});
331bdd1243dSDimitry Andric   }
332bdd1243dSDimitry Andric }
333bdd1243dSDimitry Andric 
3345f757f3fSDimitry Andric void ModuleDepCollector::addModuleFiles(
3355f757f3fSDimitry Andric     CowCompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
3365f757f3fSDimitry Andric   for (const ModuleID &MID : ClangModuleDeps) {
3375f757f3fSDimitry Andric     std::string PCMPath =
3385f757f3fSDimitry Andric         Controller.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile);
3395f757f3fSDimitry Andric     if (EagerLoadModules)
3405f757f3fSDimitry Andric       CI.getMutFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
3415f757f3fSDimitry Andric     else
3425f757f3fSDimitry Andric       CI.getMutHeaderSearchOpts().PrebuiltModuleFiles.insert(
3435f757f3fSDimitry Andric           {MID.ModuleName, std::move(PCMPath)});
3445f757f3fSDimitry Andric   }
3455f757f3fSDimitry Andric }
3465f757f3fSDimitry Andric 
347bdd1243dSDimitry Andric static bool needsModules(FrontendInputFile FIF) {
348bdd1243dSDimitry Andric   switch (FIF.getKind().getLanguage()) {
349bdd1243dSDimitry Andric   case Language::Unknown:
350bdd1243dSDimitry Andric   case Language::Asm:
351bdd1243dSDimitry Andric   case Language::LLVM_IR:
352bdd1243dSDimitry Andric     return false;
353bdd1243dSDimitry Andric   default:
354bdd1243dSDimitry Andric     return true;
355bdd1243dSDimitry Andric   }
356bdd1243dSDimitry Andric }
357bdd1243dSDimitry Andric 
358bdd1243dSDimitry Andric void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) {
359bdd1243dSDimitry Andric   CI.clearImplicitModuleBuildOptions();
360*0fca6ea1SDimitry Andric   resetBenignCodeGenOptions(CI.getFrontendOpts().ProgramAction,
361*0fca6ea1SDimitry Andric                             CI.getLangOpts(), CI.getCodeGenOpts());
362bdd1243dSDimitry Andric 
363bdd1243dSDimitry Andric   if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) {
364bdd1243dSDimitry Andric     Preprocessor &PP = ScanInstance.getPreprocessor();
365bdd1243dSDimitry Andric     if (Module *CurrentModule = PP.getCurrentModuleImplementation())
366bdd1243dSDimitry Andric       if (OptionalFileEntryRef CurrentModuleMap =
367bdd1243dSDimitry Andric               PP.getHeaderSearchInfo()
368bdd1243dSDimitry Andric                   .getModuleMap()
369bdd1243dSDimitry Andric                   .getModuleMapFileForUniquing(CurrentModule))
370bdd1243dSDimitry Andric         CI.getFrontendOpts().ModuleMapFiles.emplace_back(
37106c3fb27SDimitry Andric             CurrentModuleMap->getNameAsRequested());
372bdd1243dSDimitry Andric 
373bdd1243dSDimitry Andric     SmallVector<ModuleID> DirectDeps;
374bdd1243dSDimitry Andric     for (const auto &KV : ModularDeps)
3755f757f3fSDimitry Andric       if (DirectModularDeps.contains(KV.first))
376bdd1243dSDimitry Andric         DirectDeps.push_back(KV.second->ID);
377bdd1243dSDimitry Andric 
378bdd1243dSDimitry Andric     // TODO: Report module maps the same way it's done for modular dependencies.
379bdd1243dSDimitry Andric     addModuleMapFiles(CI, DirectDeps);
380bdd1243dSDimitry Andric 
381bdd1243dSDimitry Andric     addModuleFiles(CI, DirectDeps);
382bdd1243dSDimitry Andric 
383bdd1243dSDimitry Andric     for (const auto &KV : DirectPrebuiltModularDeps)
384bdd1243dSDimitry Andric       CI.getFrontendOpts().ModuleFiles.push_back(KV.second.PCMFile);
385bdd1243dSDimitry Andric   }
386bdd1243dSDimitry Andric }
387bdd1243dSDimitry Andric 
388bdd1243dSDimitry Andric static std::string getModuleContextHash(const ModuleDeps &MD,
3895f757f3fSDimitry Andric                                         const CowCompilerInvocation &CI,
3905f757f3fSDimitry Andric                                         bool EagerLoadModules,
3915f757f3fSDimitry Andric                                         llvm::vfs::FileSystem &VFS) {
3925f757f3fSDimitry Andric   llvm::HashBuilder<llvm::TruncatedBLAKE3<16>, llvm::endianness::native>
393bdd1243dSDimitry Andric       HashBuilder;
394bdd1243dSDimitry Andric   SmallString<32> Scratch;
395bdd1243dSDimitry Andric 
396bdd1243dSDimitry Andric   // Hash the compiler version and serialization version to ensure the module
397bdd1243dSDimitry Andric   // will be readable.
398bdd1243dSDimitry Andric   HashBuilder.add(getClangFullRepositoryVersion());
399bdd1243dSDimitry Andric   HashBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR);
4005f757f3fSDimitry Andric   llvm::ErrorOr<std::string> CWD = VFS.getCurrentWorkingDirectory();
4015f757f3fSDimitry Andric   if (CWD)
4025f757f3fSDimitry Andric     HashBuilder.add(*CWD);
403bdd1243dSDimitry Andric 
404bdd1243dSDimitry Andric   // Hash the BuildInvocation without any input files.
4055f757f3fSDimitry Andric   SmallString<0> ArgVec;
4065f757f3fSDimitry Andric   ArgVec.reserve(4096);
4075f757f3fSDimitry Andric   CI.generateCC1CommandLine([&](const Twine &Arg) {
4085f757f3fSDimitry Andric     Arg.toVector(ArgVec);
4095f757f3fSDimitry Andric     ArgVec.push_back('\0');
4105f757f3fSDimitry Andric   });
4115f757f3fSDimitry Andric   HashBuilder.add(ArgVec);
412bdd1243dSDimitry Andric 
413bdd1243dSDimitry Andric   // Hash the module dependencies. These paths may differ even if the invocation
414bdd1243dSDimitry Andric   // is identical if they depend on the contents of the files in the TU -- for
415bdd1243dSDimitry Andric   // example, case-insensitive paths to modulemap files. Usually such a case
416bdd1243dSDimitry Andric   // would indicate a missed optimization to canonicalize, but it may be
417bdd1243dSDimitry Andric   // difficult to canonicalize all cases when there is a VFS.
418bdd1243dSDimitry Andric   for (const auto &ID : MD.ClangModuleDeps) {
419bdd1243dSDimitry Andric     HashBuilder.add(ID.ModuleName);
420bdd1243dSDimitry Andric     HashBuilder.add(ID.ContextHash);
421bdd1243dSDimitry Andric   }
422bdd1243dSDimitry Andric 
423bdd1243dSDimitry Andric   HashBuilder.add(EagerLoadModules);
424bdd1243dSDimitry Andric 
425bdd1243dSDimitry Andric   llvm::BLAKE3Result<16> Hash = HashBuilder.final();
426bdd1243dSDimitry Andric   std::array<uint64_t, 2> Words;
427bdd1243dSDimitry Andric   static_assert(sizeof(Hash) == sizeof(Words), "Hash must match Words");
428bdd1243dSDimitry Andric   std::memcpy(Words.data(), Hash.data(), sizeof(Hash));
429bdd1243dSDimitry Andric   return toString(llvm::APInt(sizeof(Words) * 8, Words), 36, /*Signed=*/false);
430bdd1243dSDimitry Andric }
431bdd1243dSDimitry Andric 
4325f757f3fSDimitry Andric void ModuleDepCollector::associateWithContextHash(
4335f757f3fSDimitry Andric     const CowCompilerInvocation &CI, ModuleDeps &Deps) {
4345f757f3fSDimitry Andric   Deps.ID.ContextHash = getModuleContextHash(
4355f757f3fSDimitry Andric       Deps, CI, EagerLoadModules, ScanInstance.getVirtualFileSystem());
436bdd1243dSDimitry Andric   bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second;
437bdd1243dSDimitry Andric   (void)Inserted;
438bdd1243dSDimitry Andric   assert(Inserted && "duplicate module mapping");
439fe6060f1SDimitry Andric }
440fe6060f1SDimitry Andric 
44106c3fb27SDimitry Andric void ModuleDepCollectorPP::LexedFileChanged(FileID FID,
44206c3fb27SDimitry Andric                                             LexedFileChangeReason Reason,
443480093f4SDimitry Andric                                             SrcMgr::CharacteristicKind FileType,
44406c3fb27SDimitry Andric                                             FileID PrevFID,
44506c3fb27SDimitry Andric                                             SourceLocation Loc) {
44606c3fb27SDimitry Andric   if (Reason != LexedFileChangeReason::EnterFile)
447480093f4SDimitry Andric     return;
448480093f4SDimitry Andric 
4495ffd83dbSDimitry Andric   // This has to be delayed as the context hash can change at the start of
4505ffd83dbSDimitry Andric   // `CompilerInstance::ExecuteAction`.
4515ffd83dbSDimitry Andric   if (MDC.ContextHash.empty()) {
452349cc55cSDimitry Andric     MDC.ContextHash = MDC.ScanInstance.getInvocation().getModuleHash();
4535ffd83dbSDimitry Andric     MDC.Consumer.handleContextHash(MDC.ContextHash);
4545ffd83dbSDimitry Andric   }
4555ffd83dbSDimitry Andric 
456349cc55cSDimitry Andric   SourceManager &SM = MDC.ScanInstance.getSourceManager();
457480093f4SDimitry Andric 
458480093f4SDimitry Andric   // Dependency generation really does want to go all the way to the
459480093f4SDimitry Andric   // file entry for a source location to find out what is depended on.
460480093f4SDimitry Andric   // We do not want #line markers to affect dependency generation!
46106c3fb27SDimitry Andric   if (std::optional<StringRef> Filename = SM.getNonBuiltinFilenameForID(FID))
462bdd1243dSDimitry Andric     MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*Filename));
463480093f4SDimitry Andric }
464480093f4SDimitry Andric 
465480093f4SDimitry Andric void ModuleDepCollectorPP::InclusionDirective(
466480093f4SDimitry Andric     SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
467bdd1243dSDimitry Andric     bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
468*0fca6ea1SDimitry Andric     StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
469*0fca6ea1SDimitry Andric     bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
470*0fca6ea1SDimitry Andric   if (!File && !ModuleImported) {
471480093f4SDimitry Andric     // This is a non-modular include that HeaderSearch failed to find. Add it
472480093f4SDimitry Andric     // here as `FileChanged` will never see it.
473bdd1243dSDimitry Andric     MDC.addFileDep(FileName);
4745ffd83dbSDimitry Andric   }
475*0fca6ea1SDimitry Andric   handleImport(SuggestedModule);
476480093f4SDimitry Andric }
477480093f4SDimitry Andric 
4785ffd83dbSDimitry Andric void ModuleDepCollectorPP::moduleImport(SourceLocation ImportLoc,
4795ffd83dbSDimitry Andric                                         ModuleIdPath Path,
4805ffd83dbSDimitry Andric                                         const Module *Imported) {
4811ac55f4cSDimitry Andric   if (MDC.ScanInstance.getPreprocessor().isInImportingCXXNamedModules()) {
4821ac55f4cSDimitry Andric     P1689ModuleInfo RequiredModule;
4831ac55f4cSDimitry Andric     RequiredModule.ModuleName = Path[0].first->getName().str();
4841ac55f4cSDimitry Andric     RequiredModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule;
4851ac55f4cSDimitry Andric     MDC.RequiredStdCXXModules.push_back(RequiredModule);
4861ac55f4cSDimitry Andric     return;
4871ac55f4cSDimitry Andric   }
4881ac55f4cSDimitry Andric 
4895ffd83dbSDimitry Andric   handleImport(Imported);
4905ffd83dbSDimitry Andric }
4915ffd83dbSDimitry Andric 
4925ffd83dbSDimitry Andric void ModuleDepCollectorPP::handleImport(const Module *Imported) {
493480093f4SDimitry Andric   if (!Imported)
494480093f4SDimitry Andric     return;
495480093f4SDimitry Andric 
496fe6060f1SDimitry Andric   const Module *TopLevelModule = Imported->getTopLevelModule();
497fe6060f1SDimitry Andric 
498fe6060f1SDimitry Andric   if (MDC.isPrebuiltModule(TopLevelModule))
499bdd1243dSDimitry Andric     MDC.DirectPrebuiltModularDeps.insert(
500bdd1243dSDimitry Andric         {TopLevelModule, PrebuiltModuleDep{TopLevelModule}});
501fe6060f1SDimitry Andric   else
5025f757f3fSDimitry Andric     MDC.DirectModularDeps.insert(TopLevelModule);
503480093f4SDimitry Andric }
504480093f4SDimitry Andric 
505480093f4SDimitry Andric void ModuleDepCollectorPP::EndOfMainFile() {
506349cc55cSDimitry Andric   FileID MainFileID = MDC.ScanInstance.getSourceManager().getMainFileID();
507349cc55cSDimitry Andric   MDC.MainFile = std::string(MDC.ScanInstance.getSourceManager()
5085f757f3fSDimitry Andric                                  .getFileEntryRefForID(MainFileID)
509349cc55cSDimitry Andric                                  ->getName());
510480093f4SDimitry Andric 
5111ac55f4cSDimitry Andric   auto &PP = MDC.ScanInstance.getPreprocessor();
5121ac55f4cSDimitry Andric   if (PP.isInNamedModule()) {
5131ac55f4cSDimitry Andric     P1689ModuleInfo ProvidedModule;
5141ac55f4cSDimitry Andric     ProvidedModule.ModuleName = PP.getNamedModuleName();
5151ac55f4cSDimitry Andric     ProvidedModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule;
5161ac55f4cSDimitry Andric     ProvidedModule.IsStdCXXModuleInterface = PP.isInNamedInterfaceUnit();
5171ac55f4cSDimitry Andric     // Don't put implementation (non partition) unit as Provide.
5181ac55f4cSDimitry Andric     // Put the module as required instead. Since the implementation
5191ac55f4cSDimitry Andric     // unit will import the primary module implicitly.
5201ac55f4cSDimitry Andric     if (PP.isInImplementationUnit())
5211ac55f4cSDimitry Andric       MDC.RequiredStdCXXModules.push_back(ProvidedModule);
5221ac55f4cSDimitry Andric     else
5231ac55f4cSDimitry Andric       MDC.ProvidedStdCXXModule = ProvidedModule;
5241ac55f4cSDimitry Andric   }
5251ac55f4cSDimitry Andric 
526349cc55cSDimitry Andric   if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
527bdd1243dSDimitry Andric     MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude);
528fe6060f1SDimitry Andric 
529bdd1243dSDimitry Andric   for (const Module *M :
530bdd1243dSDimitry Andric        MDC.ScanInstance.getPreprocessor().getAffectingClangModules())
531bdd1243dSDimitry Andric     if (!MDC.isPrebuiltModule(M))
5325f757f3fSDimitry Andric       MDC.DirectModularDeps.insert(M);
533bdd1243dSDimitry Andric 
5345f757f3fSDimitry Andric   for (const Module *M : MDC.DirectModularDeps)
535480093f4SDimitry Andric     handleTopLevelModule(M);
536480093f4SDimitry Andric 
537fe6060f1SDimitry Andric   MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts);
538fe6060f1SDimitry Andric 
5391ac55f4cSDimitry Andric   if (MDC.IsStdModuleP1689Format)
5401ac55f4cSDimitry Andric     MDC.Consumer.handleProvidedAndRequiredStdCXXModules(
5411ac55f4cSDimitry Andric         MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules);
5421ac55f4cSDimitry Andric 
543fe6060f1SDimitry Andric   for (auto &&I : MDC.ModularDeps)
54481ad6265SDimitry Andric     MDC.Consumer.handleModuleDependency(*I.second);
545480093f4SDimitry Andric 
5465f757f3fSDimitry Andric   for (const Module *M : MDC.DirectModularDeps) {
5475f757f3fSDimitry Andric     auto It = MDC.ModularDeps.find(M);
5485f757f3fSDimitry Andric     // Only report direct dependencies that were successfully handled.
5495f757f3fSDimitry Andric     if (It != MDC.ModularDeps.end())
5505f757f3fSDimitry Andric       MDC.Consumer.handleDirectModuleDependency(MDC.ModularDeps[M]->ID);
5515f757f3fSDimitry Andric   }
5525f757f3fSDimitry Andric 
553fe6060f1SDimitry Andric   for (auto &&I : MDC.FileDeps)
554fe6060f1SDimitry Andric     MDC.Consumer.handleFileDependency(I);
555fe6060f1SDimitry Andric 
556bdd1243dSDimitry Andric   for (auto &&I : MDC.DirectPrebuiltModularDeps)
557bdd1243dSDimitry Andric     MDC.Consumer.handlePrebuiltModuleDependency(I.second);
558480093f4SDimitry Andric }
559480093f4SDimitry Andric 
560bdd1243dSDimitry Andric std::optional<ModuleID>
561bdd1243dSDimitry Andric ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
562480093f4SDimitry Andric   assert(M == M->getTopLevelModule() && "Expected top level module!");
563480093f4SDimitry Andric 
564bdd1243dSDimitry Andric   // A top-level module might not be actually imported as a module when
565bdd1243dSDimitry Andric   // -fmodule-name is used to compile a translation unit that imports this
566bdd1243dSDimitry Andric   // module. In that case it can be skipped. The appropriate header
567bdd1243dSDimitry Andric   // dependencies will still be reported as expected.
568bdd1243dSDimitry Andric   if (!M->getASTFile())
569bdd1243dSDimitry Andric     return {};
570bdd1243dSDimitry Andric 
571fe6060f1SDimitry Andric   // If this module has been handled already, just return its ID.
57281ad6265SDimitry Andric   auto ModI = MDC.ModularDeps.insert({M, nullptr});
573fe6060f1SDimitry Andric   if (!ModI.second)
57481ad6265SDimitry Andric     return ModI.first->second->ID;
575480093f4SDimitry Andric 
57681ad6265SDimitry Andric   ModI.first->second = std::make_unique<ModuleDeps>();
57781ad6265SDimitry Andric   ModuleDeps &MD = *ModI.first->second;
578480093f4SDimitry Andric 
579fe6060f1SDimitry Andric   MD.ID.ModuleName = M->getFullModuleName();
580fe6060f1SDimitry Andric   MD.IsSystem = M->IsSystem;
581*0fca6ea1SDimitry Andric   // For modules which use export_as link name, the linked product that of the
582*0fca6ea1SDimitry Andric   // corresponding export_as-named module.
583*0fca6ea1SDimitry Andric   if (!M->UseExportAsModuleLinkName)
584*0fca6ea1SDimitry Andric     MD.LinkLibraries = M->LinkLibraries;
585fe6060f1SDimitry Andric 
586bdd1243dSDimitry Andric   ModuleMap &ModMapInfo =
587bdd1243dSDimitry Andric       MDC.ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
588bdd1243dSDimitry Andric 
589bdd1243dSDimitry Andric   OptionalFileEntryRef ModuleMap = ModMapInfo.getModuleMapFileForUniquing(M);
5900eae32dcSDimitry Andric 
5910eae32dcSDimitry Andric   if (ModuleMap) {
592bdd1243dSDimitry Andric     SmallString<128> Path = ModuleMap->getNameAsRequested();
593bdd1243dSDimitry Andric     ModMapInfo.canonicalizeModuleMapPath(Path);
5940eae32dcSDimitry Andric     MD.ClangModuleMapFile = std::string(Path);
5950eae32dcSDimitry Andric   }
596fe6060f1SDimitry Andric 
597480093f4SDimitry Andric   serialization::ModuleFile *MF =
598349cc55cSDimitry Andric       MDC.ScanInstance.getASTReader()->getModuleManager().lookup(
5995f757f3fSDimitry Andric           *M->getASTFile());
6005f757f3fSDimitry Andric   MDC.ScanInstance.getASTReader()->visitInputFileInfos(
6015f757f3fSDimitry Andric       *MF, /*IncludeSystem=*/true,
6025f757f3fSDimitry Andric       [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
603fe6060f1SDimitry Andric         // __inferred_module.map is the result of the way in which an implicit
604fe6060f1SDimitry Andric         // module build handles inferred modules. It adds an overlay VFS with
605fe6060f1SDimitry Andric         // this file in the proper directory and relies on the rest of Clang to
606fe6060f1SDimitry Andric         // handle it like normal. With explicitly built modules we don't need
607fe6060f1SDimitry Andric         // to play VFS tricks, so replace it with the correct module map.
6085f757f3fSDimitry Andric         if (StringRef(IFI.Filename).ends_with("__inferred_module.map")) {
609bdd1243dSDimitry Andric           MDC.addFileDep(MD, ModuleMap->getName());
610fe6060f1SDimitry Andric           return;
611fe6060f1SDimitry Andric         }
6125f757f3fSDimitry Andric         MDC.addFileDep(MD, IFI.Filename);
613480093f4SDimitry Andric       });
614480093f4SDimitry Andric 
615bdd1243dSDimitry Andric   llvm::DenseSet<const Module *> SeenDeps;
616bdd1243dSDimitry Andric   addAllSubmodulePrebuiltDeps(M, MD, SeenDeps);
617bdd1243dSDimitry Andric   addAllSubmoduleDeps(M, MD, SeenDeps);
618bdd1243dSDimitry Andric   addAllAffectingClangModules(M, MD, SeenDeps);
619bdd1243dSDimitry Andric 
6205f757f3fSDimitry Andric   MDC.ScanInstance.getASTReader()->visitInputFileInfos(
6215f757f3fSDimitry Andric       *MF, /*IncludeSystem=*/true,
6225f757f3fSDimitry Andric       [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
6235f757f3fSDimitry Andric         if (!(IFI.TopLevel && IFI.ModuleMap))
62481ad6265SDimitry Andric           return;
6255f757f3fSDimitry Andric         if (StringRef(IFI.FilenameAsRequested)
6265f757f3fSDimitry Andric                 .ends_with("__inferred_module.map"))
6275f757f3fSDimitry Andric           return;
6285f757f3fSDimitry Andric         MD.ModuleMapFileDeps.emplace_back(IFI.FilenameAsRequested);
62981ad6265SDimitry Andric       });
63081ad6265SDimitry Andric 
6315f757f3fSDimitry Andric   CowCompilerInvocation CI =
6325f757f3fSDimitry Andric       MDC.getInvocationAdjustedForModuleBuildWithoutOutputs(
6335f757f3fSDimitry Andric           MD, [&](CowCompilerInvocation &BuildInvocation) {
634*0fca6ea1SDimitry Andric             if (any(MDC.OptimizeArgs & (ScanningOptimizations::HeaderSearch |
635*0fca6ea1SDimitry Andric                                         ScanningOptimizations::VFS)))
6365f757f3fSDimitry Andric               optimizeHeaderSearchOpts(BuildInvocation.getMutHeaderSearchOpts(),
637*0fca6ea1SDimitry Andric                                        *MDC.ScanInstance.getASTReader(), *MF,
638*0fca6ea1SDimitry Andric                                        MDC.PrebuiltModuleVFSMap,
639*0fca6ea1SDimitry Andric                                        MDC.OptimizeArgs);
6405f757f3fSDimitry Andric             if (any(MDC.OptimizeArgs & ScanningOptimizations::SystemWarnings))
6415f757f3fSDimitry Andric               optimizeDiagnosticOpts(
6425f757f3fSDimitry Andric                   BuildInvocation.getMutDiagnosticOpts(),
6435f757f3fSDimitry Andric                   BuildInvocation.getFrontendOpts().IsSystemModule);
644349cc55cSDimitry Andric           });
645fe6060f1SDimitry Andric 
646bdd1243dSDimitry Andric   MDC.associateWithContextHash(CI, MD);
647bdd1243dSDimitry Andric 
648bdd1243dSDimitry Andric   // Finish the compiler invocation. Requires dependencies and the context hash.
649bdd1243dSDimitry Andric   MDC.addOutputPaths(CI, MD);
650bdd1243dSDimitry Andric 
6515f757f3fSDimitry Andric   MD.BuildInfo = std::move(CI);
652fe6060f1SDimitry Andric 
653fe6060f1SDimitry Andric   return MD.ID;
654fe6060f1SDimitry Andric }
655fe6060f1SDimitry Andric 
65681ad6265SDimitry Andric static void forEachSubmoduleSorted(const Module *M,
65781ad6265SDimitry Andric                                    llvm::function_ref<void(const Module *)> F) {
65881ad6265SDimitry Andric   // Submodule order depends on order of header includes for inferred submodules
65981ad6265SDimitry Andric   // we don't care about the exact order, so sort so that it's consistent across
66081ad6265SDimitry Andric   // TUs to improve sharing.
66106c3fb27SDimitry Andric   SmallVector<const Module *> Submodules(M->submodules());
66281ad6265SDimitry Andric   llvm::stable_sort(Submodules, [](const Module *A, const Module *B) {
66381ad6265SDimitry Andric     return A->Name < B->Name;
66481ad6265SDimitry Andric   });
66581ad6265SDimitry Andric   for (const Module *SubM : Submodules)
66681ad6265SDimitry Andric     F(SubM);
66781ad6265SDimitry Andric }
66881ad6265SDimitry Andric 
669349cc55cSDimitry Andric void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps(
670349cc55cSDimitry Andric     const Module *M, ModuleDeps &MD,
671349cc55cSDimitry Andric     llvm::DenseSet<const Module *> &SeenSubmodules) {
672349cc55cSDimitry Andric   addModulePrebuiltDeps(M, MD, SeenSubmodules);
673349cc55cSDimitry Andric 
67481ad6265SDimitry Andric   forEachSubmoduleSorted(M, [&](const Module *SubM) {
675349cc55cSDimitry Andric     addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules);
67681ad6265SDimitry Andric   });
677349cc55cSDimitry Andric }
678349cc55cSDimitry Andric 
679349cc55cSDimitry Andric void ModuleDepCollectorPP::addModulePrebuiltDeps(
680349cc55cSDimitry Andric     const Module *M, ModuleDeps &MD,
681349cc55cSDimitry Andric     llvm::DenseSet<const Module *> &SeenSubmodules) {
682fe6060f1SDimitry Andric   for (const Module *Import : M->Imports)
683fe6060f1SDimitry Andric     if (Import->getTopLevelModule() != M->getTopLevelModule())
684349cc55cSDimitry Andric       if (MDC.isPrebuiltModule(Import->getTopLevelModule()))
685349cc55cSDimitry Andric         if (SeenSubmodules.insert(Import->getTopLevelModule()).second)
686349cc55cSDimitry Andric           MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule());
687480093f4SDimitry Andric }
688480093f4SDimitry Andric 
6895ffd83dbSDimitry Andric void ModuleDepCollectorPP::addAllSubmoduleDeps(
6905ffd83dbSDimitry Andric     const Module *M, ModuleDeps &MD,
6915ffd83dbSDimitry Andric     llvm::DenseSet<const Module *> &AddedModules) {
6925ffd83dbSDimitry Andric   addModuleDep(M, MD, AddedModules);
693480093f4SDimitry Andric 
69481ad6265SDimitry Andric   forEachSubmoduleSorted(M, [&](const Module *SubM) {
6955ffd83dbSDimitry Andric     addAllSubmoduleDeps(SubM, MD, AddedModules);
69681ad6265SDimitry Andric   });
697480093f4SDimitry Andric }
698480093f4SDimitry Andric 
6995ffd83dbSDimitry Andric void ModuleDepCollectorPP::addModuleDep(
7005ffd83dbSDimitry Andric     const Module *M, ModuleDeps &MD,
7015ffd83dbSDimitry Andric     llvm::DenseSet<const Module *> &AddedModules) {
702480093f4SDimitry Andric   for (const Module *Import : M->Imports) {
703fe6060f1SDimitry Andric     if (Import->getTopLevelModule() != M->getTopLevelModule() &&
704fe6060f1SDimitry Andric         !MDC.isPrebuiltModule(Import)) {
705bdd1243dSDimitry Andric       if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule()))
7065ffd83dbSDimitry Andric         if (AddedModules.insert(Import->getTopLevelModule()).second)
707bdd1243dSDimitry Andric           MD.ClangModuleDeps.push_back(*ImportID);
708bdd1243dSDimitry Andric     }
709bdd1243dSDimitry Andric   }
710bdd1243dSDimitry Andric }
711bdd1243dSDimitry Andric 
712bdd1243dSDimitry Andric void ModuleDepCollectorPP::addAllAffectingClangModules(
713bdd1243dSDimitry Andric     const Module *M, ModuleDeps &MD,
714bdd1243dSDimitry Andric     llvm::DenseSet<const Module *> &AddedModules) {
715bdd1243dSDimitry Andric   addAffectingClangModule(M, MD, AddedModules);
716bdd1243dSDimitry Andric 
717bdd1243dSDimitry Andric   for (const Module *SubM : M->submodules())
718bdd1243dSDimitry Andric     addAllAffectingClangModules(SubM, MD, AddedModules);
719bdd1243dSDimitry Andric }
720bdd1243dSDimitry Andric 
721bdd1243dSDimitry Andric void ModuleDepCollectorPP::addAffectingClangModule(
722bdd1243dSDimitry Andric     const Module *M, ModuleDeps &MD,
723bdd1243dSDimitry Andric     llvm::DenseSet<const Module *> &AddedModules) {
724bdd1243dSDimitry Andric   for (const Module *Affecting : M->AffectingClangModules) {
725bdd1243dSDimitry Andric     assert(Affecting == Affecting->getTopLevelModule() &&
726bdd1243dSDimitry Andric            "Not quite import not top-level module");
727bdd1243dSDimitry Andric     if (Affecting != M->getTopLevelModule() &&
728bdd1243dSDimitry Andric         !MDC.isPrebuiltModule(Affecting)) {
729bdd1243dSDimitry Andric       if (auto ImportID = handleTopLevelModule(Affecting))
730bdd1243dSDimitry Andric         if (AddedModules.insert(Affecting).second)
731bdd1243dSDimitry Andric           MD.ClangModuleDeps.push_back(*ImportID);
732480093f4SDimitry Andric     }
733480093f4SDimitry Andric   }
734480093f4SDimitry Andric }
735480093f4SDimitry Andric 
7365ffd83dbSDimitry Andric ModuleDepCollector::ModuleDepCollector(
737349cc55cSDimitry Andric     std::unique_ptr<DependencyOutputOptions> Opts,
738349cc55cSDimitry Andric     CompilerInstance &ScanInstance, DependencyConsumer &C,
73906c3fb27SDimitry Andric     DependencyActionController &Controller, CompilerInvocation OriginalCI,
740*0fca6ea1SDimitry Andric     PrebuiltModuleVFSMapT PrebuiltModuleVFSMap,
7415f757f3fSDimitry Andric     ScanningOptimizations OptimizeArgs, bool EagerLoadModules,
7425f757f3fSDimitry Andric     bool IsStdModuleP1689Format)
74306c3fb27SDimitry Andric     : ScanInstance(ScanInstance), Consumer(C), Controller(Controller),
744*0fca6ea1SDimitry Andric       PrebuiltModuleVFSMap(std::move(PrebuiltModuleVFSMap)),
7455f757f3fSDimitry Andric       Opts(std::move(Opts)),
7465f757f3fSDimitry Andric       CommonInvocation(
7475f757f3fSDimitry Andric           makeCommonInvocationForModuleBuild(std::move(OriginalCI))),
74806c3fb27SDimitry Andric       OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules),
7491ac55f4cSDimitry Andric       IsStdModuleP1689Format(IsStdModuleP1689Format) {}
750480093f4SDimitry Andric 
751480093f4SDimitry Andric void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) {
752349cc55cSDimitry Andric   PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this));
753480093f4SDimitry Andric }
754480093f4SDimitry Andric 
755480093f4SDimitry Andric void ModuleDepCollector::attachToASTReader(ASTReader &R) {}
756fe6060f1SDimitry Andric 
757fe6060f1SDimitry Andric bool ModuleDepCollector::isPrebuiltModule(const Module *M) {
758fe6060f1SDimitry Andric   std::string Name(M->getTopLevelModuleName());
759fe6060f1SDimitry Andric   const auto &PrebuiltModuleFiles =
760349cc55cSDimitry Andric       ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles;
761fe6060f1SDimitry Andric   auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name);
762fe6060f1SDimitry Andric   if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end())
763fe6060f1SDimitry Andric     return false;
764fe6060f1SDimitry Andric   assert("Prebuilt module came from the expected AST file" &&
765fe6060f1SDimitry Andric          PrebuiltModuleFileIt->second == M->getASTFile()->getName());
766fe6060f1SDimitry Andric   return true;
767fe6060f1SDimitry Andric }
768bdd1243dSDimitry Andric 
769bdd1243dSDimitry Andric static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path,
770bdd1243dSDimitry Andric                                           SmallVectorImpl<char> &Storage) {
771bdd1243dSDimitry Andric   if (llvm::sys::path::is_absolute(Path) &&
772bdd1243dSDimitry Andric       !llvm::sys::path::is_style_windows(llvm::sys::path::Style::native))
773bdd1243dSDimitry Andric     return Path;
774bdd1243dSDimitry Andric   Storage.assign(Path.begin(), Path.end());
775bdd1243dSDimitry Andric   CI.getFileManager().makeAbsolutePath(Storage);
776bdd1243dSDimitry Andric   llvm::sys::path::make_preferred(Storage);
777bdd1243dSDimitry Andric   return StringRef(Storage.data(), Storage.size());
778bdd1243dSDimitry Andric }
779bdd1243dSDimitry Andric 
780bdd1243dSDimitry Andric void ModuleDepCollector::addFileDep(StringRef Path) {
7815f757f3fSDimitry Andric   if (IsStdModuleP1689Format) {
7825f757f3fSDimitry Andric     // Within P1689 format, we don't want all the paths to be absolute path
7835f757f3fSDimitry Andric     // since it may violate the tranditional make style dependencies info.
7845f757f3fSDimitry Andric     FileDeps.push_back(std::string(Path));
7855f757f3fSDimitry Andric     return;
7865f757f3fSDimitry Andric   }
7875f757f3fSDimitry Andric 
788bdd1243dSDimitry Andric   llvm::SmallString<256> Storage;
789bdd1243dSDimitry Andric   Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
790bdd1243dSDimitry Andric   FileDeps.push_back(std::string(Path));
791bdd1243dSDimitry Andric }
792bdd1243dSDimitry Andric 
793bdd1243dSDimitry Andric void ModuleDepCollector::addFileDep(ModuleDeps &MD, StringRef Path) {
7945f757f3fSDimitry Andric   if (IsStdModuleP1689Format) {
7955f757f3fSDimitry Andric     MD.FileDeps.insert(Path);
7965f757f3fSDimitry Andric     return;
7975f757f3fSDimitry Andric   }
7985f757f3fSDimitry Andric 
799bdd1243dSDimitry Andric   llvm::SmallString<256> Storage;
800bdd1243dSDimitry Andric   Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
801bdd1243dSDimitry Andric   MD.FileDeps.insert(Path);
802bdd1243dSDimitry Andric }
803