10b57cec5SDimitry Andric //===- DependencyScanningWorker.cpp - clang-scan-deps worker --------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
1006c3fb27SDimitry Andric #include "clang/Basic/DiagnosticDriver.h"
11bdd1243dSDimitry Andric #include "clang/Basic/DiagnosticFrontend.h"
12*0fca6ea1SDimitry Andric #include "clang/Basic/DiagnosticSerialization.h"
13fe6060f1SDimitry Andric #include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
14bdd1243dSDimitry Andric #include "clang/Driver/Compilation.h"
15bdd1243dSDimitry Andric #include "clang/Driver/Driver.h"
16bdd1243dSDimitry Andric #include "clang/Driver/Job.h"
17bdd1243dSDimitry Andric #include "clang/Driver/Tool.h"
180b57cec5SDimitry Andric #include "clang/Frontend/CompilerInstance.h"
19a7dea167SDimitry Andric #include "clang/Frontend/CompilerInvocation.h"
200b57cec5SDimitry Andric #include "clang/Frontend/FrontendActions.h"
210b57cec5SDimitry Andric #include "clang/Frontend/TextDiagnosticPrinter.h"
220b57cec5SDimitry Andric #include "clang/Frontend/Utils.h"
23a7dea167SDimitry Andric #include "clang/Lex/PreprocessorOptions.h"
24a7dea167SDimitry Andric #include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
25480093f4SDimitry Andric #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
260b57cec5SDimitry Andric #include "clang/Tooling/Tooling.h"
27*0fca6ea1SDimitry Andric #include "llvm/ADT/ScopeExit.h"
2806c3fb27SDimitry Andric #include "llvm/Support/Allocator.h"
2906c3fb27SDimitry Andric #include "llvm/Support/Error.h"
3006c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h"
31bdd1243dSDimitry Andric #include <optional>
320b57cec5SDimitry Andric
330b57cec5SDimitry Andric using namespace clang;
340b57cec5SDimitry Andric using namespace tooling;
350b57cec5SDimitry Andric using namespace dependencies;
360b57cec5SDimitry Andric
370b57cec5SDimitry Andric namespace {
380b57cec5SDimitry Andric
39a7dea167SDimitry Andric /// Forwards the gatherered dependencies to the consumer.
40a7dea167SDimitry Andric class DependencyConsumerForwarder : public DependencyFileGenerator {
410b57cec5SDimitry Andric public:
DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts,StringRef WorkingDirectory,DependencyConsumer & C)42a7dea167SDimitry Andric DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts,
43bdd1243dSDimitry Andric StringRef WorkingDirectory, DependencyConsumer &C)
44bdd1243dSDimitry Andric : DependencyFileGenerator(*Opts), WorkingDirectory(WorkingDirectory),
45bdd1243dSDimitry Andric Opts(std::move(Opts)), C(C) {}
460b57cec5SDimitry Andric
finishedMainFile(DiagnosticsEngine & Diags)470b57cec5SDimitry Andric void finishedMainFile(DiagnosticsEngine &Diags) override {
48fe6060f1SDimitry Andric C.handleDependencyOutputOpts(*Opts);
49a7dea167SDimitry Andric llvm::SmallString<256> CanonPath;
50a7dea167SDimitry Andric for (const auto &File : getDependencies()) {
51a7dea167SDimitry Andric CanonPath = File;
52a7dea167SDimitry Andric llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true);
53bdd1243dSDimitry Andric llvm::sys::fs::make_absolute(WorkingDirectory, CanonPath);
54fe6060f1SDimitry Andric C.handleFileDependency(CanonPath);
55a7dea167SDimitry Andric }
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric
580b57cec5SDimitry Andric private:
59bdd1243dSDimitry Andric StringRef WorkingDirectory;
600b57cec5SDimitry Andric std::unique_ptr<DependencyOutputOptions> Opts;
61a7dea167SDimitry Andric DependencyConsumer &C;
620b57cec5SDimitry Andric };
630b57cec5SDimitry Andric
checkHeaderSearchPaths(const HeaderSearchOptions & HSOpts,const HeaderSearchOptions & ExistingHSOpts,DiagnosticsEngine * Diags,const LangOptions & LangOpts)64*0fca6ea1SDimitry Andric static bool checkHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
65*0fca6ea1SDimitry Andric const HeaderSearchOptions &ExistingHSOpts,
66*0fca6ea1SDimitry Andric DiagnosticsEngine *Diags,
67*0fca6ea1SDimitry Andric const LangOptions &LangOpts) {
68*0fca6ea1SDimitry Andric if (LangOpts.Modules) {
69*0fca6ea1SDimitry Andric if (HSOpts.VFSOverlayFiles != ExistingHSOpts.VFSOverlayFiles) {
70*0fca6ea1SDimitry Andric if (Diags) {
71*0fca6ea1SDimitry Andric Diags->Report(diag::warn_pch_vfsoverlay_mismatch);
72*0fca6ea1SDimitry Andric auto VFSNote = [&](int Type, ArrayRef<std::string> VFSOverlays) {
73*0fca6ea1SDimitry Andric if (VFSOverlays.empty()) {
74*0fca6ea1SDimitry Andric Diags->Report(diag::note_pch_vfsoverlay_empty) << Type;
75*0fca6ea1SDimitry Andric } else {
76*0fca6ea1SDimitry Andric std::string Files = llvm::join(VFSOverlays, "\n");
77*0fca6ea1SDimitry Andric Diags->Report(diag::note_pch_vfsoverlay_files) << Type << Files;
78*0fca6ea1SDimitry Andric }
79*0fca6ea1SDimitry Andric };
80*0fca6ea1SDimitry Andric VFSNote(0, HSOpts.VFSOverlayFiles);
81*0fca6ea1SDimitry Andric VFSNote(1, ExistingHSOpts.VFSOverlayFiles);
82*0fca6ea1SDimitry Andric }
83*0fca6ea1SDimitry Andric }
84*0fca6ea1SDimitry Andric }
85*0fca6ea1SDimitry Andric return false;
86*0fca6ea1SDimitry Andric }
87*0fca6ea1SDimitry Andric
8881ad6265SDimitry Andric using PrebuiltModuleFilesT = decltype(HeaderSearchOptions::PrebuiltModuleFiles);
8981ad6265SDimitry Andric
90fe6060f1SDimitry Andric /// A listener that collects the imported modules and optionally the input
91fe6060f1SDimitry Andric /// files.
92fe6060f1SDimitry Andric class PrebuiltModuleListener : public ASTReaderListener {
93fe6060f1SDimitry Andric public:
PrebuiltModuleListener(PrebuiltModuleFilesT & PrebuiltModuleFiles,llvm::SmallVector<std::string> & NewModuleFiles,PrebuiltModuleVFSMapT & PrebuiltModuleVFSMap,const HeaderSearchOptions & HSOpts,const LangOptions & LangOpts,DiagnosticsEngine & Diags)9481ad6265SDimitry Andric PrebuiltModuleListener(PrebuiltModuleFilesT &PrebuiltModuleFiles,
95*0fca6ea1SDimitry Andric llvm::SmallVector<std::string> &NewModuleFiles,
96*0fca6ea1SDimitry Andric PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap,
97*0fca6ea1SDimitry Andric const HeaderSearchOptions &HSOpts,
98*0fca6ea1SDimitry Andric const LangOptions &LangOpts, DiagnosticsEngine &Diags)
9906c3fb27SDimitry Andric : PrebuiltModuleFiles(PrebuiltModuleFiles),
100*0fca6ea1SDimitry Andric NewModuleFiles(NewModuleFiles),
101*0fca6ea1SDimitry Andric PrebuiltModuleVFSMap(PrebuiltModuleVFSMap), ExistingHSOpts(HSOpts),
102*0fca6ea1SDimitry Andric ExistingLangOpts(LangOpts), Diags(Diags) {}
103fe6060f1SDimitry Andric
needsImportVisitation() const104fe6060f1SDimitry Andric bool needsImportVisitation() const override { return true; }
105fe6060f1SDimitry Andric
visitImport(StringRef ModuleName,StringRef Filename)106fe6060f1SDimitry Andric void visitImport(StringRef ModuleName, StringRef Filename) override {
10781ad6265SDimitry Andric if (PrebuiltModuleFiles.insert({ModuleName.str(), Filename.str()}).second)
10881ad6265SDimitry Andric NewModuleFiles.push_back(Filename.str());
109fe6060f1SDimitry Andric }
110fe6060f1SDimitry Andric
visitModuleFile(StringRef Filename,serialization::ModuleKind Kind)111*0fca6ea1SDimitry Andric void visitModuleFile(StringRef Filename,
112*0fca6ea1SDimitry Andric serialization::ModuleKind Kind) override {
113*0fca6ea1SDimitry Andric CurrentFile = Filename;
114*0fca6ea1SDimitry Andric }
115*0fca6ea1SDimitry Andric
ReadHeaderSearchPaths(const HeaderSearchOptions & HSOpts,bool Complain)116*0fca6ea1SDimitry Andric bool ReadHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
117*0fca6ea1SDimitry Andric bool Complain) override {
118*0fca6ea1SDimitry Andric std::vector<std::string> VFSOverlayFiles = HSOpts.VFSOverlayFiles;
119*0fca6ea1SDimitry Andric PrebuiltModuleVFSMap.insert(
120*0fca6ea1SDimitry Andric {CurrentFile, llvm::StringSet<>(VFSOverlayFiles)});
121*0fca6ea1SDimitry Andric return checkHeaderSearchPaths(
122*0fca6ea1SDimitry Andric HSOpts, ExistingHSOpts, Complain ? &Diags : nullptr, ExistingLangOpts);
123*0fca6ea1SDimitry Andric }
124*0fca6ea1SDimitry Andric
125fe6060f1SDimitry Andric private:
12681ad6265SDimitry Andric PrebuiltModuleFilesT &PrebuiltModuleFiles;
12781ad6265SDimitry Andric llvm::SmallVector<std::string> &NewModuleFiles;
128*0fca6ea1SDimitry Andric PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap;
129*0fca6ea1SDimitry Andric const HeaderSearchOptions &ExistingHSOpts;
130*0fca6ea1SDimitry Andric const LangOptions &ExistingLangOpts;
131*0fca6ea1SDimitry Andric DiagnosticsEngine &Diags;
132*0fca6ea1SDimitry Andric std::string CurrentFile;
133fe6060f1SDimitry Andric };
134fe6060f1SDimitry Andric
135fe6060f1SDimitry Andric /// Visit the given prebuilt module and collect all of the modules it
136fe6060f1SDimitry Andric /// transitively imports and contributing input files.
visitPrebuiltModule(StringRef PrebuiltModuleFilename,CompilerInstance & CI,PrebuiltModuleFilesT & ModuleFiles,PrebuiltModuleVFSMapT & PrebuiltModuleVFSMap,DiagnosticsEngine & Diags)137*0fca6ea1SDimitry Andric static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename,
138fe6060f1SDimitry Andric CompilerInstance &CI,
139*0fca6ea1SDimitry Andric PrebuiltModuleFilesT &ModuleFiles,
140*0fca6ea1SDimitry Andric PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap,
141*0fca6ea1SDimitry Andric DiagnosticsEngine &Diags) {
14281ad6265SDimitry Andric // List of module files to be processed.
143*0fca6ea1SDimitry Andric llvm::SmallVector<std::string> Worklist;
144*0fca6ea1SDimitry Andric PrebuiltModuleListener Listener(ModuleFiles, Worklist, PrebuiltModuleVFSMap,
145*0fca6ea1SDimitry Andric CI.getHeaderSearchOpts(), CI.getLangOpts(),
146*0fca6ea1SDimitry Andric Diags);
147fe6060f1SDimitry Andric
148*0fca6ea1SDimitry Andric Listener.visitModuleFile(PrebuiltModuleFilename,
149*0fca6ea1SDimitry Andric serialization::MK_ExplicitModule);
150*0fca6ea1SDimitry Andric if (ASTReader::readASTFileControlBlock(
151*0fca6ea1SDimitry Andric PrebuiltModuleFilename, CI.getFileManager(), CI.getModuleCache(),
152*0fca6ea1SDimitry Andric CI.getPCHContainerReader(),
153*0fca6ea1SDimitry Andric /*FindModuleFileExtensions=*/false, Listener,
154*0fca6ea1SDimitry Andric /*ValidateDiagnosticOptions=*/false, ASTReader::ARR_OutOfDate))
155*0fca6ea1SDimitry Andric return true;
156*0fca6ea1SDimitry Andric
157*0fca6ea1SDimitry Andric while (!Worklist.empty()) {
158*0fca6ea1SDimitry Andric Listener.visitModuleFile(Worklist.back(), serialization::MK_ExplicitModule);
159*0fca6ea1SDimitry Andric if (ASTReader::readASTFileControlBlock(
160bdd1243dSDimitry Andric Worklist.pop_back_val(), CI.getFileManager(), CI.getModuleCache(),
16181ad6265SDimitry Andric CI.getPCHContainerReader(),
162fe6060f1SDimitry Andric /*FindModuleFileExtensions=*/false, Listener,
163*0fca6ea1SDimitry Andric /*ValidateDiagnosticOptions=*/false))
164*0fca6ea1SDimitry Andric return true;
165*0fca6ea1SDimitry Andric }
166*0fca6ea1SDimitry Andric return false;
167fe6060f1SDimitry Andric }
168fe6060f1SDimitry Andric
169fe6060f1SDimitry Andric /// Transform arbitrary file name into an object-like file name.
makeObjFileName(StringRef FileName)170fe6060f1SDimitry Andric static std::string makeObjFileName(StringRef FileName) {
171fe6060f1SDimitry Andric SmallString<128> ObjFileName(FileName);
172fe6060f1SDimitry Andric llvm::sys::path::replace_extension(ObjFileName, "o");
1737a6dacacSDimitry Andric return std::string(ObjFileName);
174fe6060f1SDimitry Andric }
175fe6060f1SDimitry Andric
176fe6060f1SDimitry Andric /// Deduce the dependency target based on the output file and input files.
177fe6060f1SDimitry Andric static std::string
deduceDepTarget(const std::string & OutputFile,const SmallVectorImpl<FrontendInputFile> & InputFiles)178fe6060f1SDimitry Andric deduceDepTarget(const std::string &OutputFile,
179fe6060f1SDimitry Andric const SmallVectorImpl<FrontendInputFile> &InputFiles) {
180fe6060f1SDimitry Andric if (OutputFile != "-")
181fe6060f1SDimitry Andric return OutputFile;
182fe6060f1SDimitry Andric
183fe6060f1SDimitry Andric if (InputFiles.empty() || !InputFiles.front().isFile())
184fe6060f1SDimitry Andric return "clang-scan-deps\\ dependency";
185fe6060f1SDimitry Andric
186fe6060f1SDimitry Andric return makeObjFileName(InputFiles.front().getFile());
187fe6060f1SDimitry Andric }
188fe6060f1SDimitry Andric
189349cc55cSDimitry Andric /// Sanitize diagnostic options for dependency scan.
sanitizeDiagOpts(DiagnosticOptions & DiagOpts)190349cc55cSDimitry Andric static void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) {
191349cc55cSDimitry Andric // Don't print 'X warnings and Y errors generated'.
192349cc55cSDimitry Andric DiagOpts.ShowCarets = false;
193349cc55cSDimitry Andric // Don't write out diagnostic file.
194349cc55cSDimitry Andric DiagOpts.DiagnosticSerializationFile.clear();
195*0fca6ea1SDimitry Andric // Don't emit warnings except for scanning specific warnings.
196*0fca6ea1SDimitry Andric // TODO: It would be useful to add a more principled way to ignore all
197*0fca6ea1SDimitry Andric // warnings that come from source code. The issue is that we need to
198*0fca6ea1SDimitry Andric // ignore warnings that could be surpressed by
199*0fca6ea1SDimitry Andric // `#pragma clang diagnostic`, while still allowing some scanning
200*0fca6ea1SDimitry Andric // warnings for things we're not ready to turn into errors yet.
201*0fca6ea1SDimitry Andric // See `test/ClangScanDeps/diagnostic-pragmas.c` for an example.
202*0fca6ea1SDimitry Andric llvm::erase_if(DiagOpts.Warnings, [](StringRef Warning) {
203*0fca6ea1SDimitry Andric return llvm::StringSwitch<bool>(Warning)
204*0fca6ea1SDimitry Andric .Cases("pch-vfs-diff", "error=pch-vfs-diff", false)
205*0fca6ea1SDimitry Andric .StartsWith("no-error=", false)
206*0fca6ea1SDimitry Andric .Default(true);
207*0fca6ea1SDimitry Andric });
208*0fca6ea1SDimitry Andric }
209*0fca6ea1SDimitry Andric
210*0fca6ea1SDimitry Andric // Clang implements -D and -U by splatting text into a predefines buffer. This
211*0fca6ea1SDimitry Andric // allows constructs such as `-DFඞ=3 "-D F\u{0D9E} 4 3 2”` to be accepted and
212*0fca6ea1SDimitry Andric // define the same macro, or adding C++ style comments before the macro name.
213*0fca6ea1SDimitry Andric //
214*0fca6ea1SDimitry Andric // This function checks that the first non-space characters in the macro
215*0fca6ea1SDimitry Andric // obviously form an identifier that can be uniqued on without lexing. Failing
216*0fca6ea1SDimitry Andric // to do this could lead to changing the final definition of a macro.
217*0fca6ea1SDimitry Andric //
218*0fca6ea1SDimitry Andric // We could set up a preprocessor and actually lex the name, but that's very
219*0fca6ea1SDimitry Andric // heavyweight for a situation that will almost never happen in practice.
getSimpleMacroName(StringRef Macro)220*0fca6ea1SDimitry Andric static std::optional<StringRef> getSimpleMacroName(StringRef Macro) {
221*0fca6ea1SDimitry Andric StringRef Name = Macro.split("=").first.ltrim(" \t");
222*0fca6ea1SDimitry Andric std::size_t I = 0;
223*0fca6ea1SDimitry Andric
224*0fca6ea1SDimitry Andric auto FinishName = [&]() -> std::optional<StringRef> {
225*0fca6ea1SDimitry Andric StringRef SimpleName = Name.slice(0, I);
226*0fca6ea1SDimitry Andric if (SimpleName.empty())
227*0fca6ea1SDimitry Andric return std::nullopt;
228*0fca6ea1SDimitry Andric return SimpleName;
229*0fca6ea1SDimitry Andric };
230*0fca6ea1SDimitry Andric
231*0fca6ea1SDimitry Andric for (; I != Name.size(); ++I) {
232*0fca6ea1SDimitry Andric switch (Name[I]) {
233*0fca6ea1SDimitry Andric case '(': // Start of macro parameter list
234*0fca6ea1SDimitry Andric case ' ': // End of macro name
235*0fca6ea1SDimitry Andric case '\t':
236*0fca6ea1SDimitry Andric return FinishName();
237*0fca6ea1SDimitry Andric case '_':
238*0fca6ea1SDimitry Andric continue;
239*0fca6ea1SDimitry Andric default:
240*0fca6ea1SDimitry Andric if (llvm::isAlnum(Name[I]))
241*0fca6ea1SDimitry Andric continue;
242*0fca6ea1SDimitry Andric return std::nullopt;
243*0fca6ea1SDimitry Andric }
244*0fca6ea1SDimitry Andric }
245*0fca6ea1SDimitry Andric return FinishName();
246*0fca6ea1SDimitry Andric }
247*0fca6ea1SDimitry Andric
canonicalizeDefines(PreprocessorOptions & PPOpts)248*0fca6ea1SDimitry Andric static void canonicalizeDefines(PreprocessorOptions &PPOpts) {
249*0fca6ea1SDimitry Andric using MacroOpt = std::pair<StringRef, std::size_t>;
250*0fca6ea1SDimitry Andric std::vector<MacroOpt> SimpleNames;
251*0fca6ea1SDimitry Andric SimpleNames.reserve(PPOpts.Macros.size());
252*0fca6ea1SDimitry Andric std::size_t Index = 0;
253*0fca6ea1SDimitry Andric for (const auto &M : PPOpts.Macros) {
254*0fca6ea1SDimitry Andric auto SName = getSimpleMacroName(M.first);
255*0fca6ea1SDimitry Andric // Skip optimizing if we can't guarantee we can preserve relative order.
256*0fca6ea1SDimitry Andric if (!SName)
257*0fca6ea1SDimitry Andric return;
258*0fca6ea1SDimitry Andric SimpleNames.emplace_back(*SName, Index);
259*0fca6ea1SDimitry Andric ++Index;
260*0fca6ea1SDimitry Andric }
261*0fca6ea1SDimitry Andric
262*0fca6ea1SDimitry Andric llvm::stable_sort(SimpleNames, llvm::less_first());
263*0fca6ea1SDimitry Andric // Keep the last instance of each macro name by going in reverse
264*0fca6ea1SDimitry Andric auto NewEnd = std::unique(
265*0fca6ea1SDimitry Andric SimpleNames.rbegin(), SimpleNames.rend(),
266*0fca6ea1SDimitry Andric [](const MacroOpt &A, const MacroOpt &B) { return A.first == B.first; });
267*0fca6ea1SDimitry Andric SimpleNames.erase(SimpleNames.begin(), NewEnd.base());
268*0fca6ea1SDimitry Andric
269*0fca6ea1SDimitry Andric // Apply permutation.
270*0fca6ea1SDimitry Andric decltype(PPOpts.Macros) NewMacros;
271*0fca6ea1SDimitry Andric NewMacros.reserve(SimpleNames.size());
272*0fca6ea1SDimitry Andric for (std::size_t I = 0, E = SimpleNames.size(); I != E; ++I) {
273*0fca6ea1SDimitry Andric std::size_t OriginalIndex = SimpleNames[I].second;
274*0fca6ea1SDimitry Andric // We still emit undefines here as they may be undefining a predefined macro
275*0fca6ea1SDimitry Andric NewMacros.push_back(std::move(PPOpts.Macros[OriginalIndex]));
276*0fca6ea1SDimitry Andric }
277*0fca6ea1SDimitry Andric std::swap(PPOpts.Macros, NewMacros);
278349cc55cSDimitry Andric }
279349cc55cSDimitry Andric
2800b57cec5SDimitry Andric /// A clang tool that runs the preprocessor in a mode that's optimized for
2810b57cec5SDimitry Andric /// dependency scanning for the given compiler invocation.
2820b57cec5SDimitry Andric class DependencyScanningAction : public tooling::ToolAction {
2830b57cec5SDimitry Andric public:
DependencyScanningAction(StringRef WorkingDirectory,DependencyConsumer & Consumer,DependencyActionController & Controller,llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS,ScanningOutputFormat Format,ScanningOptimizations OptimizeArgs,bool EagerLoadModules,bool DisableFree,std::optional<StringRef> ModuleName=std::nullopt)284a7dea167SDimitry Andric DependencyScanningAction(
285a7dea167SDimitry Andric StringRef WorkingDirectory, DependencyConsumer &Consumer,
28606c3fb27SDimitry Andric DependencyActionController &Controller,
287a7dea167SDimitry Andric llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS,
2885f757f3fSDimitry Andric ScanningOutputFormat Format, ScanningOptimizations OptimizeArgs,
2895f757f3fSDimitry Andric bool EagerLoadModules, bool DisableFree,
2905f757f3fSDimitry Andric std::optional<StringRef> ModuleName = std::nullopt)
291a7dea167SDimitry Andric : WorkingDirectory(WorkingDirectory), Consumer(Consumer),
29206c3fb27SDimitry Andric Controller(Controller), DepFS(std::move(DepFS)), Format(Format),
29306c3fb27SDimitry Andric OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules),
29406c3fb27SDimitry Andric DisableFree(DisableFree), ModuleName(ModuleName) {}
2950b57cec5SDimitry Andric
runInvocation(std::shared_ptr<CompilerInvocation> Invocation,FileManager * DriverFileMgr,std::shared_ptr<PCHContainerOperations> PCHContainerOps,DiagnosticConsumer * DiagConsumer)2960b57cec5SDimitry Andric bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
297*0fca6ea1SDimitry Andric FileManager *DriverFileMgr,
2980b57cec5SDimitry Andric std::shared_ptr<PCHContainerOperations> PCHContainerOps,
2990b57cec5SDimitry Andric DiagnosticConsumer *DiagConsumer) override {
300fe6060f1SDimitry Andric // Make a deep copy of the original Clang invocation.
301fe6060f1SDimitry Andric CompilerInvocation OriginalInvocation(*Invocation);
30281ad6265SDimitry Andric // Restore the value of DisableFree, which may be modified by Tooling.
30381ad6265SDimitry Andric OriginalInvocation.getFrontendOpts().DisableFree = DisableFree;
304*0fca6ea1SDimitry Andric if (any(OptimizeArgs & ScanningOptimizations::Macros))
305*0fca6ea1SDimitry Andric canonicalizeDefines(OriginalInvocation.getPreprocessorOpts());
306fe6060f1SDimitry Andric
307bdd1243dSDimitry Andric if (Scanned) {
308bdd1243dSDimitry Andric // Scanning runs once for the first -cc1 invocation in a chain of driver
309bdd1243dSDimitry Andric // jobs. For any dependent jobs, reuse the scanning result and just
310bdd1243dSDimitry Andric // update the LastCC1Arguments to correspond to the new invocation.
311bdd1243dSDimitry Andric // FIXME: to support multi-arch builds, each arch requires a separate scan
312bdd1243dSDimitry Andric setLastCC1Arguments(std::move(OriginalInvocation));
313bdd1243dSDimitry Andric return true;
314bdd1243dSDimitry Andric }
315bdd1243dSDimitry Andric
316bdd1243dSDimitry Andric Scanned = true;
317bdd1243dSDimitry Andric
3180b57cec5SDimitry Andric // Create a compiler instance to handle the actual work.
319bdd1243dSDimitry Andric ScanInstanceStorage.emplace(std::move(PCHContainerOps));
320bdd1243dSDimitry Andric CompilerInstance &ScanInstance = *ScanInstanceStorage;
321349cc55cSDimitry Andric ScanInstance.setInvocation(std::move(Invocation));
3220b57cec5SDimitry Andric
3230b57cec5SDimitry Andric // Create the compiler's actual diagnostics engine.
324349cc55cSDimitry Andric sanitizeDiagOpts(ScanInstance.getDiagnosticOpts());
325349cc55cSDimitry Andric ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
326349cc55cSDimitry Andric if (!ScanInstance.hasDiagnostics())
3270b57cec5SDimitry Andric return false;
3280b57cec5SDimitry Andric
329*0fca6ea1SDimitry Andric // Some DiagnosticConsumers require that finish() is called.
330*0fca6ea1SDimitry Andric auto DiagConsumerFinisher =
331*0fca6ea1SDimitry Andric llvm::make_scope_exit([DiagConsumer]() { DiagConsumer->finish(); });
332*0fca6ea1SDimitry Andric
333349cc55cSDimitry Andric ScanInstance.getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath =
334349cc55cSDimitry Andric true;
335fe6060f1SDimitry Andric
33681ad6265SDimitry Andric ScanInstance.getFrontendOpts().GenerateGlobalModuleIndex = false;
33781ad6265SDimitry Andric ScanInstance.getFrontendOpts().UseGlobalModuleIndex = false;
338bdd1243dSDimitry Andric ScanInstance.getFrontendOpts().ModulesShareFileManager = false;
33906c3fb27SDimitry Andric ScanInstance.getHeaderSearchOpts().ModuleFormat = "raw";
340*0fca6ea1SDimitry Andric ScanInstance.getHeaderSearchOpts().ModulesIncludeVFSUsage =
341*0fca6ea1SDimitry Andric any(OptimizeArgs & ScanningOptimizations::VFS);
34281ad6265SDimitry Andric
343bdd1243dSDimitry Andric // Support for virtual file system overlays.
344*0fca6ea1SDimitry Andric auto FS = createVFSFromCompilerInvocation(
345bdd1243dSDimitry Andric ScanInstance.getInvocation(), ScanInstance.getDiagnostics(),
346*0fca6ea1SDimitry Andric DriverFileMgr->getVirtualFileSystemPtr());
347bdd1243dSDimitry Andric
348*0fca6ea1SDimitry Andric // Create a new FileManager to match the invocation's FileSystemOptions.
349*0fca6ea1SDimitry Andric auto *FileMgr = ScanInstance.createFileManager(FS);
350349cc55cSDimitry Andric ScanInstance.createSourceManager(*FileMgr);
351fe6060f1SDimitry Andric
352fe6060f1SDimitry Andric // Store the list of prebuilt module files into header search options. This
353fe6060f1SDimitry Andric // will prevent the implicit build to create duplicate modules and will
354fe6060f1SDimitry Andric // force reuse of the existing prebuilt module files instead.
355*0fca6ea1SDimitry Andric PrebuiltModuleVFSMapT PrebuiltModuleVFSMap;
356349cc55cSDimitry Andric if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
357*0fca6ea1SDimitry Andric if (visitPrebuiltModule(
358*0fca6ea1SDimitry Andric ScanInstance.getPreprocessorOpts().ImplicitPCHInclude,
359*0fca6ea1SDimitry Andric ScanInstance,
360*0fca6ea1SDimitry Andric ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles,
361*0fca6ea1SDimitry Andric PrebuiltModuleVFSMap, ScanInstance.getDiagnostics()))
362*0fca6ea1SDimitry Andric return false;
363fe6060f1SDimitry Andric
364fe6060f1SDimitry Andric // Use the dependency scanning optimized file system if requested to do so.
365*0fca6ea1SDimitry Andric if (DepFS)
36681ad6265SDimitry Andric ScanInstance.getPreprocessorOpts().DependencyDirectivesForFile =
367*0fca6ea1SDimitry Andric [LocalDepFS = DepFS](FileEntryRef File)
368bdd1243dSDimitry Andric -> std::optional<ArrayRef<dependency_directives_scan::Directive>> {
36981ad6265SDimitry Andric if (llvm::ErrorOr<EntryRef> Entry =
37081ad6265SDimitry Andric LocalDepFS->getOrCreateFileSystemEntry(File.getName()))
371*0fca6ea1SDimitry Andric if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry))
37281ad6265SDimitry Andric return Entry->getDirectiveTokens();
373bdd1243dSDimitry Andric return std::nullopt;
37481ad6265SDimitry Andric };
375a7dea167SDimitry Andric
3760b57cec5SDimitry Andric // Create the dependency collector that will collect the produced
3770b57cec5SDimitry Andric // dependencies.
3780b57cec5SDimitry Andric //
3790b57cec5SDimitry Andric // This also moves the existing dependency output options from the
3800b57cec5SDimitry Andric // invocation to the collector. The options in the invocation are reset,
3810b57cec5SDimitry Andric // which ensures that the compiler won't create new dependency collectors,
3820b57cec5SDimitry Andric // and thus won't write out the extra '.d' files to disk.
383fe6060f1SDimitry Andric auto Opts = std::make_unique<DependencyOutputOptions>();
384349cc55cSDimitry Andric std::swap(*Opts, ScanInstance.getInvocation().getDependencyOutputOpts());
385fe6060f1SDimitry Andric // We need at least one -MT equivalent for the generator of make dependency
386fe6060f1SDimitry Andric // files to work.
3870b57cec5SDimitry Andric if (Opts->Targets.empty())
388349cc55cSDimitry Andric Opts->Targets = {
389349cc55cSDimitry Andric deduceDepTarget(ScanInstance.getFrontendOpts().OutputFile,
390349cc55cSDimitry Andric ScanInstance.getFrontendOpts().Inputs)};
391fe6060f1SDimitry Andric Opts->IncludeSystemHeaders = true;
392480093f4SDimitry Andric
393480093f4SDimitry Andric switch (Format) {
394480093f4SDimitry Andric case ScanningOutputFormat::Make:
395349cc55cSDimitry Andric ScanInstance.addDependencyCollector(
396bdd1243dSDimitry Andric std::make_shared<DependencyConsumerForwarder>(
397bdd1243dSDimitry Andric std::move(Opts), WorkingDirectory, Consumer));
398480093f4SDimitry Andric break;
3991ac55f4cSDimitry Andric case ScanningOutputFormat::P1689:
400480093f4SDimitry Andric case ScanningOutputFormat::Full:
401bdd1243dSDimitry Andric MDC = std::make_shared<ModuleDepCollector>(
40206c3fb27SDimitry Andric std::move(Opts), ScanInstance, Consumer, Controller,
403*0fca6ea1SDimitry Andric OriginalInvocation, std::move(PrebuiltModuleVFSMap), OptimizeArgs,
404*0fca6ea1SDimitry Andric EagerLoadModules, Format == ScanningOutputFormat::P1689);
405bdd1243dSDimitry Andric ScanInstance.addDependencyCollector(MDC);
406480093f4SDimitry Andric break;
407480093f4SDimitry Andric }
408480093f4SDimitry Andric
4095ffd83dbSDimitry Andric // Consider different header search and diagnostic options to create
4105ffd83dbSDimitry Andric // different modules. This avoids the unsound aliasing of module PCMs.
4115ffd83dbSDimitry Andric //
412349cc55cSDimitry Andric // TODO: Implement diagnostic bucketing to reduce the impact of strict
413349cc55cSDimitry Andric // context hashing.
414349cc55cSDimitry Andric ScanInstance.getHeaderSearchOpts().ModulesStrictContextHash = true;
4155f757f3fSDimitry Andric ScanInstance.getHeaderSearchOpts().ModulesSkipDiagnosticOptions = true;
4165f757f3fSDimitry Andric ScanInstance.getHeaderSearchOpts().ModulesSkipHeaderSearchPaths = true;
4175f757f3fSDimitry Andric ScanInstance.getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings =
4185f757f3fSDimitry Andric true;
4190b57cec5SDimitry Andric
42006c3fb27SDimitry Andric // Avoid some checks and module map parsing when loading PCM files.
42106c3fb27SDimitry Andric ScanInstance.getPreprocessorOpts().ModulesCheckRelocated = false;
42206c3fb27SDimitry Andric
423349cc55cSDimitry Andric std::unique_ptr<FrontendAction> Action;
424349cc55cSDimitry Andric
42581ad6265SDimitry Andric if (ModuleName)
426349cc55cSDimitry Andric Action = std::make_unique<GetDependenciesByModuleNameAction>(*ModuleName);
427349cc55cSDimitry Andric else
428349cc55cSDimitry Andric Action = std::make_unique<ReadPCHAndPreprocessAction>();
429349cc55cSDimitry Andric
430*0fca6ea1SDimitry Andric if (ScanInstance.getDiagnostics().hasErrorOccurred())
431*0fca6ea1SDimitry Andric return false;
432*0fca6ea1SDimitry Andric
433*0fca6ea1SDimitry Andric // Each action is responsible for calling finish.
434*0fca6ea1SDimitry Andric DiagConsumerFinisher.release();
435349cc55cSDimitry Andric const bool Result = ScanInstance.ExecuteAction(*Action);
436bdd1243dSDimitry Andric
437bdd1243dSDimitry Andric if (Result)
438bdd1243dSDimitry Andric setLastCC1Arguments(std::move(OriginalInvocation));
439bdd1243dSDimitry Andric
440*0fca6ea1SDimitry Andric // Propagate the statistics to the parent FileManager.
441*0fca6ea1SDimitry Andric DriverFileMgr->AddStats(ScanInstance.getFileManager());
442*0fca6ea1SDimitry Andric
4430b57cec5SDimitry Andric return Result;
4440b57cec5SDimitry Andric }
4450b57cec5SDimitry Andric
hasScanned() const446bdd1243dSDimitry Andric bool hasScanned() const { return Scanned; }
447bdd1243dSDimitry Andric
448bdd1243dSDimitry Andric /// Take the cc1 arguments corresponding to the most recent invocation used
449bdd1243dSDimitry Andric /// with this action. Any modifications implied by the discovered dependencies
450bdd1243dSDimitry Andric /// will have already been applied.
takeLastCC1Arguments()451bdd1243dSDimitry Andric std::vector<std::string> takeLastCC1Arguments() {
452bdd1243dSDimitry Andric std::vector<std::string> Result;
453bdd1243dSDimitry Andric std::swap(Result, LastCC1Arguments); // Reset LastCC1Arguments to empty.
454bdd1243dSDimitry Andric return Result;
455bdd1243dSDimitry Andric }
456bdd1243dSDimitry Andric
457bdd1243dSDimitry Andric private:
setLastCC1Arguments(CompilerInvocation && CI)458bdd1243dSDimitry Andric void setLastCC1Arguments(CompilerInvocation &&CI) {
459bdd1243dSDimitry Andric if (MDC)
460bdd1243dSDimitry Andric MDC->applyDiscoveredDependencies(CI);
461bdd1243dSDimitry Andric LastCC1Arguments = CI.getCC1CommandLine();
462bdd1243dSDimitry Andric }
463bdd1243dSDimitry Andric
4640b57cec5SDimitry Andric private:
4650b57cec5SDimitry Andric StringRef WorkingDirectory;
466a7dea167SDimitry Andric DependencyConsumer &Consumer;
46706c3fb27SDimitry Andric DependencyActionController &Controller;
468a7dea167SDimitry Andric llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
469480093f4SDimitry Andric ScanningOutputFormat Format;
4705f757f3fSDimitry Andric ScanningOptimizations OptimizeArgs;
471bdd1243dSDimitry Andric bool EagerLoadModules;
47281ad6265SDimitry Andric bool DisableFree;
473bdd1243dSDimitry Andric std::optional<StringRef> ModuleName;
474bdd1243dSDimitry Andric std::optional<CompilerInstance> ScanInstanceStorage;
475bdd1243dSDimitry Andric std::shared_ptr<ModuleDepCollector> MDC;
476bdd1243dSDimitry Andric std::vector<std::string> LastCC1Arguments;
477bdd1243dSDimitry Andric bool Scanned = false;
4780b57cec5SDimitry Andric };
4790b57cec5SDimitry Andric
4800b57cec5SDimitry Andric } // end anonymous namespace
4810b57cec5SDimitry Andric
DependencyScanningWorker(DependencyScanningService & Service,llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)482a7dea167SDimitry Andric DependencyScanningWorker::DependencyScanningWorker(
483fcaf7f86SDimitry Andric DependencyScanningService &Service,
484fcaf7f86SDimitry Andric llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
4855f757f3fSDimitry Andric : Format(Service.getFormat()), OptimizeArgs(Service.getOptimizeArgs()),
486bdd1243dSDimitry Andric EagerLoadModules(Service.shouldEagerLoadModules()) {
4870b57cec5SDimitry Andric PCHContainerOps = std::make_shared<PCHContainerOperations>();
48806c3fb27SDimitry Andric // We need to read object files from PCH built outside the scanner.
489fe6060f1SDimitry Andric PCHContainerOps->registerReader(
490fe6060f1SDimitry Andric std::make_unique<ObjectFilePCHContainerReader>());
49106c3fb27SDimitry Andric // The scanner itself writes only raw ast files.
49206c3fb27SDimitry Andric PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());
493fe6060f1SDimitry Andric
494bdd1243dSDimitry Andric switch (Service.getMode()) {
495bdd1243dSDimitry Andric case ScanningMode::DependencyDirectivesScan:
496bdd1243dSDimitry Andric DepFS =
497bdd1243dSDimitry Andric new DependencyScanningWorkerFilesystem(Service.getSharedCache(), FS);
498bdd1243dSDimitry Andric BaseFS = DepFS;
499bdd1243dSDimitry Andric break;
500bdd1243dSDimitry Andric case ScanningMode::CanonicalPreprocessing:
501bdd1243dSDimitry Andric DepFS = nullptr;
502bdd1243dSDimitry Andric BaseFS = FS;
503bdd1243dSDimitry Andric break;
504bdd1243dSDimitry Andric }
5050b57cec5SDimitry Andric }
5060b57cec5SDimitry Andric
computeDependencies(StringRef WorkingDirectory,const std::vector<std::string> & CommandLine,DependencyConsumer & Consumer,DependencyActionController & Controller,std::optional<StringRef> ModuleName)507bdd1243dSDimitry Andric llvm::Error DependencyScanningWorker::computeDependencies(
508bdd1243dSDimitry Andric StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
50906c3fb27SDimitry Andric DependencyConsumer &Consumer, DependencyActionController &Controller,
51006c3fb27SDimitry Andric std::optional<StringRef> ModuleName) {
511bdd1243dSDimitry Andric std::vector<const char *> CLI;
512bdd1243dSDimitry Andric for (const std::string &Arg : CommandLine)
513bdd1243dSDimitry Andric CLI.push_back(Arg.c_str());
514bdd1243dSDimitry Andric auto DiagOpts = CreateAndPopulateDiagOpts(CLI);
515349cc55cSDimitry Andric sanitizeDiagOpts(*DiagOpts);
516349cc55cSDimitry Andric
5170b57cec5SDimitry Andric // Capture the emitted diagnostics and report them to the client
5180b57cec5SDimitry Andric // in the case of a failure.
5190b57cec5SDimitry Andric std::string DiagnosticOutput;
5200b57cec5SDimitry Andric llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
521bdd1243dSDimitry Andric TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release());
5220b57cec5SDimitry Andric
52306c3fb27SDimitry Andric if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
52406c3fb27SDimitry Andric DiagPrinter, ModuleName))
525a7dea167SDimitry Andric return llvm::Error::success();
5260b57cec5SDimitry Andric return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
5270b57cec5SDimitry Andric llvm::inconvertibleErrorCode());
5280b57cec5SDimitry Andric }
529a7dea167SDimitry Andric
forEachDriverJob(ArrayRef<std::string> ArgStrs,DiagnosticsEngine & Diags,FileManager & FM,llvm::function_ref<bool (const driver::Command & Cmd)> Callback)530bdd1243dSDimitry Andric static bool forEachDriverJob(
53106c3fb27SDimitry Andric ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags, FileManager &FM,
532bdd1243dSDimitry Andric llvm::function_ref<bool(const driver::Command &Cmd)> Callback) {
53306c3fb27SDimitry Andric SmallVector<const char *, 256> Argv;
53406c3fb27SDimitry Andric Argv.reserve(ArgStrs.size());
53506c3fb27SDimitry Andric for (const std::string &Arg : ArgStrs)
53606c3fb27SDimitry Andric Argv.push_back(Arg.c_str());
53706c3fb27SDimitry Andric
53806c3fb27SDimitry Andric llvm::vfs::FileSystem *FS = &FM.getVirtualFileSystem();
53906c3fb27SDimitry Andric
540bdd1243dSDimitry Andric std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
54106c3fb27SDimitry Andric Argv[0], llvm::sys::getDefaultTargetTriple(), Diags,
54206c3fb27SDimitry Andric "clang LLVM compiler", FS);
543bdd1243dSDimitry Andric Driver->setTitle("clang_based_tool");
544bdd1243dSDimitry Andric
54506c3fb27SDimitry Andric llvm::BumpPtrAllocator Alloc;
54606c3fb27SDimitry Andric bool CLMode = driver::IsClangCL(
54706c3fb27SDimitry Andric driver::getDriverMode(Argv[0], ArrayRef(Argv).slice(1)));
54806c3fb27SDimitry Andric
54906c3fb27SDimitry Andric if (llvm::Error E = driver::expandResponseFiles(Argv, CLMode, Alloc, FS)) {
55006c3fb27SDimitry Andric Diags.Report(diag::err_drv_expand_response_file)
55106c3fb27SDimitry Andric << llvm::toString(std::move(E));
55206c3fb27SDimitry Andric return false;
55306c3fb27SDimitry Andric }
554bdd1243dSDimitry Andric
555bdd1243dSDimitry Andric const std::unique_ptr<driver::Compilation> Compilation(
556bdd1243dSDimitry Andric Driver->BuildCompilation(llvm::ArrayRef(Argv)));
557bdd1243dSDimitry Andric if (!Compilation)
558bdd1243dSDimitry Andric return false;
559bdd1243dSDimitry Andric
5605f757f3fSDimitry Andric if (Compilation->containsError())
5615f757f3fSDimitry Andric return false;
5625f757f3fSDimitry Andric
563bdd1243dSDimitry Andric for (const driver::Command &Job : Compilation->getJobs()) {
564bdd1243dSDimitry Andric if (!Callback(Job))
565bdd1243dSDimitry Andric return false;
566bdd1243dSDimitry Andric }
567bdd1243dSDimitry Andric return true;
568bdd1243dSDimitry Andric }
569bdd1243dSDimitry Andric
createAndRunToolInvocation(std::vector<std::string> CommandLine,DependencyScanningAction & Action,FileManager & FM,std::shared_ptr<clang::PCHContainerOperations> & PCHContainerOps,DiagnosticsEngine & Diags,DependencyConsumer & Consumer)5705f757f3fSDimitry Andric static bool createAndRunToolInvocation(
5715f757f3fSDimitry Andric std::vector<std::string> CommandLine, DependencyScanningAction &Action,
5725f757f3fSDimitry Andric FileManager &FM,
5735f757f3fSDimitry Andric std::shared_ptr<clang::PCHContainerOperations> &PCHContainerOps,
5745f757f3fSDimitry Andric DiagnosticsEngine &Diags, DependencyConsumer &Consumer) {
5755f757f3fSDimitry Andric
5765f757f3fSDimitry Andric // Save executable path before providing CommandLine to ToolInvocation
5775f757f3fSDimitry Andric std::string Executable = CommandLine[0];
5785f757f3fSDimitry Andric ToolInvocation Invocation(std::move(CommandLine), &Action, &FM,
5795f757f3fSDimitry Andric PCHContainerOps);
5805f757f3fSDimitry Andric Invocation.setDiagnosticConsumer(Diags.getClient());
5815f757f3fSDimitry Andric Invocation.setDiagnosticOptions(&Diags.getDiagnosticOptions());
5825f757f3fSDimitry Andric if (!Invocation.run())
5835f757f3fSDimitry Andric return false;
5845f757f3fSDimitry Andric
5855f757f3fSDimitry Andric std::vector<std::string> Args = Action.takeLastCC1Arguments();
5865f757f3fSDimitry Andric Consumer.handleBuildCommand({std::move(Executable), std::move(Args)});
5875f757f3fSDimitry Andric return true;
5885f757f3fSDimitry Andric }
5895f757f3fSDimitry Andric
computeDependencies(StringRef WorkingDirectory,const std::vector<std::string> & CommandLine,DependencyConsumer & Consumer,DependencyActionController & Controller,DiagnosticConsumer & DC,std::optional<StringRef> ModuleName)590bdd1243dSDimitry Andric bool DependencyScanningWorker::computeDependencies(
591349cc55cSDimitry Andric StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
59206c3fb27SDimitry Andric DependencyConsumer &Consumer, DependencyActionController &Controller,
59306c3fb27SDimitry Andric DiagnosticConsumer &DC, std::optional<StringRef> ModuleName) {
594349cc55cSDimitry Andric // Reset what might have been modified in the previous worker invocation.
595bdd1243dSDimitry Andric BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
596349cc55cSDimitry Andric
597bdd1243dSDimitry Andric std::optional<std::vector<std::string>> ModifiedCommandLine;
598bdd1243dSDimitry Andric llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> ModifiedFS;
599bdd1243dSDimitry Andric
60006c3fb27SDimitry Andric // If we're scanning based on a module name alone, we don't expect the client
60106c3fb27SDimitry Andric // to provide us with an input file. However, the driver really wants to have
60206c3fb27SDimitry Andric // one. Let's just make it up to make the driver happy.
60306c3fb27SDimitry Andric if (ModuleName) {
604bdd1243dSDimitry Andric auto OverlayFS =
605bdd1243dSDimitry Andric llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
606bdd1243dSDimitry Andric auto InMemoryFS =
607bdd1243dSDimitry Andric llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
608bdd1243dSDimitry Andric InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
609bdd1243dSDimitry Andric OverlayFS->pushOverlay(InMemoryFS);
610bdd1243dSDimitry Andric ModifiedFS = OverlayFS;
61106c3fb27SDimitry Andric
61206c3fb27SDimitry Andric SmallString<128> FakeInputPath;
61306c3fb27SDimitry Andric // TODO: We should retry the creation if the path already exists.
61406c3fb27SDimitry Andric llvm::sys::fs::createUniquePath(*ModuleName + "-%%%%%%%%.input",
61506c3fb27SDimitry Andric FakeInputPath,
61606c3fb27SDimitry Andric /*MakeAbsolute=*/false);
61706c3fb27SDimitry Andric InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer(""));
61806c3fb27SDimitry Andric
61906c3fb27SDimitry Andric ModifiedCommandLine = CommandLine;
62006c3fb27SDimitry Andric ModifiedCommandLine->emplace_back(FakeInputPath);
621349cc55cSDimitry Andric }
622349cc55cSDimitry Andric
623349cc55cSDimitry Andric const std::vector<std::string> &FinalCommandLine =
624349cc55cSDimitry Andric ModifiedCommandLine ? *ModifiedCommandLine : CommandLine;
62506c3fb27SDimitry Andric auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS;
626349cc55cSDimitry Andric
627*0fca6ea1SDimitry Andric auto FileMgr =
628*0fca6ea1SDimitry Andric llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions{}, FinalFS);
629bdd1243dSDimitry Andric
63006c3fb27SDimitry Andric std::vector<const char *> FinalCCommandLine(FinalCommandLine.size(), nullptr);
63106c3fb27SDimitry Andric llvm::transform(FinalCommandLine, FinalCCommandLine.begin(),
632349cc55cSDimitry Andric [](const std::string &Str) { return Str.c_str(); });
633349cc55cSDimitry Andric
634bdd1243dSDimitry Andric auto DiagOpts = CreateAndPopulateDiagOpts(FinalCCommandLine);
635bdd1243dSDimitry Andric sanitizeDiagOpts(*DiagOpts);
636bdd1243dSDimitry Andric IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
637bdd1243dSDimitry Andric CompilerInstance::createDiagnostics(DiagOpts.release(), &DC,
638bdd1243dSDimitry Andric /*ShouldOwnClient=*/false);
639bdd1243dSDimitry Andric
640bdd1243dSDimitry Andric // Although `Diagnostics` are used only for command-line parsing, the
641bdd1243dSDimitry Andric // custom `DiagConsumer` might expect a `SourceManager` to be present.
642bdd1243dSDimitry Andric SourceManager SrcMgr(*Diags, *FileMgr);
643bdd1243dSDimitry Andric Diags->setSourceManager(&SrcMgr);
64481ad6265SDimitry Andric // DisableFree is modified by Tooling for running
64581ad6265SDimitry Andric // in-process; preserve the original value, which is
64681ad6265SDimitry Andric // always true for a driver invocation.
64781ad6265SDimitry Andric bool DisableFree = true;
64806c3fb27SDimitry Andric DependencyScanningAction Action(WorkingDirectory, Consumer, Controller, DepFS,
64906c3fb27SDimitry Andric Format, OptimizeArgs, EagerLoadModules,
65006c3fb27SDimitry Andric DisableFree, ModuleName);
6515f757f3fSDimitry Andric
6525f757f3fSDimitry Andric bool Success = false;
6535f757f3fSDimitry Andric if (FinalCommandLine[1] == "-cc1") {
6545f757f3fSDimitry Andric Success = createAndRunToolInvocation(FinalCommandLine, Action, *FileMgr,
6555f757f3fSDimitry Andric PCHContainerOps, *Diags, Consumer);
6565f757f3fSDimitry Andric } else {
6575f757f3fSDimitry Andric Success = forEachDriverJob(
658bdd1243dSDimitry Andric FinalCommandLine, *Diags, *FileMgr, [&](const driver::Command &Cmd) {
659bdd1243dSDimitry Andric if (StringRef(Cmd.getCreator().getName()) != "clang") {
660bdd1243dSDimitry Andric // Non-clang command. Just pass through to the dependency
661bdd1243dSDimitry Andric // consumer.
662bdd1243dSDimitry Andric Consumer.handleBuildCommand(
663bdd1243dSDimitry Andric {Cmd.getExecutable(),
664bdd1243dSDimitry Andric {Cmd.getArguments().begin(), Cmd.getArguments().end()}});
665bdd1243dSDimitry Andric return true;
666bdd1243dSDimitry Andric }
667bdd1243dSDimitry Andric
6685f757f3fSDimitry Andric // Insert -cc1 comand line options into Argv
669bdd1243dSDimitry Andric std::vector<std::string> Argv;
670bdd1243dSDimitry Andric Argv.push_back(Cmd.getExecutable());
671bdd1243dSDimitry Andric Argv.insert(Argv.end(), Cmd.getArguments().begin(),
672bdd1243dSDimitry Andric Cmd.getArguments().end());
673bdd1243dSDimitry Andric
674349cc55cSDimitry Andric // Create an invocation that uses the underlying file
675349cc55cSDimitry Andric // system to ensure that any file system requests that
676349cc55cSDimitry Andric // are made by the driver do not go through the
677349cc55cSDimitry Andric // dependency scanning filesystem.
6785f757f3fSDimitry Andric return createAndRunToolInvocation(std::move(Argv), Action, *FileMgr,
6795f757f3fSDimitry Andric PCHContainerOps, *Diags, Consumer);
680a7dea167SDimitry Andric });
6815f757f3fSDimitry Andric }
682bdd1243dSDimitry Andric
683bdd1243dSDimitry Andric if (Success && !Action.hasScanned())
684bdd1243dSDimitry Andric Diags->Report(diag::err_fe_expected_compiler_job)
685bdd1243dSDimitry Andric << llvm::join(FinalCommandLine, " ");
686bdd1243dSDimitry Andric return Success && Action.hasScanned();
6870b57cec5SDimitry Andric }
68806c3fb27SDimitry Andric
~DependencyActionController()68906c3fb27SDimitry Andric DependencyActionController::~DependencyActionController() {}
690