xref: /freebsd-src/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp (revision 1ac55f4cb0001fed92329746c730aa9a947c09a5)
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"
15bdd1243dSDimitry Andric #include "llvm/Support/BLAKE3.h"
16fe6060f1SDimitry Andric #include "llvm/Support/StringSaver.h"
17bdd1243dSDimitry Andric #include <optional>
18480093f4SDimitry Andric 
19480093f4SDimitry Andric using namespace clang;
20480093f4SDimitry Andric using namespace tooling;
21480093f4SDimitry Andric using namespace dependencies;
22480093f4SDimitry Andric 
23349cc55cSDimitry Andric static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts,
24349cc55cSDimitry Andric                                      ASTReader &Reader,
25349cc55cSDimitry Andric                                      const serialization::ModuleFile &MF) {
26349cc55cSDimitry Andric   // Only preserve search paths that were used during the dependency scan.
27349cc55cSDimitry Andric   std::vector<HeaderSearchOptions::Entry> Entries = Opts.UserEntries;
28349cc55cSDimitry Andric   Opts.UserEntries.clear();
2981ad6265SDimitry Andric 
3081ad6265SDimitry Andric   llvm::BitVector SearchPathUsage(Entries.size());
3181ad6265SDimitry Andric   llvm::DenseSet<const serialization::ModuleFile *> Visited;
3281ad6265SDimitry Andric   std::function<void(const serialization::ModuleFile *)> VisitMF =
3381ad6265SDimitry Andric       [&](const serialization::ModuleFile *MF) {
3481ad6265SDimitry Andric         SearchPathUsage |= MF->SearchPathUsage;
3581ad6265SDimitry Andric         Visited.insert(MF);
3681ad6265SDimitry Andric         for (const serialization::ModuleFile *Import : MF->Imports)
3781ad6265SDimitry Andric           if (!Visited.contains(Import))
3881ad6265SDimitry Andric             VisitMF(Import);
3981ad6265SDimitry Andric       };
4081ad6265SDimitry Andric   VisitMF(&MF);
4181ad6265SDimitry Andric 
4281ad6265SDimitry Andric   for (auto Idx : SearchPathUsage.set_bits())
4381ad6265SDimitry Andric     Opts.UserEntries.push_back(Entries[Idx]);
44349cc55cSDimitry Andric }
45349cc55cSDimitry Andric 
46753f127fSDimitry Andric static std::vector<std::string> splitString(std::string S, char Separator) {
47753f127fSDimitry Andric   SmallVector<StringRef> Segments;
48753f127fSDimitry Andric   StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false);
49753f127fSDimitry Andric   std::vector<std::string> Result;
50753f127fSDimitry Andric   Result.reserve(Segments.size());
51753f127fSDimitry Andric   for (StringRef Segment : Segments)
52753f127fSDimitry Andric     Result.push_back(Segment.str());
53753f127fSDimitry Andric   return Result;
54753f127fSDimitry Andric }
55753f127fSDimitry Andric 
56bdd1243dSDimitry Andric void ModuleDepCollector::addOutputPaths(CompilerInvocation &CI,
57bdd1243dSDimitry Andric                                         ModuleDeps &Deps) {
58bdd1243dSDimitry Andric   CI.getFrontendOpts().OutputFile =
59bdd1243dSDimitry Andric       Consumer.lookupModuleOutput(Deps.ID, ModuleOutputKind::ModuleFile);
60bdd1243dSDimitry Andric   if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty())
61753f127fSDimitry Andric     CI.getDiagnosticOpts().DiagnosticSerializationFile =
62bdd1243dSDimitry Andric         Consumer.lookupModuleOutput(
63bdd1243dSDimitry Andric             Deps.ID, ModuleOutputKind::DiagnosticSerializationFile);
64bdd1243dSDimitry Andric   if (!CI.getDependencyOutputOpts().OutputFile.empty()) {
65bdd1243dSDimitry Andric     CI.getDependencyOutputOpts().OutputFile =
66bdd1243dSDimitry Andric         Consumer.lookupModuleOutput(Deps.ID, ModuleOutputKind::DependencyFile);
67bdd1243dSDimitry Andric     CI.getDependencyOutputOpts().Targets =
68bdd1243dSDimitry Andric         splitString(Consumer.lookupModuleOutput(
69bdd1243dSDimitry Andric                         Deps.ID, ModuleOutputKind::DependencyTargets),
70bdd1243dSDimitry Andric                     '\0');
71bdd1243dSDimitry Andric     if (!CI.getDependencyOutputOpts().OutputFile.empty() &&
72bdd1243dSDimitry Andric         CI.getDependencyOutputOpts().Targets.empty()) {
73753f127fSDimitry Andric       // Fallback to -o as dependency target, as in the driver.
74753f127fSDimitry Andric       SmallString<128> Target;
75bdd1243dSDimitry Andric       quoteMakeTarget(CI.getFrontendOpts().OutputFile, Target);
76bdd1243dSDimitry Andric       CI.getDependencyOutputOpts().Targets.push_back(std::string(Target));
77bdd1243dSDimitry Andric     }
78753f127fSDimitry Andric   }
79753f127fSDimitry Andric }
80fe6060f1SDimitry Andric 
81bdd1243dSDimitry Andric CompilerInvocation
82bdd1243dSDimitry Andric ModuleDepCollector::makeInvocationForModuleBuildWithoutOutputs(
83bdd1243dSDimitry Andric     const ModuleDeps &Deps,
84bdd1243dSDimitry Andric     llvm::function_ref<void(CompilerInvocation &)> Optimize) const {
85bdd1243dSDimitry Andric   // Make a deep copy of the original Clang invocation.
86bdd1243dSDimitry Andric   CompilerInvocation CI(OriginalInvocation);
87fe6060f1SDimitry Andric 
88bdd1243dSDimitry Andric   CI.resetNonModularOptions();
89bdd1243dSDimitry Andric   CI.clearImplicitModuleBuildOptions();
90bdd1243dSDimitry Andric 
91bdd1243dSDimitry Andric   // Remove options incompatible with explicit module build or are likely to
92bdd1243dSDimitry Andric   // differ between identical modules discovered from different translation
93bdd1243dSDimitry Andric   // units.
94bdd1243dSDimitry Andric   CI.getFrontendOpts().Inputs.clear();
95bdd1243dSDimitry Andric   CI.getFrontendOpts().OutputFile.clear();
96bdd1243dSDimitry Andric 
97bdd1243dSDimitry Andric   // TODO: Figure out better way to set options to their default value.
98bdd1243dSDimitry Andric   CI.getCodeGenOpts().MainFileName.clear();
99bdd1243dSDimitry Andric   CI.getCodeGenOpts().DwarfDebugFlags.clear();
100bdd1243dSDimitry Andric   if (!CI.getLangOpts()->ModulesCodegen) {
101bdd1243dSDimitry Andric     CI.getCodeGenOpts().DebugCompilationDir.clear();
102bdd1243dSDimitry Andric     CI.getCodeGenOpts().CoverageCompilationDir.clear();
103fe6060f1SDimitry Andric   }
104fe6060f1SDimitry Andric 
105bdd1243dSDimitry Andric   // Map output paths that affect behaviour to "-" so their existence is in the
106bdd1243dSDimitry Andric   // context hash. The final path will be computed in addOutputPaths.
107bdd1243dSDimitry Andric   if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty())
108bdd1243dSDimitry Andric     CI.getDiagnosticOpts().DiagnosticSerializationFile = "-";
109bdd1243dSDimitry Andric   if (!CI.getDependencyOutputOpts().OutputFile.empty())
110bdd1243dSDimitry Andric     CI.getDependencyOutputOpts().OutputFile = "-";
111bdd1243dSDimitry Andric   CI.getDependencyOutputOpts().Targets.clear();
112bdd1243dSDimitry Andric 
113bdd1243dSDimitry Andric   CI.getFrontendOpts().ProgramAction = frontend::GenerateModule;
114bdd1243dSDimitry Andric   CI.getLangOpts()->ModuleName = Deps.ID.ModuleName;
115bdd1243dSDimitry Andric   CI.getFrontendOpts().IsSystemModule = Deps.IsSystem;
116bdd1243dSDimitry Andric 
117bdd1243dSDimitry Andric   // Inputs
118bdd1243dSDimitry Andric   InputKind ModuleMapInputKind(CI.getFrontendOpts().DashX.getLanguage(),
119bdd1243dSDimitry Andric                                InputKind::Format::ModuleMap);
120bdd1243dSDimitry Andric   CI.getFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile,
121bdd1243dSDimitry Andric                                            ModuleMapInputKind);
122bdd1243dSDimitry Andric 
123bdd1243dSDimitry Andric   auto CurrentModuleMapEntry =
124bdd1243dSDimitry Andric       ScanInstance.getFileManager().getFile(Deps.ClangModuleMapFile);
125bdd1243dSDimitry Andric   assert(CurrentModuleMapEntry && "module map file entry not found");
126bdd1243dSDimitry Andric 
127bdd1243dSDimitry Andric   auto DepModuleMapFiles = collectModuleMapFiles(Deps.ClangModuleDeps);
128bdd1243dSDimitry Andric   for (StringRef ModuleMapFile : Deps.ModuleMapFileDeps) {
129bdd1243dSDimitry Andric     // TODO: Track these as `FileEntryRef` to simplify the equality check below.
130bdd1243dSDimitry Andric     auto ModuleMapEntry = ScanInstance.getFileManager().getFile(ModuleMapFile);
131bdd1243dSDimitry Andric     assert(ModuleMapEntry && "module map file entry not found");
132bdd1243dSDimitry Andric 
133bdd1243dSDimitry Andric     // Don't report module maps describing eagerly-loaded dependency. This
134bdd1243dSDimitry Andric     // information will be deserialized from the PCM.
135bdd1243dSDimitry Andric     // TODO: Verify this works fine when modulemap for module A is eagerly
136bdd1243dSDimitry Andric     // loaded from A.pcm, and module map passed on the command line contains
137bdd1243dSDimitry Andric     // definition of a submodule: "explicit module A.Private { ... }".
138bdd1243dSDimitry Andric     if (EagerLoadModules && DepModuleMapFiles.contains(*ModuleMapEntry))
139bdd1243dSDimitry Andric       continue;
140bdd1243dSDimitry Andric 
141bdd1243dSDimitry Andric     // Don't report module map file of the current module unless it also
142bdd1243dSDimitry Andric     // describes a dependency (for symmetry).
143bdd1243dSDimitry Andric     if (*ModuleMapEntry == *CurrentModuleMapEntry &&
144bdd1243dSDimitry Andric         !DepModuleMapFiles.contains(*ModuleMapEntry))
145bdd1243dSDimitry Andric       continue;
146bdd1243dSDimitry Andric 
147bdd1243dSDimitry Andric     CI.getFrontendOpts().ModuleMapFiles.emplace_back(ModuleMapFile);
148bdd1243dSDimitry Andric   }
149bdd1243dSDimitry Andric 
150bdd1243dSDimitry Andric   // Report the prebuilt modules this module uses.
151bdd1243dSDimitry Andric   for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps)
152bdd1243dSDimitry Andric     CI.getFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile);
153bdd1243dSDimitry Andric 
154bdd1243dSDimitry Andric   // Add module file inputs from dependencies.
155bdd1243dSDimitry Andric   addModuleFiles(CI, Deps.ClangModuleDeps);
156bdd1243dSDimitry Andric 
157bdd1243dSDimitry Andric   // Remove any macro definitions that are explicitly ignored.
158bdd1243dSDimitry Andric   if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) {
159bdd1243dSDimitry Andric     llvm::erase_if(
160bdd1243dSDimitry Andric         CI.getPreprocessorOpts().Macros,
161bdd1243dSDimitry Andric         [&CI](const std::pair<std::string, bool> &Def) {
162bdd1243dSDimitry Andric           StringRef MacroDef = Def.first;
163bdd1243dSDimitry Andric           return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains(
164bdd1243dSDimitry Andric               llvm::CachedHashString(MacroDef.split('=').first));
165bdd1243dSDimitry Andric         });
166bdd1243dSDimitry Andric     // Remove the now unused option.
167bdd1243dSDimitry Andric     CI.getHeaderSearchOpts().ModulesIgnoreMacros.clear();
168bdd1243dSDimitry Andric   }
169bdd1243dSDimitry Andric 
170bdd1243dSDimitry Andric   Optimize(CI);
171bdd1243dSDimitry Andric 
172bdd1243dSDimitry Andric   return CI;
173bdd1243dSDimitry Andric }
174bdd1243dSDimitry Andric 
175bdd1243dSDimitry Andric llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles(
176bdd1243dSDimitry Andric     ArrayRef<ModuleID> ClangModuleDeps) const {
177bdd1243dSDimitry Andric   llvm::DenseSet<const FileEntry *> ModuleMapFiles;
178bdd1243dSDimitry Andric   for (const ModuleID &MID : ClangModuleDeps) {
179bdd1243dSDimitry Andric     ModuleDeps *MD = ModuleDepsByID.lookup(MID);
180bdd1243dSDimitry Andric     assert(MD && "Inconsistent dependency info");
181bdd1243dSDimitry Andric     // TODO: Track ClangModuleMapFile as `FileEntryRef`.
182bdd1243dSDimitry Andric     auto FE = ScanInstance.getFileManager().getFile(MD->ClangModuleMapFile);
183bdd1243dSDimitry Andric     assert(FE && "Missing module map file that was previously found");
184bdd1243dSDimitry Andric     ModuleMapFiles.insert(*FE);
185bdd1243dSDimitry Andric   }
186bdd1243dSDimitry Andric   return ModuleMapFiles;
187bdd1243dSDimitry Andric }
188bdd1243dSDimitry Andric 
189bdd1243dSDimitry Andric void ModuleDepCollector::addModuleMapFiles(
190bdd1243dSDimitry Andric     CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
191bdd1243dSDimitry Andric   if (EagerLoadModules)
192bdd1243dSDimitry Andric     return; // Only pcm is needed for eager load.
193bdd1243dSDimitry Andric 
194bdd1243dSDimitry Andric   for (const ModuleID &MID : ClangModuleDeps) {
195bdd1243dSDimitry Andric     ModuleDeps *MD = ModuleDepsByID.lookup(MID);
196bdd1243dSDimitry Andric     assert(MD && "Inconsistent dependency info");
197bdd1243dSDimitry Andric     CI.getFrontendOpts().ModuleMapFiles.push_back(MD->ClangModuleMapFile);
198bdd1243dSDimitry Andric   }
199bdd1243dSDimitry Andric }
200bdd1243dSDimitry Andric 
201bdd1243dSDimitry Andric void ModuleDepCollector::addModuleFiles(
202bdd1243dSDimitry Andric     CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
203bdd1243dSDimitry Andric   for (const ModuleID &MID : ClangModuleDeps) {
204bdd1243dSDimitry Andric     std::string PCMPath =
205bdd1243dSDimitry Andric         Consumer.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile);
206bdd1243dSDimitry Andric     if (EagerLoadModules)
207bdd1243dSDimitry Andric       CI.getFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
208bdd1243dSDimitry Andric     else
209bdd1243dSDimitry Andric       CI.getHeaderSearchOpts().PrebuiltModuleFiles.insert(
210bdd1243dSDimitry Andric           {MID.ModuleName, std::move(PCMPath)});
211bdd1243dSDimitry Andric   }
212bdd1243dSDimitry Andric }
213bdd1243dSDimitry Andric 
214bdd1243dSDimitry Andric static bool needsModules(FrontendInputFile FIF) {
215bdd1243dSDimitry Andric   switch (FIF.getKind().getLanguage()) {
216bdd1243dSDimitry Andric   case Language::Unknown:
217bdd1243dSDimitry Andric   case Language::Asm:
218bdd1243dSDimitry Andric   case Language::LLVM_IR:
219bdd1243dSDimitry Andric     return false;
220bdd1243dSDimitry Andric   default:
221bdd1243dSDimitry Andric     return true;
222bdd1243dSDimitry Andric   }
223bdd1243dSDimitry Andric }
224bdd1243dSDimitry Andric 
225bdd1243dSDimitry Andric void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) {
226bdd1243dSDimitry Andric   CI.clearImplicitModuleBuildOptions();
227bdd1243dSDimitry Andric 
228bdd1243dSDimitry Andric   if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) {
229bdd1243dSDimitry Andric     Preprocessor &PP = ScanInstance.getPreprocessor();
230bdd1243dSDimitry Andric     if (Module *CurrentModule = PP.getCurrentModuleImplementation())
231bdd1243dSDimitry Andric       if (OptionalFileEntryRef CurrentModuleMap =
232bdd1243dSDimitry Andric               PP.getHeaderSearchInfo()
233bdd1243dSDimitry Andric                   .getModuleMap()
234bdd1243dSDimitry Andric                   .getModuleMapFileForUniquing(CurrentModule))
235bdd1243dSDimitry Andric         CI.getFrontendOpts().ModuleMapFiles.emplace_back(
236bdd1243dSDimitry Andric             CurrentModuleMap->getName());
237bdd1243dSDimitry Andric 
238bdd1243dSDimitry Andric     SmallVector<ModuleID> DirectDeps;
239bdd1243dSDimitry Andric     for (const auto &KV : ModularDeps)
240bdd1243dSDimitry Andric       if (KV.second->ImportedByMainFile)
241bdd1243dSDimitry Andric         DirectDeps.push_back(KV.second->ID);
242bdd1243dSDimitry Andric 
243bdd1243dSDimitry Andric     // TODO: Report module maps the same way it's done for modular dependencies.
244bdd1243dSDimitry Andric     addModuleMapFiles(CI, DirectDeps);
245bdd1243dSDimitry Andric 
246bdd1243dSDimitry Andric     addModuleFiles(CI, DirectDeps);
247bdd1243dSDimitry Andric 
248bdd1243dSDimitry Andric     for (const auto &KV : DirectPrebuiltModularDeps)
249bdd1243dSDimitry Andric       CI.getFrontendOpts().ModuleFiles.push_back(KV.second.PCMFile);
250bdd1243dSDimitry Andric   }
251bdd1243dSDimitry Andric }
252bdd1243dSDimitry Andric 
253bdd1243dSDimitry Andric static std::string getModuleContextHash(const ModuleDeps &MD,
254bdd1243dSDimitry Andric                                         const CompilerInvocation &CI,
255bdd1243dSDimitry Andric                                         bool EagerLoadModules) {
256bdd1243dSDimitry Andric   llvm::HashBuilder<llvm::TruncatedBLAKE3<16>,
257bdd1243dSDimitry Andric                     llvm::support::endianness::native>
258bdd1243dSDimitry Andric       HashBuilder;
259bdd1243dSDimitry Andric   SmallString<32> Scratch;
260bdd1243dSDimitry Andric 
261bdd1243dSDimitry Andric   // Hash the compiler version and serialization version to ensure the module
262bdd1243dSDimitry Andric   // will be readable.
263bdd1243dSDimitry Andric   HashBuilder.add(getClangFullRepositoryVersion());
264bdd1243dSDimitry Andric   HashBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR);
265bdd1243dSDimitry Andric 
266bdd1243dSDimitry Andric   // Hash the BuildInvocation without any input files.
267bdd1243dSDimitry Andric   SmallVector<const char *, 32> DummyArgs;
268bdd1243dSDimitry Andric   CI.generateCC1CommandLine(DummyArgs, [&](const Twine &Arg) {
269bdd1243dSDimitry Andric     Scratch.clear();
270bdd1243dSDimitry Andric     StringRef Str = Arg.toStringRef(Scratch);
271bdd1243dSDimitry Andric     HashBuilder.add(Str);
272bdd1243dSDimitry Andric     return "<unused>";
273bdd1243dSDimitry Andric   });
274bdd1243dSDimitry Andric 
275bdd1243dSDimitry Andric   // Hash the module dependencies. These paths may differ even if the invocation
276bdd1243dSDimitry Andric   // is identical if they depend on the contents of the files in the TU -- for
277bdd1243dSDimitry Andric   // example, case-insensitive paths to modulemap files. Usually such a case
278bdd1243dSDimitry Andric   // would indicate a missed optimization to canonicalize, but it may be
279bdd1243dSDimitry Andric   // difficult to canonicalize all cases when there is a VFS.
280bdd1243dSDimitry Andric   for (const auto &ID : MD.ClangModuleDeps) {
281bdd1243dSDimitry Andric     HashBuilder.add(ID.ModuleName);
282bdd1243dSDimitry Andric     HashBuilder.add(ID.ContextHash);
283bdd1243dSDimitry Andric   }
284bdd1243dSDimitry Andric 
285bdd1243dSDimitry Andric   HashBuilder.add(EagerLoadModules);
286bdd1243dSDimitry Andric 
287bdd1243dSDimitry Andric   llvm::BLAKE3Result<16> Hash = HashBuilder.final();
288bdd1243dSDimitry Andric   std::array<uint64_t, 2> Words;
289bdd1243dSDimitry Andric   static_assert(sizeof(Hash) == sizeof(Words), "Hash must match Words");
290bdd1243dSDimitry Andric   std::memcpy(Words.data(), Hash.data(), sizeof(Hash));
291bdd1243dSDimitry Andric   return toString(llvm::APInt(sizeof(Words) * 8, Words), 36, /*Signed=*/false);
292bdd1243dSDimitry Andric }
293bdd1243dSDimitry Andric 
294bdd1243dSDimitry Andric void ModuleDepCollector::associateWithContextHash(const CompilerInvocation &CI,
295bdd1243dSDimitry Andric                                                   ModuleDeps &Deps) {
296bdd1243dSDimitry Andric   Deps.ID.ContextHash = getModuleContextHash(Deps, CI, EagerLoadModules);
297bdd1243dSDimitry Andric   bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second;
298bdd1243dSDimitry Andric   (void)Inserted;
299bdd1243dSDimitry Andric   assert(Inserted && "duplicate module mapping");
300fe6060f1SDimitry Andric }
301fe6060f1SDimitry Andric 
302480093f4SDimitry Andric void ModuleDepCollectorPP::FileChanged(SourceLocation Loc,
303480093f4SDimitry Andric                                        FileChangeReason Reason,
304480093f4SDimitry Andric                                        SrcMgr::CharacteristicKind FileType,
305480093f4SDimitry Andric                                        FileID PrevFID) {
306480093f4SDimitry Andric   if (Reason != PPCallbacks::EnterFile)
307480093f4SDimitry Andric     return;
308480093f4SDimitry Andric 
3095ffd83dbSDimitry Andric   // This has to be delayed as the context hash can change at the start of
3105ffd83dbSDimitry Andric   // `CompilerInstance::ExecuteAction`.
3115ffd83dbSDimitry Andric   if (MDC.ContextHash.empty()) {
312349cc55cSDimitry Andric     MDC.ContextHash = MDC.ScanInstance.getInvocation().getModuleHash();
3135ffd83dbSDimitry Andric     MDC.Consumer.handleContextHash(MDC.ContextHash);
3145ffd83dbSDimitry Andric   }
3155ffd83dbSDimitry Andric 
316349cc55cSDimitry Andric   SourceManager &SM = MDC.ScanInstance.getSourceManager();
317480093f4SDimitry Andric 
318480093f4SDimitry Andric   // Dependency generation really does want to go all the way to the
319480093f4SDimitry Andric   // file entry for a source location to find out what is depended on.
320480093f4SDimitry Andric   // We do not want #line markers to affect dependency generation!
321bdd1243dSDimitry Andric   if (std::optional<StringRef> Filename =
322e8d8bef9SDimitry Andric           SM.getNonBuiltinFilenameForID(SM.getFileID(SM.getExpansionLoc(Loc))))
323bdd1243dSDimitry Andric     MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*Filename));
324480093f4SDimitry Andric }
325480093f4SDimitry Andric 
326480093f4SDimitry Andric void ModuleDepCollectorPP::InclusionDirective(
327480093f4SDimitry Andric     SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
328bdd1243dSDimitry Andric     bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
329480093f4SDimitry Andric     StringRef SearchPath, StringRef RelativePath, const Module *Imported,
330480093f4SDimitry Andric     SrcMgr::CharacteristicKind FileType) {
331480093f4SDimitry Andric   if (!File && !Imported) {
332480093f4SDimitry Andric     // This is a non-modular include that HeaderSearch failed to find. Add it
333480093f4SDimitry Andric     // here as `FileChanged` will never see it.
334bdd1243dSDimitry Andric     MDC.addFileDep(FileName);
3355ffd83dbSDimitry Andric   }
3365ffd83dbSDimitry Andric   handleImport(Imported);
337480093f4SDimitry Andric }
338480093f4SDimitry Andric 
3395ffd83dbSDimitry Andric void ModuleDepCollectorPP::moduleImport(SourceLocation ImportLoc,
3405ffd83dbSDimitry Andric                                         ModuleIdPath Path,
3415ffd83dbSDimitry Andric                                         const Module *Imported) {
342*1ac55f4cSDimitry Andric   if (MDC.ScanInstance.getPreprocessor().isInImportingCXXNamedModules()) {
343*1ac55f4cSDimitry Andric     P1689ModuleInfo RequiredModule;
344*1ac55f4cSDimitry Andric     RequiredModule.ModuleName = Path[0].first->getName().str();
345*1ac55f4cSDimitry Andric     RequiredModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule;
346*1ac55f4cSDimitry Andric     MDC.RequiredStdCXXModules.push_back(RequiredModule);
347*1ac55f4cSDimitry Andric     return;
348*1ac55f4cSDimitry Andric   }
349*1ac55f4cSDimitry Andric 
3505ffd83dbSDimitry Andric   handleImport(Imported);
3515ffd83dbSDimitry Andric }
3525ffd83dbSDimitry Andric 
3535ffd83dbSDimitry Andric void ModuleDepCollectorPP::handleImport(const Module *Imported) {
354480093f4SDimitry Andric   if (!Imported)
355480093f4SDimitry Andric     return;
356480093f4SDimitry Andric 
357fe6060f1SDimitry Andric   const Module *TopLevelModule = Imported->getTopLevelModule();
358fe6060f1SDimitry Andric 
359fe6060f1SDimitry Andric   if (MDC.isPrebuiltModule(TopLevelModule))
360bdd1243dSDimitry Andric     MDC.DirectPrebuiltModularDeps.insert(
361bdd1243dSDimitry Andric         {TopLevelModule, PrebuiltModuleDep{TopLevelModule}});
362fe6060f1SDimitry Andric   else
363fe6060f1SDimitry Andric     DirectModularDeps.insert(TopLevelModule);
364480093f4SDimitry Andric }
365480093f4SDimitry Andric 
366480093f4SDimitry Andric void ModuleDepCollectorPP::EndOfMainFile() {
367349cc55cSDimitry Andric   FileID MainFileID = MDC.ScanInstance.getSourceManager().getMainFileID();
368349cc55cSDimitry Andric   MDC.MainFile = std::string(MDC.ScanInstance.getSourceManager()
369349cc55cSDimitry Andric                                  .getFileEntryForID(MainFileID)
370349cc55cSDimitry Andric                                  ->getName());
371480093f4SDimitry Andric 
372*1ac55f4cSDimitry Andric   auto &PP = MDC.ScanInstance.getPreprocessor();
373*1ac55f4cSDimitry Andric   if (PP.isInNamedModule()) {
374*1ac55f4cSDimitry Andric     P1689ModuleInfo ProvidedModule;
375*1ac55f4cSDimitry Andric     ProvidedModule.ModuleName = PP.getNamedModuleName();
376*1ac55f4cSDimitry Andric     ProvidedModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule;
377*1ac55f4cSDimitry Andric     ProvidedModule.IsStdCXXModuleInterface = PP.isInNamedInterfaceUnit();
378*1ac55f4cSDimitry Andric     // Don't put implementation (non partition) unit as Provide.
379*1ac55f4cSDimitry Andric     // Put the module as required instead. Since the implementation
380*1ac55f4cSDimitry Andric     // unit will import the primary module implicitly.
381*1ac55f4cSDimitry Andric     if (PP.isInImplementationUnit())
382*1ac55f4cSDimitry Andric       MDC.RequiredStdCXXModules.push_back(ProvidedModule);
383*1ac55f4cSDimitry Andric     else
384*1ac55f4cSDimitry Andric       MDC.ProvidedStdCXXModule = ProvidedModule;
385*1ac55f4cSDimitry Andric   }
386*1ac55f4cSDimitry Andric 
387349cc55cSDimitry Andric   if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
388bdd1243dSDimitry Andric     MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude);
389fe6060f1SDimitry Andric 
390bdd1243dSDimitry Andric   for (const Module *M :
391bdd1243dSDimitry Andric        MDC.ScanInstance.getPreprocessor().getAffectingClangModules())
392bdd1243dSDimitry Andric     if (!MDC.isPrebuiltModule(M))
393bdd1243dSDimitry Andric       DirectModularDeps.insert(M);
394bdd1243dSDimitry Andric 
395bdd1243dSDimitry Andric   for (const Module *M : DirectModularDeps)
396480093f4SDimitry Andric     handleTopLevelModule(M);
397480093f4SDimitry Andric 
398fe6060f1SDimitry Andric   MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts);
399fe6060f1SDimitry Andric 
400*1ac55f4cSDimitry Andric   if (MDC.IsStdModuleP1689Format)
401*1ac55f4cSDimitry Andric     MDC.Consumer.handleProvidedAndRequiredStdCXXModules(
402*1ac55f4cSDimitry Andric         MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules);
403*1ac55f4cSDimitry Andric 
404fe6060f1SDimitry Andric   for (auto &&I : MDC.ModularDeps)
40581ad6265SDimitry Andric     MDC.Consumer.handleModuleDependency(*I.second);
406480093f4SDimitry Andric 
407fe6060f1SDimitry Andric   for (auto &&I : MDC.FileDeps)
408fe6060f1SDimitry Andric     MDC.Consumer.handleFileDependency(I);
409fe6060f1SDimitry Andric 
410bdd1243dSDimitry Andric   for (auto &&I : MDC.DirectPrebuiltModularDeps)
411bdd1243dSDimitry Andric     MDC.Consumer.handlePrebuiltModuleDependency(I.second);
412480093f4SDimitry Andric }
413480093f4SDimitry Andric 
414bdd1243dSDimitry Andric std::optional<ModuleID>
415bdd1243dSDimitry Andric ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
416480093f4SDimitry Andric   assert(M == M->getTopLevelModule() && "Expected top level module!");
417480093f4SDimitry Andric 
418bdd1243dSDimitry Andric   // A top-level module might not be actually imported as a module when
419bdd1243dSDimitry Andric   // -fmodule-name is used to compile a translation unit that imports this
420bdd1243dSDimitry Andric   // module. In that case it can be skipped. The appropriate header
421bdd1243dSDimitry Andric   // dependencies will still be reported as expected.
422bdd1243dSDimitry Andric   if (!M->getASTFile())
423bdd1243dSDimitry Andric     return {};
424bdd1243dSDimitry Andric 
425fe6060f1SDimitry Andric   // If this module has been handled already, just return its ID.
42681ad6265SDimitry Andric   auto ModI = MDC.ModularDeps.insert({M, nullptr});
427fe6060f1SDimitry Andric   if (!ModI.second)
42881ad6265SDimitry Andric     return ModI.first->second->ID;
429480093f4SDimitry Andric 
43081ad6265SDimitry Andric   ModI.first->second = std::make_unique<ModuleDeps>();
43181ad6265SDimitry Andric   ModuleDeps &MD = *ModI.first->second;
432480093f4SDimitry Andric 
433fe6060f1SDimitry Andric   MD.ID.ModuleName = M->getFullModuleName();
434fe6060f1SDimitry Andric   MD.ImportedByMainFile = DirectModularDeps.contains(M);
435fe6060f1SDimitry Andric   MD.IsSystem = M->IsSystem;
436fe6060f1SDimitry Andric 
437bdd1243dSDimitry Andric   ModuleMap &ModMapInfo =
438bdd1243dSDimitry Andric       MDC.ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
439bdd1243dSDimitry Andric 
440bdd1243dSDimitry Andric   OptionalFileEntryRef ModuleMap = ModMapInfo.getModuleMapFileForUniquing(M);
4410eae32dcSDimitry Andric 
4420eae32dcSDimitry Andric   if (ModuleMap) {
443bdd1243dSDimitry Andric     SmallString<128> Path = ModuleMap->getNameAsRequested();
444bdd1243dSDimitry Andric     ModMapInfo.canonicalizeModuleMapPath(Path);
4450eae32dcSDimitry Andric     MD.ClangModuleMapFile = std::string(Path);
4460eae32dcSDimitry Andric   }
447fe6060f1SDimitry Andric 
448480093f4SDimitry Andric   serialization::ModuleFile *MF =
449349cc55cSDimitry Andric       MDC.ScanInstance.getASTReader()->getModuleManager().lookup(
450349cc55cSDimitry Andric           M->getASTFile());
451349cc55cSDimitry Andric   MDC.ScanInstance.getASTReader()->visitInputFiles(
452480093f4SDimitry Andric       *MF, true, true, [&](const serialization::InputFile &IF, bool isSystem) {
453fe6060f1SDimitry Andric         // __inferred_module.map is the result of the way in which an implicit
454fe6060f1SDimitry Andric         // module build handles inferred modules. It adds an overlay VFS with
455fe6060f1SDimitry Andric         // this file in the proper directory and relies on the rest of Clang to
456fe6060f1SDimitry Andric         // handle it like normal. With explicitly built modules we don't need
457fe6060f1SDimitry Andric         // to play VFS tricks, so replace it with the correct module map.
458fe6060f1SDimitry Andric         if (IF.getFile()->getName().endswith("__inferred_module.map")) {
459bdd1243dSDimitry Andric           MDC.addFileDep(MD, ModuleMap->getName());
460fe6060f1SDimitry Andric           return;
461fe6060f1SDimitry Andric         }
462bdd1243dSDimitry Andric         MDC.addFileDep(MD, IF.getFile()->getName());
463480093f4SDimitry Andric       });
464480093f4SDimitry Andric 
465bdd1243dSDimitry Andric   llvm::DenseSet<const Module *> SeenDeps;
466bdd1243dSDimitry Andric   addAllSubmodulePrebuiltDeps(M, MD, SeenDeps);
467bdd1243dSDimitry Andric   addAllSubmoduleDeps(M, MD, SeenDeps);
468bdd1243dSDimitry Andric   addAllAffectingClangModules(M, MD, SeenDeps);
469bdd1243dSDimitry Andric 
47081ad6265SDimitry Andric   MDC.ScanInstance.getASTReader()->visitTopLevelModuleMaps(
471bdd1243dSDimitry Andric       *MF, [&](FileEntryRef FE) {
472bdd1243dSDimitry Andric         if (FE.getNameAsRequested().endswith("__inferred_module.map"))
47381ad6265SDimitry Andric           return;
474bdd1243dSDimitry Andric         MD.ModuleMapFileDeps.emplace_back(FE.getNameAsRequested());
47581ad6265SDimitry Andric       });
47681ad6265SDimitry Andric 
477bdd1243dSDimitry Andric   CompilerInvocation CI = MDC.makeInvocationForModuleBuildWithoutOutputs(
478349cc55cSDimitry Andric       MD, [&](CompilerInvocation &BuildInvocation) {
479349cc55cSDimitry Andric         if (MDC.OptimizeArgs)
480349cc55cSDimitry Andric           optimizeHeaderSearchOpts(BuildInvocation.getHeaderSearchOpts(),
481349cc55cSDimitry Andric                                    *MDC.ScanInstance.getASTReader(), *MF);
482349cc55cSDimitry Andric       });
483fe6060f1SDimitry Andric 
484bdd1243dSDimitry Andric   MDC.associateWithContextHash(CI, MD);
485bdd1243dSDimitry Andric 
486bdd1243dSDimitry Andric   // Finish the compiler invocation. Requires dependencies and the context hash.
487bdd1243dSDimitry Andric   MDC.addOutputPaths(CI, MD);
488bdd1243dSDimitry Andric 
489bdd1243dSDimitry Andric   MD.BuildArguments = CI.getCC1CommandLine();
490fe6060f1SDimitry Andric 
491fe6060f1SDimitry Andric   return MD.ID;
492fe6060f1SDimitry Andric }
493fe6060f1SDimitry Andric 
49481ad6265SDimitry Andric static void forEachSubmoduleSorted(const Module *M,
49581ad6265SDimitry Andric                                    llvm::function_ref<void(const Module *)> F) {
49681ad6265SDimitry Andric   // Submodule order depends on order of header includes for inferred submodules
49781ad6265SDimitry Andric   // we don't care about the exact order, so sort so that it's consistent across
49881ad6265SDimitry Andric   // TUs to improve sharing.
49981ad6265SDimitry Andric   SmallVector<const Module *> Submodules(M->submodule_begin(),
50081ad6265SDimitry Andric                                          M->submodule_end());
50181ad6265SDimitry Andric   llvm::stable_sort(Submodules, [](const Module *A, const Module *B) {
50281ad6265SDimitry Andric     return A->Name < B->Name;
50381ad6265SDimitry Andric   });
50481ad6265SDimitry Andric   for (const Module *SubM : Submodules)
50581ad6265SDimitry Andric     F(SubM);
50681ad6265SDimitry Andric }
50781ad6265SDimitry Andric 
508349cc55cSDimitry Andric void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps(
509349cc55cSDimitry Andric     const Module *M, ModuleDeps &MD,
510349cc55cSDimitry Andric     llvm::DenseSet<const Module *> &SeenSubmodules) {
511349cc55cSDimitry Andric   addModulePrebuiltDeps(M, MD, SeenSubmodules);
512349cc55cSDimitry Andric 
51381ad6265SDimitry Andric   forEachSubmoduleSorted(M, [&](const Module *SubM) {
514349cc55cSDimitry Andric     addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules);
51581ad6265SDimitry Andric   });
516349cc55cSDimitry Andric }
517349cc55cSDimitry Andric 
518349cc55cSDimitry Andric void ModuleDepCollectorPP::addModulePrebuiltDeps(
519349cc55cSDimitry Andric     const Module *M, ModuleDeps &MD,
520349cc55cSDimitry Andric     llvm::DenseSet<const Module *> &SeenSubmodules) {
521fe6060f1SDimitry Andric   for (const Module *Import : M->Imports)
522fe6060f1SDimitry Andric     if (Import->getTopLevelModule() != M->getTopLevelModule())
523349cc55cSDimitry Andric       if (MDC.isPrebuiltModule(Import->getTopLevelModule()))
524349cc55cSDimitry Andric         if (SeenSubmodules.insert(Import->getTopLevelModule()).second)
525349cc55cSDimitry Andric           MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule());
526480093f4SDimitry Andric }
527480093f4SDimitry Andric 
5285ffd83dbSDimitry Andric void ModuleDepCollectorPP::addAllSubmoduleDeps(
5295ffd83dbSDimitry Andric     const Module *M, ModuleDeps &MD,
5305ffd83dbSDimitry Andric     llvm::DenseSet<const Module *> &AddedModules) {
5315ffd83dbSDimitry Andric   addModuleDep(M, MD, AddedModules);
532480093f4SDimitry Andric 
53381ad6265SDimitry Andric   forEachSubmoduleSorted(M, [&](const Module *SubM) {
5345ffd83dbSDimitry Andric     addAllSubmoduleDeps(SubM, MD, AddedModules);
53581ad6265SDimitry Andric   });
536480093f4SDimitry Andric }
537480093f4SDimitry Andric 
5385ffd83dbSDimitry Andric void ModuleDepCollectorPP::addModuleDep(
5395ffd83dbSDimitry Andric     const Module *M, ModuleDeps &MD,
5405ffd83dbSDimitry Andric     llvm::DenseSet<const Module *> &AddedModules) {
541480093f4SDimitry Andric   for (const Module *Import : M->Imports) {
542fe6060f1SDimitry Andric     if (Import->getTopLevelModule() != M->getTopLevelModule() &&
543fe6060f1SDimitry Andric         !MDC.isPrebuiltModule(Import)) {
544bdd1243dSDimitry Andric       if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule()))
5455ffd83dbSDimitry Andric         if (AddedModules.insert(Import->getTopLevelModule()).second)
546bdd1243dSDimitry Andric           MD.ClangModuleDeps.push_back(*ImportID);
547bdd1243dSDimitry Andric     }
548bdd1243dSDimitry Andric   }
549bdd1243dSDimitry Andric }
550bdd1243dSDimitry Andric 
551bdd1243dSDimitry Andric void ModuleDepCollectorPP::addAllAffectingClangModules(
552bdd1243dSDimitry Andric     const Module *M, ModuleDeps &MD,
553bdd1243dSDimitry Andric     llvm::DenseSet<const Module *> &AddedModules) {
554bdd1243dSDimitry Andric   addAffectingClangModule(M, MD, AddedModules);
555bdd1243dSDimitry Andric 
556bdd1243dSDimitry Andric   for (const Module *SubM : M->submodules())
557bdd1243dSDimitry Andric     addAllAffectingClangModules(SubM, MD, AddedModules);
558bdd1243dSDimitry Andric }
559bdd1243dSDimitry Andric 
560bdd1243dSDimitry Andric void ModuleDepCollectorPP::addAffectingClangModule(
561bdd1243dSDimitry Andric     const Module *M, ModuleDeps &MD,
562bdd1243dSDimitry Andric     llvm::DenseSet<const Module *> &AddedModules) {
563bdd1243dSDimitry Andric   for (const Module *Affecting : M->AffectingClangModules) {
564bdd1243dSDimitry Andric     assert(Affecting == Affecting->getTopLevelModule() &&
565bdd1243dSDimitry Andric            "Not quite import not top-level module");
566bdd1243dSDimitry Andric     if (Affecting != M->getTopLevelModule() &&
567bdd1243dSDimitry Andric         !MDC.isPrebuiltModule(Affecting)) {
568bdd1243dSDimitry Andric       if (auto ImportID = handleTopLevelModule(Affecting))
569bdd1243dSDimitry Andric         if (AddedModules.insert(Affecting).second)
570bdd1243dSDimitry Andric           MD.ClangModuleDeps.push_back(*ImportID);
571480093f4SDimitry Andric     }
572480093f4SDimitry Andric   }
573480093f4SDimitry Andric }
574480093f4SDimitry Andric 
5755ffd83dbSDimitry Andric ModuleDepCollector::ModuleDepCollector(
576349cc55cSDimitry Andric     std::unique_ptr<DependencyOutputOptions> Opts,
577349cc55cSDimitry Andric     CompilerInstance &ScanInstance, DependencyConsumer &C,
578*1ac55f4cSDimitry Andric     CompilerInvocation OriginalCI, bool OptimizeArgs, bool EagerLoadModules,
579*1ac55f4cSDimitry Andric     bool IsStdModuleP1689Format)
580349cc55cSDimitry Andric     : ScanInstance(ScanInstance), Consumer(C), Opts(std::move(Opts)),
581bdd1243dSDimitry Andric       OriginalInvocation(std::move(OriginalCI)), OptimizeArgs(OptimizeArgs),
582*1ac55f4cSDimitry Andric       EagerLoadModules(EagerLoadModules),
583*1ac55f4cSDimitry Andric       IsStdModuleP1689Format(IsStdModuleP1689Format) {}
584480093f4SDimitry Andric 
585480093f4SDimitry Andric void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) {
586349cc55cSDimitry Andric   PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this));
587480093f4SDimitry Andric }
588480093f4SDimitry Andric 
589480093f4SDimitry Andric void ModuleDepCollector::attachToASTReader(ASTReader &R) {}
590fe6060f1SDimitry Andric 
591fe6060f1SDimitry Andric bool ModuleDepCollector::isPrebuiltModule(const Module *M) {
592fe6060f1SDimitry Andric   std::string Name(M->getTopLevelModuleName());
593fe6060f1SDimitry Andric   const auto &PrebuiltModuleFiles =
594349cc55cSDimitry Andric       ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles;
595fe6060f1SDimitry Andric   auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name);
596fe6060f1SDimitry Andric   if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end())
597fe6060f1SDimitry Andric     return false;
598fe6060f1SDimitry Andric   assert("Prebuilt module came from the expected AST file" &&
599fe6060f1SDimitry Andric          PrebuiltModuleFileIt->second == M->getASTFile()->getName());
600fe6060f1SDimitry Andric   return true;
601fe6060f1SDimitry Andric }
602bdd1243dSDimitry Andric 
603bdd1243dSDimitry Andric static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path,
604bdd1243dSDimitry Andric                                           SmallVectorImpl<char> &Storage) {
605bdd1243dSDimitry Andric   if (llvm::sys::path::is_absolute(Path) &&
606bdd1243dSDimitry Andric       !llvm::sys::path::is_style_windows(llvm::sys::path::Style::native))
607bdd1243dSDimitry Andric     return Path;
608bdd1243dSDimitry Andric   Storage.assign(Path.begin(), Path.end());
609bdd1243dSDimitry Andric   CI.getFileManager().makeAbsolutePath(Storage);
610bdd1243dSDimitry Andric   llvm::sys::path::make_preferred(Storage);
611bdd1243dSDimitry Andric   return StringRef(Storage.data(), Storage.size());
612bdd1243dSDimitry Andric }
613bdd1243dSDimitry Andric 
614bdd1243dSDimitry Andric void ModuleDepCollector::addFileDep(StringRef Path) {
615bdd1243dSDimitry Andric   llvm::SmallString<256> Storage;
616bdd1243dSDimitry Andric   Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
617bdd1243dSDimitry Andric   FileDeps.push_back(std::string(Path));
618bdd1243dSDimitry Andric }
619bdd1243dSDimitry Andric 
620bdd1243dSDimitry Andric void ModuleDepCollector::addFileDep(ModuleDeps &MD, StringRef Path) {
621bdd1243dSDimitry Andric   llvm::SmallString<256> Storage;
622bdd1243dSDimitry Andric   Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
623bdd1243dSDimitry Andric   MD.FileDeps.insert(Path);
624bdd1243dSDimitry Andric }
625