clang 23.0.0git
DependencyScanningTool.cpp
Go to the documentation of this file.
1//===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
13#include "clang/Driver/Tool.h"
17#include "llvm/ADT/ScopeExit.h"
18#include "llvm/ADT/SmallVectorExtras.h"
19#include "llvm/ADT/iterator.h"
20#include "llvm/TargetParser/Host.h"
21#include <optional>
22
23using namespace clang;
24using namespace tooling;
25using namespace dependencies;
26
27namespace {
28/// Prints out all of the gathered dependencies into a string.
29class MakeDependencyPrinterConsumer : public DependencyConsumer {
30public:
31 void handleBuildCommand(Command) override {}
32
33 void
34 handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {
35 this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
36 }
37
38 void handleFileDependency(StringRef File) override {
39 Dependencies.push_back(std::string(File));
40 }
41
42 // These are ignored for the make format as it can't support the full
43 // set of deps, and handleFileDependency handles enough for implicitly
44 // built modules to work.
45 void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {}
46 void handleModuleDependency(ModuleDeps MD) override {}
47 void handleDirectModuleDependency(ModuleID ID) override {}
48 void handleVisibleModule(std::string ModuleName) override {}
49 void handleContextHash(std::string Hash) override {}
50
51 void printDependencies(std::string &S) {
52 assert(Opts && "Handled dependency output options.");
53
54 class DependencyPrinter : public DependencyFileGenerator {
55 public:
56 DependencyPrinter(DependencyOutputOptions &Opts,
57 ArrayRef<std::string> Dependencies)
58 : DependencyFileGenerator(Opts) {
59 for (const auto &Dep : Dependencies)
60 addDependency(Dep);
61 }
62
63 void printDependencies(std::string &S) {
64 llvm::raw_string_ostream OS(S);
65 outputDependencyFile(OS);
66 }
67 };
68
69 DependencyPrinter Generator(*Opts, Dependencies);
70 Generator.printDependencies(S);
71 }
72
73protected:
74 std::unique_ptr<DependencyOutputOptions> Opts;
75 std::vector<std::string> Dependencies;
76};
77} // anonymous namespace
78
79static std::pair<std::unique_ptr<driver::Driver>,
80 std::unique_ptr<driver::Compilation>>
83 llvm::BumpPtrAllocator &Alloc) {
85 Argv.reserve(ArgStrs.size());
86 for (const std::string &Arg : ArgStrs)
87 Argv.push_back(Arg.c_str());
88
89 std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
90 Argv[0], llvm::sys::getDefaultTargetTriple(), Diags,
91 "clang LLVM compiler", FS);
92 Driver->setTitle("clang_based_tool");
93
94 bool CLMode = driver::IsClangCL(
95 driver::getDriverMode(Argv[0], ArrayRef(Argv).slice(1)));
96
97 if (llvm::Error E =
98 driver::expandResponseFiles(Argv, CLMode, Alloc, FS.get())) {
99 Diags.Report(diag::err_drv_expand_response_file)
100 << llvm::toString(std::move(E));
101 return std::make_pair(nullptr, nullptr);
102 }
103
104 std::unique_ptr<driver::Compilation> Compilation(
105 Driver->BuildCompilation(Argv));
106 if (!Compilation)
107 return std::make_pair(nullptr, nullptr);
108
109 if (Compilation->containsError())
110 return std::make_pair(nullptr, nullptr);
111
112 if (Compilation->getJobs().empty()) {
113 Diags.Report(diag::err_fe_expected_compiler_job)
114 << llvm::join(ArgStrs, " ");
115 return std::make_pair(nullptr, nullptr);
116 }
117
118 return std::make_pair(std::move(Driver), std::move(Compilation));
119}
120
121/// Constructs the full frontend command line, including executable, for the
122/// given driver \c Cmd.
125 const auto &Args = Cmd.getArguments();
127 Out.reserve(Args.size() + 1);
128 Out.emplace_back(Cmd.getExecutable());
129 llvm::append_range(Out, Args);
130 return Out;
131}
132
134 DependencyScanningWorker &Worker, StringRef WorkingDirectory,
135 ArrayRef<std::string> CommandLine, DependencyConsumer &Consumer,
136 DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer,
139 if (OverlayFS) {
140 FS = OverlayFS;
141 } else {
142 FS = &Worker.getVFS();
143 FS->setCurrentWorkingDirectory(WorkingDirectory);
144 }
145
146 // Compilation holds a non-owning a reference to the Driver, hence we need to
147 // keep the Driver alive when we use Compilation. Arguments to commands may be
148 // owned by Alloc when expanded from response files.
149 llvm::BumpPtrAllocator Alloc;
150 auto DiagEngineWithDiagOpts =
151 DiagnosticsEngineWithDiagOpts(CommandLine, FS, DiagConsumer);
152 const auto [Driver, Compilation] = buildCompilation(
153 CommandLine, *DiagEngineWithDiagOpts.DiagEngine, FS, Alloc);
154 if (!Compilation)
155 return false;
156
157 SmallVector<SmallVector<std::string, 0>> FrontendCommandLines;
158 for (const auto &Cmd : Compilation->getJobs())
159 FrontendCommandLines.push_back(buildCC1CommandLine(Cmd));
160 SmallVector<ArrayRef<std::string>> FrontendCommandLinesView(
161 FrontendCommandLines.begin(), FrontendCommandLines.end());
162
163 return Worker.computeDependencies(WorkingDirectory, FrontendCommandLinesView,
164 Consumer, Controller, DiagConsumer,
165 OverlayFS);
166}
167
168static llvm::Error makeErrorFromDiagnosticsOS(
169 TextDiagnosticsPrinterWithOutput &DiagPrinterWithOS) {
170 return llvm::make_error<llvm::StringError>(
171 DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode());
172}
173
175 DependencyScanningWorker &Worker, StringRef WorkingDirectory,
176 ArrayRef<std::string> CommandLine, DependencyConsumer &Consumer,
177 DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer,
179 const auto IsCC1Input = (CommandLine.size() >= 2 && CommandLine[1] == "-cc1");
180 return IsCC1Input ? Worker.computeDependencies(WorkingDirectory, CommandLine,
181 Consumer, Controller,
182 DiagConsumer, OverlayFS)
184 Worker, WorkingDirectory, CommandLine, Consumer,
185 Controller, DiagConsumer, OverlayFS);
186}
187
188std::optional<std::string>
190 StringRef CWD,
191 DiagnosticConsumer &DiagConsumer) {
192 MakeDependencyPrinterConsumer DepConsumer;
193 CallbackActionController Controller(nullptr);
194 if (!computeDependencies(Worker, CWD, CommandLine, DepConsumer, Controller,
195 DiagConsumer))
196 return std::nullopt;
197 std::string Output;
198 DepConsumer.printDependencies(Output);
199 return Output;
200}
201
203 const CompileCommand &Command, StringRef CWD, std::string &MakeformatOutput,
204 std::string &MakeformatOutputPath, DiagnosticConsumer &DiagConsumer) {
205 class P1689ModuleDependencyPrinterConsumer
206 : public MakeDependencyPrinterConsumer {
207 public:
208 P1689ModuleDependencyPrinterConsumer(P1689Rule &Rule,
209 const CompileCommand &Command)
210 : Filename(Command.Filename), Rule(Rule) {
211 Rule.PrimaryOutput = Command.Output;
212 }
213
214 void handleProvidedAndRequiredStdCXXModules(
215 std::optional<P1689ModuleInfo> Provided,
216 std::vector<P1689ModuleInfo> Requires) override {
217 Rule.Provides = std::move(Provided);
218 if (Rule.Provides)
219 Rule.Provides->SourcePath = Filename.str();
220 Rule.Requires = std::move(Requires);
221 }
222
223 StringRef getMakeFormatDependencyOutputPath() {
224 if (Opts->OutputFormat != DependencyOutputFormat::Make)
225 return {};
226 return Opts->OutputFile;
227 }
228
229 private:
230 StringRef Filename;
231 P1689Rule &Rule;
232 };
233
234 class P1689ActionController : public DependencyActionController {
235 public:
236 // The lookupModuleOutput is for clang modules. P1689 format don't need it.
237 std::string lookupModuleOutput(const ModuleDeps &,
238 ModuleOutputKind Kind) override {
239 return "";
240 }
241 };
242
243 P1689Rule Rule;
244 P1689ModuleDependencyPrinterConsumer Consumer(Rule, Command);
245 P1689ActionController Controller;
246 if (!computeDependencies(Worker, CWD, Command.CommandLine, Consumer,
247 Controller, DiagConsumer))
248 return std::nullopt;
249
250 MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath();
251 if (!MakeformatOutputPath.empty())
252 Consumer.printDependencies(MakeformatOutput);
253 return Rule;
254}
255
256static std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,
257 std::vector<std::string>>
259 ArrayRef<std::string> CommandLine,
260 StringRef WorkingDirectory,
261 llvm::MemoryBufferRef TUBuffer) {
262 // Reset what might have been modified in the previous worker invocation.
263 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
264
265 auto OverlayFS =
266 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
267 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
268 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
269 auto InputPath = TUBuffer.getBufferIdentifier();
270 InMemoryFS->addFile(
271 InputPath, 0, llvm::MemoryBuffer::getMemBufferCopy(TUBuffer.getBuffer()));
272 IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay = InMemoryFS;
273
274 OverlayFS->pushOverlay(InMemoryOverlay);
275 std::vector<std::string> ModifiedCommandLine(CommandLine);
276 ModifiedCommandLine.emplace_back(InputPath);
277
278 return std::make_pair(OverlayFS, ModifiedCommandLine);
279}
280
281// The fake input buffer is read-only, and it is used to produce
282// unique source locations for the diagnostics. Therefore sharing
283// this global buffer across threads is ok.
284static const std::string
287
288static std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,
289 std::vector<std::string>>
291 ArrayRef<std::string> CommandLine,
292 StringRef WorkingDirectory) {
293 // Reset what might have been modified in the previous worker invocation.
294 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
295
296 // If we're scanning based on a module name alone, we don't expect the client
297 // to provide us with an input file. However, the driver really wants to have
298 // one. Let's just make it up to make the driver happy.
299 auto OverlayFS =
300 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
301 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
302 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
303 StringRef FakeInputPath("module-include.input");
304 InMemoryFS->addFile(FakeInputPath, 0,
305 llvm::MemoryBuffer::getMemBuffer(FakeInput));
306 IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay = InMemoryFS;
307 OverlayFS->pushOverlay(InMemoryOverlay);
308
309 std::vector<std::string> ModifiedCommandLine(CommandLine);
310 ModifiedCommandLine.emplace_back(FakeInputPath);
311
312 return std::make_pair(OverlayFS, ModifiedCommandLine);
313}
314
315std::optional<TranslationUnitDeps>
317 ArrayRef<std::string> CommandLine, StringRef CWD,
318 DiagnosticConsumer &DiagConsumer,
319 const llvm::DenseSet<ModuleID> &AlreadySeen,
320 LookupModuleOutputCallback LookupModuleOutput,
321 std::optional<llvm::MemoryBufferRef> TUBuffer) {
322 FullDependencyConsumer Consumer(AlreadySeen);
323 CallbackActionController Controller(LookupModuleOutput);
324
325 // If we are scanning from a TUBuffer, create an overlay filesystem with the
326 // input as an in-memory file and add it to the command line.
328 std::vector<std::string> CommandLineWithTUBufferInput;
329 if (TUBuffer) {
330 std::tie(OverlayFS, CommandLineWithTUBufferInput) =
331 initVFSForTUBufferScanning(&Worker.getVFS(), CommandLine, CWD,
332 *TUBuffer);
333 CommandLine = CommandLineWithTUBufferInput;
334 }
335
336 if (!computeDependencies(Worker, CWD, CommandLine, Consumer, Controller,
337 DiagConsumer, OverlayFS))
338 return std::nullopt;
339 return Consumer.takeTranslationUnitDeps();
340}
341
344 StringRef ModuleName, ArrayRef<std::string> CommandLine, StringRef CWD,
345 const llvm::DenseSet<ModuleID> &AlreadySeen,
346 LookupModuleOutputCallback LookupModuleOutput) {
347 auto MaybeCIWithContext =
348 CompilerInstanceWithContext::initializeOrError(*this, CWD, CommandLine);
349 if (auto Error = MaybeCIWithContext.takeError())
350 return Error;
351
352 return MaybeCIWithContext->computeDependenciesByNameOrError(
353 ModuleName, AlreadySeen, LookupModuleOutput);
354}
355
356static std::optional<SmallVector<std::string, 0>> getFirstCC1CommandLine(
357 ArrayRef<std::string> CommandLine, DiagnosticsEngine &Diags,
359 // Compilation holds a non-owning a reference to the Driver, hence we need to
360 // keep the Driver alive when we use Compilation. Arguments to commands may be
361 // owned by Alloc when expanded from response files.
362 llvm::BumpPtrAllocator Alloc;
363 const auto [Driver, Compilation] =
364 buildCompilation(CommandLine, Diags, OverlayFS, Alloc);
365 if (!Compilation)
366 return std::nullopt;
367
368 const auto IsClangCmd = [](const driver::Command &Cmd) {
369 return StringRef(Cmd.getCreator().getName()) == "clang";
370 };
371
372 const auto &Jobs = Compilation->getJobs();
373 if (const auto It = llvm::find_if(Jobs, IsClangCmd); It != Jobs.end())
374 return buildCC1CommandLine(*It);
375 return std::nullopt;
376}
377
378std::optional<CompilerInstanceWithContext>
380 DependencyScanningTool &Tool, StringRef CWD,
381 ArrayRef<std::string> CommandLine, DiagnosticConsumer &DC) {
382 auto [OverlayFS, ModifiedCommandLine] =
383 initVFSForByNameScanning(&Tool.Worker.getVFS(), CommandLine, CWD);
384 auto DiagEngineWithCmdAndOpts =
385 std::make_unique<DiagnosticsEngineWithDiagOpts>(ModifiedCommandLine,
386 OverlayFS, DC);
387
388 if (CommandLine.size() >= 2 && CommandLine[1] == "-cc1") {
389 // The input command line is already a -cc1 invocation; initialize the
390 // compiler instance directly from it.
391 CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD, CommandLine);
392 if (!CIWithContext.initialize(std::move(DiagEngineWithCmdAndOpts),
393 OverlayFS))
394 return std::nullopt;
395 return std::move(CIWithContext);
396 }
397
398 // The input command line is either a driver-style command line, or
399 // ill-formed. In this case, we will first call the Driver to build a -cc1
400 // command line for this compilation or diagnose any ill-formed input.
401 const auto MaybeFirstCC1 = getFirstCC1CommandLine(
402 ModifiedCommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS);
403 if (!MaybeFirstCC1)
404 return std::nullopt;
405
406 std::vector<std::string> CC1CommandLine(MaybeFirstCC1->begin(),
407 MaybeFirstCC1->end());
408 CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD,
409 std::move(CC1CommandLine));
410 if (!CIWithContext.initialize(std::move(DiagEngineWithCmdAndOpts), OverlayFS))
411 return std::nullopt;
412 return std::move(CIWithContext);
413}
414
417 DependencyScanningTool &Tool, StringRef CWD,
418 ArrayRef<std::string> CommandLine) {
419 auto DiagPrinterWithOS =
420 std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine);
421
422 auto Result = initializeFromCommandline(Tool, CWD, CommandLine,
423 DiagPrinterWithOS->DiagPrinter);
424 if (Result) {
425 Result->DiagPrinterWithOS = std::move(DiagPrinterWithOS);
426 return std::move(*Result);
427 }
428 return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS);
429}
430
433 StringRef ModuleName, const llvm::DenseSet<ModuleID> &AlreadySeen,
434 LookupModuleOutputCallback LookupModuleOutput) {
435 FullDependencyConsumer Consumer(AlreadySeen);
436 CallbackActionController Controller(LookupModuleOutput);
437 // We need to clear the DiagnosticOutput so that each by-name lookup
438 // has a clean diagnostics buffer.
439 DiagPrinterWithOS->DiagnosticOutput.clear();
440 if (computeDependencies(ModuleName, Consumer, Controller))
441 return Consumer.takeTranslationUnitDeps();
442 return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS);
443}
444
445bool CompilerInstanceWithContext::initialize(
446 std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts,
448 assert(DiagEngineWithDiagOpts && "Valid diagnostics engine required!");
449 DiagEngineWithCmdAndOpts = std::move(DiagEngineWithDiagOpts);
450 DiagConsumer = DiagEngineWithCmdAndOpts->DiagEngine->getClient();
451
452#ifndef NDEBUG
453 assert(OverlayFS && "OverlayFS required!");
454 bool SawDepFS = false;
455 OverlayFS->visit([&](llvm::vfs::FileSystem &VFS) {
456 SawDepFS |= &VFS == Worker.DepFS.get();
457 });
458 assert(SawDepFS && "OverlayFS not based on DepFS");
459#endif
460
461 OriginalInvocation = createCompilerInvocation(
462 CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine);
463 if (!OriginalInvocation) {
464 DiagEngineWithCmdAndOpts->DiagEngine->Report(
465 diag::err_fe_expected_compiler_job)
466 << llvm::join(CommandLine, " ");
467 return false;
468 }
469
470 if (any(Worker.Service.getOpts().OptimizeArgs &
471 ScanningOptimizations::Macros))
472 canonicalizeDefines(OriginalInvocation->getPreprocessorOpts());
473
474 // Create the CompilerInstance.
475 std::shared_ptr<ModuleCache> ModCache =
476 makeInProcessModuleCache(Worker.Service.getModuleCacheEntries());
477 CIPtr = std::make_unique<CompilerInstance>(
478 createScanCompilerInvocation(*OriginalInvocation, Worker.Service),
479 Worker.PCHContainerOps, std::move(ModCache));
480 auto &CI = *CIPtr;
481
483 CI, OverlayFS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(),
484 Worker.Service, Worker.DepFS);
485
486 StableDirs = getInitialStableDirs(CI);
487 auto MaybePrebuiltModulesASTMap =
488 computePrebuiltModulesASTMap(CI, StableDirs);
489 if (!MaybePrebuiltModulesASTMap)
490 return false;
491
492 PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
493 OutputOpts = createDependencyOutputOptions(*OriginalInvocation);
494
495 // We do not create the target in initializeScanCompilerInstance because
496 // setting it here is unique for by-name lookups. We create the target only
497 // once here, and the information is reused for all computeDependencies calls.
498 // We do not need to call createTarget explicitly if we go through
499 // CompilerInstance::ExecuteAction to perform scanning.
500 CI.createTarget();
501
502 return true;
503}
504
506 StringRef ModuleName, DependencyConsumer &Consumer,
507 DependencyActionController &Controller) {
508 if (SrcLocOffset >= MaxNumOfQueries)
509 llvm::report_fatal_error("exceeded maximum by-name scans for worker");
510
511 assert(CIPtr && "CIPtr must be initialized before calling this method");
512 auto &CI = *CIPtr;
513
514 // We need to reset the diagnostics, so that the diagnostics issued
515 // during a previous computeDependencies call do not affect the current call.
516 // If we do not reset, we may inherit fatal errors from a previous call.
517 CI.getDiagnostics().Reset();
518
519 // We create this cleanup object because computeDependencies may exit
520 // early with errors.
521 llvm::scope_exit CleanUp([&]() {
522 CI.clearDependencyCollectors();
523 // The preprocessor may not be created at the entry of this method,
524 // but it must have been created when this method returns, whether
525 // there are errors during scanning or not.
526 CI.getPreprocessor().removePPCallbacks();
527 });
528
530 CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), CWD, Consumer,
531 Worker.Service,
532 /* The MDC's constructor makes a copy of the OriginalInvocation, so
533 we can pass it in without worrying that it might be changed across
534 invocations of computeDependencies. */
535 *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs);
536
537 if (!SrcLocOffset) {
538 // When SrcLocOffset is zero, we are at the beginning of the fake source
539 // file. In this case, we call BeginSourceFile to initialize.
540 std::unique_ptr<FrontendAction> Action =
541 std::make_unique<PreprocessOnlyAction>();
542 auto *InputFile = CI.getFrontendOpts().Inputs.begin();
543 bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile);
544 assert(ActionBeginSucceeded && "Action BeginSourceFile must succeed");
545 (void)ActionBeginSucceeded;
546 }
547
548 Preprocessor &PP = CI.getPreprocessor();
550 FileID MainFileID = SM.getMainFileID();
551 SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID);
552 SourceLocation IDLocation = FileStart.getLocWithOffset(SrcLocOffset);
553 PPCallbacks *CB = nullptr;
554 if (!SrcLocOffset) {
555 // We need to call EnterSourceFile when SrcLocOffset is zero to initialize
556 // the preprocessor.
557 bool PPFailed = PP.EnterSourceFile(MainFileID, nullptr, SourceLocation());
558 assert(!PPFailed && "Preprocess must be able to enter the main file.");
559 (void)PPFailed;
560 CB = MDC->getPPCallbacks();
561 } else {
562 // When SrcLocOffset is non-zero, the preprocessor has already been
563 // initialized through a previous call of computeDependencies. We want to
564 // preserve the PP's state, hence we do not call EnterSourceFile again.
565 MDC->attachToPreprocessor(PP);
566 CB = MDC->getPPCallbacks();
567
568 FileID PrevFID;
569 SrcMgr::CharacteristicKind FileType = SM.getFileCharacteristic(IDLocation);
570 CB->LexedFileChanged(MainFileID,
572 FileType, PrevFID, IDLocation);
573 }
574
575 // FIXME: Scan modules asynchronously here as well.
576
577 SrcLocOffset++;
579 IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName);
580 Path.emplace_back(IDLocation, ModuleID);
581 auto ModResult = CI.loadModule(IDLocation, Path, Module::Hidden, false);
582
583 assert(CB && "Must have PPCallbacks after module loading");
584 CB->moduleImport(SourceLocation(), Path, ModResult);
585 // Note that we are calling the CB's EndOfMainFile function, which
586 // forwards the results to the dependency consumer.
587 // It does not indicate the end of processing the fake file.
588 CB->EndOfMainFile();
589
590 if (!ModResult)
591 return false;
592
593 CompilerInvocation ModuleInvocation(*OriginalInvocation);
594 MDC->applyDiscoveredDependencies(ModuleInvocation);
595 Consumer.handleBuildCommand(
596 {CommandLine[0], ModuleInvocation.getCC1CommandLine()});
597
598 return true;
599}
Defines the Diagnostic-related interfaces.
static std::pair< std::unique_ptr< driver::Driver >, std::unique_ptr< driver::Compilation > > buildCompilation(ArrayRef< std::string > ArgStrs, DiagnosticsEngine &Diags, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, llvm::BumpPtrAllocator &Alloc)
static std::pair< IntrusiveRefCntPtr< llvm::vfs::OverlayFileSystem >, std::vector< std::string > > initVFSForTUBufferScanning(IntrusiveRefCntPtr< llvm::vfs::FileSystem > BaseFS, ArrayRef< std::string > CommandLine, StringRef WorkingDirectory, llvm::MemoryBufferRef TUBuffer)
static llvm::Error makeErrorFromDiagnosticsOS(TextDiagnosticsPrinterWithOutput &DiagPrinterWithOS)
static const std::string FakeInput(" ", clang::tooling::CompilerInstanceWithContext::MaxNumOfQueries)
static std::pair< IntrusiveRefCntPtr< llvm::vfs::OverlayFileSystem >, std::vector< std::string > > initVFSForByNameScanning(IntrusiveRefCntPtr< llvm::vfs::FileSystem > BaseFS, ArrayRef< std::string > CommandLine, StringRef WorkingDirectory)
static SmallVector< std::string, 0 > buildCC1CommandLine(const driver::Command &Cmd)
Constructs the full frontend command line, including executable, for the given driver Cmd.
static bool computeDependenciesForDriverCommandLine(DependencyScanningWorker &Worker, StringRef WorkingDirectory, ArrayRef< std::string > CommandLine, DependencyConsumer &Consumer, DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer, IntrusiveRefCntPtr< llvm::vfs::OverlayFileSystem > OverlayFS)
static std::optional< SmallVector< std::string, 0 > > getFirstCC1CommandLine(ArrayRef< std::string > CommandLine, DiagnosticsEngine &Diags, llvm::IntrusiveRefCntPtr< llvm::vfs::OverlayFileSystem > OverlayFS)
#define SM(sm)
Defines the clang::Preprocessor interface.
std::vector< std::string > getCC1CommandLine() const
Generate cc1-compatible command line arguments from this instance, wrapping the result as a std::vect...
Helper class for holding the data necessary to invoke the compiler.
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Concrete class used by the front-end to report problems and issues.
Definition Diagnostic.h:232
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
One of these records is kept for each identifier that is lexed.
@ Hidden
All of the names in this module are hidden.
Definition Module.h:445
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition PPCallbacks.h:37
virtual void EndOfMainFile()
Callback invoked when the end of the main file is reached.
virtual void LexedFileChanged(FileID FID, LexedFileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID, SourceLocation Loc)
Callback invoked whenever the Lexer moves to a different file for lexing.
Definition PPCallbacks.h:72
virtual void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, const Module *Imported)
Callback invoked whenever there was an explicit module-import syntax.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
bool EnterSourceFile(FileID FID, ConstSearchDirIterator Dir, SourceLocation Loc, bool IsFirstIncludeOfFile=true)
Add a source file to the top of the include stack and start lexing tokens from it instead of the curr...
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
SourceManager & getSourceManager() const
Encodes a location in the source.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
A simple dependency action controller that uses a callback.
Dependency scanner callbacks that are used during scanning to influence the behaviour of the scan - f...
An individual dependency scanning worker that is able to run on its own thread.
Command - An executable path/name and argument vector to execute.
Definition Job.h:106
const llvm::opt::ArgStringList & getArguments() const
Definition Job.h:224
const char * getExecutable() const
Definition Job.h:222
static llvm::Expected< CompilerInstanceWithContext > initializeOrError(DependencyScanningTool &Tool, StringRef CWD, ArrayRef< std::string > CommandLine)
Initializing the context and the compiler instance.
static std::optional< CompilerInstanceWithContext > initializeFromCommandline(DependencyScanningTool &Tool, StringRef CWD, ArrayRef< std::string > CommandLine, DiagnosticConsumer &DC)
Initialize the tool's compiler instance from the commandline.
llvm::Expected< dependencies::TranslationUnitDeps > computeDependenciesByNameOrError(StringRef ModuleName, const llvm::DenseSet< dependencies::ModuleID > &AlreadySeen, dependencies::LookupModuleOutputCallback LookupModuleOutput)
Computes the dependeny for the module named ModuleName.
bool computeDependencies(StringRef ModuleName, dependencies::DependencyConsumer &Consumer, dependencies::DependencyActionController &Controller)
The high-level implementation of the dependency discovery tool that runs on an individual worker thre...
std::optional< dependencies::TranslationUnitDeps > getTranslationUnitDependencies(ArrayRef< std::string > CommandLine, StringRef CWD, DiagnosticConsumer &DiagConsumer, const llvm::DenseSet< dependencies::ModuleID > &AlreadySeen, dependencies::LookupModuleOutputCallback LookupModuleOutput, std::optional< llvm::MemoryBufferRef > TUBuffer=std::nullopt)
Given a Clang driver command-line for a translation unit, gather the modular dependencies and return ...
llvm::Expected< dependencies::TranslationUnitDeps > getModuleDependencies(StringRef ModuleName, ArrayRef< std::string > CommandLine, StringRef CWD, const llvm::DenseSet< dependencies::ModuleID > &AlreadySeen, dependencies::LookupModuleOutputCallback LookupModuleOutput)
Given a compilation context specified via the Clang driver command-line, gather modular dependencies ...
std::optional< P1689Rule > getP1689ModuleDependencyFile(const CompileCommand &Command, StringRef CWD, std::string &MakeformatOutput, std::string &MakeformatOutputPath, DiagnosticConsumer &DiagConsumer)
Collect the module dependency in P1689 format for C++20 named modules.
std::optional< std::string > getDependencyFile(ArrayRef< std::string > CommandLine, StringRef CWD, DiagnosticConsumer &DiagConsumer)
Print out the dependency information into a string using the dependency file format that is specified...
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
SmallVector< StringRef > getInitialStableDirs(const CompilerInstance &ScanInstance)
llvm::function_ref< std::string(const ModuleDeps &, ModuleOutputKind)> LookupModuleOutputCallback
A callback to lookup module outputs for "-fmodule-file=", "-o" etc.
@ VFS
Remove unused -ivfsoverlay arguments.
void initializeScanCompilerInstance(CompilerInstance &ScanInstance, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service, IntrusiveRefCntPtr< DependencyScanningWorkerFilesystem > DepFS)
ModuleOutputKind
An output from a module compilation, such as the path of the module file.
std::unique_ptr< CompilerInvocation > createCompilerInvocation(ArrayRef< std::string > CommandLine, DiagnosticsEngine &Diags)
void canonicalizeDefines(PreprocessorOptions &PPOpts)
Canonicalizes command-line macro defines (e.g. removing "-DX -UX").
std::unique_ptr< DependencyOutputOptions > createDependencyOutputOptions(const CompilerInvocation &Invocation)
Creates dependency output options to be reported to the dependency consumer, deducing missing informa...
std::optional< PrebuiltModulesAttrsMap > computePrebuiltModulesASTMap(CompilerInstance &ScanInstance, SmallVector< StringRef > &StableDirs)
std::shared_ptr< ModuleCache > makeInProcessModuleCache(ModuleCacheEntries &Entries)
std::shared_ptr< ModuleDepCollector > initializeScanInstanceDependencyCollector(CompilerInstance &ScanInstance, std::unique_ptr< DependencyOutputOptions > DepOutputOpts, StringRef WorkingDirectory, DependencyConsumer &Consumer, DependencyScanningService &Service, CompilerInvocation &Inv, DependencyActionController &Controller, PrebuiltModulesAttrsMap PrebuiltModulesASTMap, llvm::SmallVector< StringRef > &StableDirs)
Create the dependency collector that will collect the produced dependencies.
std::shared_ptr< CompilerInvocation > createScanCompilerInvocation(const CompilerInvocation &Invocation, const DependencyScanningService &Service)
Creates a CompilerInvocation suitable for the dependency scanner.
llvm::StringRef getDriverMode(StringRef ProgName, ArrayRef< const char * > Args)
Returns the driver mode option's value, i.e.
Definition Driver.cpp:7271
llvm::Error expandResponseFiles(SmallVectorImpl< const char * > &Args, bool ClangCLMode, llvm::BumpPtrAllocator &Alloc, llvm::vfs::FileSystem *FS=nullptr)
Expand response files from a clang driver or cc1 invocation.
Definition Driver.cpp:7288
bool IsClangCL(StringRef DriverMode)
Checks whether the value produced by getDriverMode is for CL mode.
Definition Driver.cpp:7286
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
bool computeDependencies(dependencies::DependencyScanningWorker &Worker, StringRef WorkingDirectory, ArrayRef< std::string > CommandLine, dependencies::DependencyConsumer &Consumer, dependencies::DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer, llvm::IntrusiveRefCntPtr< llvm::vfs::OverlayFileSystem > OverlayFS=nullptr)
Run the dependency scanning worker for the given driver or frontend command-line, and report the disc...
std::shared_ptr< MatchComputation< T > > Generator
Definition RewriteRule.h:65
The JSON file list parser is used to communicate input to InstallAPI.
@ Worker
'worker' clause, allowed on 'loop', Combined, and 'routine' directives.
@ Result
The result type of a method or function.
Definition TypeBase.h:905
int __ovld __cnfn any(char)
Returns 1 if the most significant bit in any component of x is set; otherwise returns 0.
A command-line tool invocation that is part of building a TU.
This is used to identify a specific module.
Specifies the working directory and command of a compilation.