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
getBuildArguments()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
optimizeHeaderSearchOpts(HeaderSearchOptions & Opts,ASTReader & Reader,const serialization::ModuleFile & MF,const PrebuiltModuleVFSMapT & PrebuiltModuleVFSMap,ScanningOptimizations OptimizeArgs)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
optimizeDiagnosticOpts(DiagnosticOptions & Opts,bool IsSystemModule)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
splitString(std::string S,char Separator)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
addOutputPaths(CowCompilerInvocation & CI,ModuleDeps & Deps)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
resetBenignCodeGenOptions(frontend::ActionKind ProgramAction,const LangOptions & LangOpts,CodeGenOptions & CGOpts)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
makeCommonInvocationForModuleBuild(CompilerInvocation CI)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
getInvocationAdjustedForModuleBuildWithoutOutputs(const ModuleDeps & Deps,llvm::function_ref<void (CowCompilerInvocation &)> Optimize) const2295f757f3fSDimitry 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
collectModuleMapFiles(ArrayRef<ModuleID> ClangModuleDeps) const295bdd1243dSDimitry 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
addModuleMapFiles(CompilerInvocation & CI,ArrayRef<ModuleID> ClangModuleDeps) const309bdd1243dSDimitry 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
addModuleFiles(CompilerInvocation & CI,ArrayRef<ModuleID> ClangModuleDeps) const321bdd1243dSDimitry 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
addModuleFiles(CowCompilerInvocation & CI,ArrayRef<ModuleID> ClangModuleDeps) const3345f757f3fSDimitry 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
needsModules(FrontendInputFile FIF)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
applyDiscoveredDependencies(CompilerInvocation & CI)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
getModuleContextHash(const ModuleDeps & MD,const CowCompilerInvocation & CI,bool EagerLoadModules,llvm::vfs::FileSystem & VFS)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
associateWithContextHash(const CowCompilerInvocation & CI,ModuleDeps & Deps)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
LexedFileChanged(FileID FID,LexedFileChangeReason Reason,SrcMgr::CharacteristicKind FileType,FileID PrevFID,SourceLocation Loc)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
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,OptionalFileEntryRef File,StringRef SearchPath,StringRef RelativePath,const Module * SuggestedModule,bool ModuleImported,SrcMgr::CharacteristicKind FileType)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
moduleImport(SourceLocation ImportLoc,ModuleIdPath Path,const Module * Imported)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
handleImport(const Module * Imported)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
EndOfMainFile()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>
handleTopLevelModule(const Module * M)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
forEachSubmoduleSorted(const Module * M,llvm::function_ref<void (const Module *)> F)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
addAllSubmodulePrebuiltDeps(const Module * M,ModuleDeps & MD,llvm::DenseSet<const Module * > & SeenSubmodules)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
addModulePrebuiltDeps(const Module * M,ModuleDeps & MD,llvm::DenseSet<const Module * > & SeenSubmodules)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
addAllSubmoduleDeps(const Module * M,ModuleDeps & MD,llvm::DenseSet<const Module * > & AddedModules)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
addModuleDep(const Module * M,ModuleDeps & MD,llvm::DenseSet<const Module * > & AddedModules)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
addAllAffectingClangModules(const Module * M,ModuleDeps & MD,llvm::DenseSet<const Module * > & AddedModules)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
addAffectingClangModule(const Module * M,ModuleDeps & MD,llvm::DenseSet<const Module * > & AddedModules)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
ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts,CompilerInstance & ScanInstance,DependencyConsumer & C,DependencyActionController & Controller,CompilerInvocation OriginalCI,PrebuiltModuleVFSMapT PrebuiltModuleVFSMap,ScanningOptimizations OptimizeArgs,bool EagerLoadModules,bool IsStdModuleP1689Format)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
attachToPreprocessor(Preprocessor & PP)751480093f4SDimitry Andric void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) {
752349cc55cSDimitry Andric PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this));
753480093f4SDimitry Andric }
754480093f4SDimitry Andric
attachToASTReader(ASTReader & R)755480093f4SDimitry Andric void ModuleDepCollector::attachToASTReader(ASTReader &R) {}
756fe6060f1SDimitry Andric
isPrebuiltModule(const Module * M)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
makeAbsoluteAndPreferred(CompilerInstance & CI,StringRef Path,SmallVectorImpl<char> & Storage)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
addFileDep(StringRef Path)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
addFileDep(ModuleDeps & MD,StringRef Path)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