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
14#include "clang/Driver/Driver.h"
15#include "clang/Driver/Tool.h"
19#include "llvm/ADT/ScopeExit.h"
20#include "llvm/ADT/SmallVectorExtras.h"
21#include "llvm/ADT/iterator.h"
22#include "llvm/TargetParser/Host.h"
23#include <optional>
24
25using namespace clang;
26using namespace tooling;
27using namespace dependencies;
28
29namespace {
30/// Prints out all of the gathered dependencies into a string.
31class MakeDependencyPrinterConsumer : public DependencyConsumer {
32public:
33 void handleBuildCommand(Command) override {}
34
35 void
36 handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {
37 this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
38 }
39
40 void handleFileDependency(StringRef File) override {
41 SmallString<128> NormalizedFile = File;
42 llvm::sys::path::remove_dots(NormalizedFile, /*remove_dot_dot=*/true);
43 Dependencies.emplace_back(NormalizedFile.str());
44 }
45
46 // These are ignored for the make format as it can't support the full
47 // set of deps, and handleFileDependency handles enough for implicitly
48 // built modules to work.
49 void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {}
50 void handleModuleDependency(ModuleDeps MD) override {
51 MD.forEachFileDep([this](StringRef File) {
52 DependenciesFromModules.push_back(std::string(File));
53 });
54 }
55 void handleDirectModuleDependency(ModuleID ID) override {}
56 void handleVisibleModule(std::string ModuleName) override {}
57 void handleContextHash(std::string Hash) override {}
58
59 void printDependencies(std::string &S) {
60 assert(Opts && "Handled dependency output options.");
61
62 class DependencyPrinter : public DependencyFileGenerator {
63 public:
64 DependencyPrinter(DependencyOutputOptions &Opts,
65 ArrayRef<std::string> Dependencies,
66 ArrayRef<std::string> ModuleDependencies)
67 : DependencyFileGenerator(Opts) {
68 for (const auto &Dep : Dependencies)
69 addDependency(Dep);
70 for (const auto &Dep : ModuleDependencies)
71 addDependency(Dep);
72 }
73
74 void printDependencies(std::string &S) {
75 llvm::raw_string_ostream OS(S);
76 outputDependencyFile(OS);
77 }
78 };
79
80 DependencyPrinter Generator(*Opts, Dependencies, DependenciesFromModules);
81 Generator.printDependencies(S);
82 }
83
84protected:
85 std::unique_ptr<DependencyOutputOptions> Opts;
86 std::vector<std::string> Dependencies;
87 std::vector<std::string> DependenciesFromModules;
88};
89} // anonymous namespace
90
91static std::pair<std::unique_ptr<driver::Driver>,
92 std::unique_ptr<driver::Compilation>>
95 llvm::BumpPtrAllocator &Alloc) {
97 Argv.reserve(ArgStrs.size());
98 for (const std::string &Arg : ArgStrs)
99 Argv.push_back(Arg.c_str());
100
101 std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
102 Argv[0], llvm::sys::getDefaultTargetTriple(), Diags,
103 "clang LLVM compiler", FS);
104 Driver->setTitle("clang_based_tool");
105
106 bool CLMode = driver::IsClangCL(
107 driver::getDriverMode(Argv[0], ArrayRef(Argv).slice(1)));
108
109 if (llvm::Error E =
110 driver::expandResponseFiles(Argv, CLMode, Alloc, FS.get())) {
111 Diags.Report(diag::err_drv_expand_response_file)
112 << llvm::toString(std::move(E));
113 return std::make_pair(nullptr, nullptr);
114 }
115
116 std::unique_ptr<driver::Compilation> Compilation(
117 Driver->BuildCompilation(Argv));
118 if (!Compilation)
119 return std::make_pair(nullptr, nullptr);
120
121 if (Compilation->containsError())
122 return std::make_pair(nullptr, nullptr);
123
124 if (Compilation->getJobs().empty()) {
125 Diags.Report(diag::err_fe_expected_compiler_job)
126 << llvm::join(ArgStrs, " ");
127 return std::make_pair(nullptr, nullptr);
128 }
129
130 return std::make_pair(std::move(Driver), std::move(Compilation));
131}
132
133/// Constructs the full frontend command line, including executable, for the
134/// given driver \c Cmd.
137 const auto &Args = Cmd.getArguments();
139 Out.reserve(Args.size() + 1);
140 Out.emplace_back(Cmd.getExecutable());
141 llvm::append_range(Out, Args);
142 return Out;
143}
144
146 DependencyScanningWorker &Worker, StringRef WorkingDirectory,
147 ArrayRef<std::string> CommandLine, DependencyConsumer &Consumer,
148 DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer,
150 auto FS = Worker.makeEffectiveVFS(WorkingDirectory, OverlayFS);
151
152 // Compilation holds a non-owning a reference to the Driver, hence we need to
153 // keep the Driver alive when we use Compilation. Arguments to commands may be
154 // owned by Alloc when expanded from response files.
155 llvm::BumpPtrAllocator Alloc;
156 auto DiagEngineWithDiagOpts =
157 DiagnosticsEngineWithDiagOpts(CommandLine, FS, DiagConsumer);
158 const auto [Driver, Compilation] = buildCompilation(
159 CommandLine, *DiagEngineWithDiagOpts.DiagEngine, FS, Alloc);
160 if (!Compilation)
161 return false;
162
163 SmallVector<SmallVector<std::string, 0>> FrontendCommandLines;
164 for (const auto &Cmd : Compilation->getJobs())
165 FrontendCommandLines.push_back(buildCC1CommandLine(Cmd));
166 SmallVector<ArrayRef<std::string>> FrontendCommandLinesView(
167 FrontendCommandLines.begin(), FrontendCommandLines.end());
168
169 return Worker.computeDependencies(WorkingDirectory, FrontendCommandLinesView,
170 Consumer, Controller, DiagConsumer,
171 std::move(OverlayFS));
172}
173
174static llvm::Error makeErrorFromDiagnosticsOS(
175 TextDiagnosticsPrinterWithOutput &DiagPrinterWithOS) {
176 return llvm::make_error<llvm::StringError>(
177 DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode());
178}
179
181 DependencyScanningWorker &Worker, StringRef WorkingDirectory,
182 ArrayRef<std::string> CommandLine, DependencyConsumer &Consumer,
183 DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer,
185 const auto IsCC1Input = (CommandLine.size() >= 2 && CommandLine[1] == "-cc1");
186 return IsCC1Input ? Worker.computeDependencies(WorkingDirectory, CommandLine,
187 Consumer, Controller,
188 DiagConsumer, OverlayFS)
190 Worker, WorkingDirectory, CommandLine, Consumer,
191 Controller, DiagConsumer, OverlayFS);
192}
193
195 ArrayRef<std::string> CommandLine, StringRef CWD,
196 LookupModuleOutputCallback LookupModuleOutput,
197 DiagnosticConsumer &DiagConsumer) {
198 MakeDependencyPrinterConsumer DepConsumer;
199 CallbackActionController Controller(LookupModuleOutput);
200 if (!computeDependencies(Worker, CWD, CommandLine, DepConsumer, Controller,
201 DiagConsumer))
202 return std::nullopt;
203 std::string Output;
204 DepConsumer.printDependencies(Output);
205 return Output;
206}
207
209 const CompileCommand &Command, StringRef CWD, std::string &MakeformatOutput,
210 std::string &MakeformatOutputPath, DiagnosticConsumer &DiagConsumer) {
211 class P1689ModuleDependencyPrinterConsumer
212 : public MakeDependencyPrinterConsumer {
213 public:
214 P1689ModuleDependencyPrinterConsumer(P1689Rule &Rule,
215 const CompileCommand &Command)
216 : Filename(Command.Filename), Rule(Rule) {
217 Rule.PrimaryOutput = Command.Output;
218 }
219
220 void handleProvidedAndRequiredStdCXXModules(
221 std::optional<P1689ModuleInfo> Provided,
222 std::vector<P1689ModuleInfo> Requires) override {
223 Rule.Provides = std::move(Provided);
224 if (Rule.Provides)
225 Rule.Provides->SourcePath = Filename.str();
226 Rule.Requires = std::move(Requires);
227 }
228
229 StringRef getMakeFormatDependencyOutputPath() {
231 return {};
232 return Opts->OutputFile;
233 }
234
235 private:
236 StringRef Filename;
237 P1689Rule &Rule;
238 };
239
240 class P1689ActionController : public DependencyActionController {
241 public:
242 // The lookupModuleOutput is for clang modules. P1689 format don't need it.
243 std::string lookupModuleOutput(const ModuleDeps &,
244 ModuleOutputKind Kind) override {
245 return "";
246 }
247
248 std::unique_ptr<DependencyActionController> clone() const override {
249 return std::make_unique<P1689ActionController>();
250 }
251 };
252
253 P1689Rule Rule;
254 P1689ModuleDependencyPrinterConsumer Consumer(Rule, Command);
255 P1689ActionController Controller;
256 if (!computeDependencies(Worker, CWD, Command.CommandLine, Consumer,
257 Controller, DiagConsumer))
258 return std::nullopt;
259
260 MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath();
261 if (!MakeformatOutputPath.empty())
262 Consumer.printDependencies(MakeformatOutput);
263 return Rule;
264}
265
266static std::pair<IntrusiveRefCntPtr<llvm::vfs::FileSystem>,
267 std::vector<std::string>>
269 llvm::MemoryBufferRef TUBuffer) {
270 StringRef InputPath = TUBuffer.getBufferIdentifier();
271 auto InputBuf = llvm::MemoryBuffer::getMemBufferCopy(TUBuffer.getBuffer());
272
273 auto FS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
274 FS->addFile(InputPath, 0, std::move(InputBuf));
275
276 std::vector<std::string> ModifiedCommandLine(CommandLine);
277 ModifiedCommandLine.emplace_back(InputPath);
278
279 return std::make_pair(std::move(FS), ModifiedCommandLine);
280}
281
282static std::pair<IntrusiveRefCntPtr<llvm::vfs::FileSystem>,
283 std::vector<std::string>>
285 // The fake input buffer is read-only, and it is used to produce unique source
286 // locations for the diagnostics. Therefore, sharing this global buffer across
287 // threads is ok.
288 static const std::string FakeInput(
290
291 StringRef InputPath =
292 llvm::sys::path::is_style_windows(llvm::sys::path::Style::native)
293 ? "Z:\\module-include.input"
294 : "/module-include.input";
295 auto InputBuf = llvm::MemoryBuffer::getMemBuffer(FakeInput, InputPath);
296
297 auto FS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
298 FS->addFile(InputPath, 0, std::move(InputBuf));
299
300 std::vector<std::string> ModifiedCommandLine(CommandLine);
301 ModifiedCommandLine.emplace_back(InputPath);
302
303 return std::make_pair(std::move(FS), ModifiedCommandLine);
304}
305
306std::optional<TranslationUnitDeps>
308 ArrayRef<std::string> CommandLine, StringRef CWD,
309 DiagnosticConsumer &DiagConsumer,
310 const llvm::DenseSet<ModuleID> &AlreadySeen,
311 LookupModuleOutputCallback LookupModuleOutput,
312 std::optional<llvm::MemoryBufferRef> TUBuffer) {
313 FullDependencyConsumer Consumer(AlreadySeen);
314 CallbackActionController Controller(LookupModuleOutput);
315
316 // If we are scanning from a TUBuffer, create an overlay filesystem with the
317 // input as an in-memory file and add it to the command line.
319 std::vector<std::string> CommandLineWithTUBufferInput;
320 if (TUBuffer) {
321 std::tie(OverlayFS, CommandLineWithTUBufferInput) =
322 initVFSForTUBufferScanning(CommandLine, *TUBuffer);
323 CommandLine = CommandLineWithTUBufferInput;
324 }
325
326 if (!computeDependencies(Worker, CWD, CommandLine, Consumer, Controller,
327 DiagConsumer, std::move(OverlayFS)))
328 return std::nullopt;
329 return Consumer.takeTranslationUnitDeps();
330}
331
334 StringRef ModuleName, ArrayRef<std::string> CommandLine, StringRef CWD,
335 const llvm::DenseSet<ModuleID> &AlreadySeen,
336 DependencyActionController &Controller) {
337 auto MaybeCIWithContext = CompilerInstanceWithContext::initializeOrError(
338 *this, CWD, CommandLine, Controller);
339 if (auto Error = MaybeCIWithContext.takeError())
340 return Error;
341
342 return MaybeCIWithContext->computeDependenciesByNameOrError(
343 ModuleName, AlreadySeen, Controller);
344}
345
346static std::optional<SmallVector<std::string, 0>>
348 DiagnosticsEngine &Diags,
350 // Compilation holds a non-owning a reference to the Driver, hence we need to
351 // keep the Driver alive when we use Compilation. Arguments to commands may be
352 // owned by Alloc when expanded from response files.
353 llvm::BumpPtrAllocator Alloc;
354 const auto [Driver, Compilation] =
355 buildCompilation(CommandLine, Diags, std::move(FS), Alloc);
356 if (!Compilation)
357 return std::nullopt;
358
359 const auto IsClangCmd = [](const driver::Command &Cmd) {
360 return StringRef(Cmd.getCreator().getName()) == "clang";
361 };
362
363 const auto &Jobs = Compilation->getJobs();
364 if (const auto It = llvm::find_if(Jobs, IsClangCmd); It != Jobs.end())
365 return buildCC1CommandLine(*It);
366 return std::nullopt;
367}
368
369std::optional<CompilerInstanceWithContext>
371 DependencyScanningTool &Tool, StringRef CWD,
372 ArrayRef<std::string> CommandLine, DependencyActionController &Controller,
373 DiagnosticConsumer &DC) {
374 auto [OverlayFS, ModifiedCommandLine] = initVFSForByNameScanning(CommandLine);
375 auto FS = Tool.Worker.makeEffectiveVFS(CWD, OverlayFS);
376
377 auto DiagEngineWithCmdAndOpts =
378 std::make_unique<DiagnosticsEngineWithDiagOpts>(ModifiedCommandLine, FS,
379 DC);
380
381 if (CommandLine.size() >= 2 && CommandLine[1] == "-cc1") {
382 // The input command line is already a -cc1 invocation; initialize the
383 // compiler instance directly from it.
384 CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD, CommandLine);
385 if (!CIWithContext.initialize(Controller,
386 std::move(DiagEngineWithCmdAndOpts),
387 std::move(OverlayFS)))
388 return std::nullopt;
389 return std::move(CIWithContext);
390 }
391
392 // The input command line is either a driver-style command line, or
393 // ill-formed. In this case, we will first call the Driver to build a -cc1
394 // command line for this compilation or diagnose any ill-formed input.
395 const auto MaybeFirstCC1 = getFirstCC1CommandLine(
396 ModifiedCommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, FS);
397 if (!MaybeFirstCC1)
398 return std::nullopt;
399
400 std::vector<std::string> CC1CommandLine(MaybeFirstCC1->begin(),
401 MaybeFirstCC1->end());
402 CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD,
403 std::move(CC1CommandLine));
404 if (!CIWithContext.initialize(Controller, std::move(DiagEngineWithCmdAndOpts),
405 std::move(OverlayFS)))
406 return std::nullopt;
407 return std::move(CIWithContext);
408}
409
412 DependencyScanningTool &Tool, StringRef CWD,
413 ArrayRef<std::string> CommandLine, DependencyActionController &Controller) {
414 auto DiagPrinterWithOS =
415 std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine);
416
417 auto Result = initializeFromCommandline(Tool, CWD, CommandLine, Controller,
418 DiagPrinterWithOS->DiagPrinter);
419 if (Result) {
420 Result->DiagPrinterWithOS = std::move(DiagPrinterWithOS);
421 return std::move(*Result);
422 }
423 return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS);
424}
425
428 StringRef ModuleName, const llvm::DenseSet<ModuleID> &AlreadySeen,
429 DependencyActionController &Controller) {
430 FullDependencyConsumer Consumer(AlreadySeen);
431 // We need to clear the DiagnosticOutput so that each by-name lookup
432 // has a clean diagnostics buffer.
433 DiagPrinterWithOS->DiagnosticOutput.clear();
434 if (computeDependencies(ModuleName, Consumer, Controller))
435 return Consumer.takeTranslationUnitDeps();
436 return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS);
437}
438
439bool CompilerInstanceWithContext::initialize(
440 DependencyActionController &Controller,
441 std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts,
443 assert(DiagEngineWithDiagOpts && "Valid diagnostics engine required!");
444 DiagEngineWithCmdAndOpts = std::move(DiagEngineWithDiagOpts);
445 DiagConsumer = DiagEngineWithCmdAndOpts->DiagEngine->getClient();
446
447 assert(OverlayFS && "OverlayFS required!");
448 auto FS = Worker.makeEffectiveVFS(CWD, std::move(OverlayFS));
449
450 OriginalInvocation = createCompilerInvocation(
451 CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine);
452 if (!OriginalInvocation) {
453 DiagEngineWithCmdAndOpts->DiagEngine->Report(
454 diag::err_fe_expected_compiler_job)
455 << llvm::join(CommandLine, " ");
456 return false;
457 }
458
459 if (any(Worker.Service.getOpts().OptimizeArgs &
460 ScanningOptimizations::Macros))
461 canonicalizeDefines(OriginalInvocation->getPreprocessorOpts());
462
463 // Create the CompilerInstance.
464 std::shared_ptr<ModuleCache> ModCache =
465 makeInProcessModuleCache(Worker.Service.getModuleCacheEntries());
466 CIPtr = std::make_unique<CompilerInstance>(
467 createScanCompilerInvocation(*OriginalInvocation, Worker.Service,
468 Controller),
469 Worker.PCHContainerOps, std::move(ModCache));
470 auto &CI = *CIPtr;
471
473 CI, std::move(FS), DiagEngineWithCmdAndOpts->DiagEngine->getClient(),
474 Worker.Service, Worker.DepFS);
475
476 StableDirs = getInitialStableDirs(CI);
477 auto MaybePrebuiltModulesASTMap =
478 computePrebuiltModulesASTMap(CI, StableDirs);
479 if (!MaybePrebuiltModulesASTMap)
480 return false;
481
482 PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
483 OutputOpts = createDependencyOutputOptions(*OriginalInvocation);
484
485 // We do not create the target in initializeScanCompilerInstance because
486 // setting it here is unique for by-name lookups. We create the target only
487 // once here, and the information is reused for all computeDependencies calls.
488 // We do not need to call createTarget explicitly if we go through
489 // CompilerInstance::ExecuteAction to perform scanning.
490 CI.createTarget();
491
492 return true;
493}
494
496 StringRef ModuleName, DependencyConsumer &Consumer,
497 DependencyActionController &Controller) {
498 if (SrcLocOffset >= MaxNumOfQueries)
499 llvm::report_fatal_error("exceeded maximum by-name scans for worker");
500
501 assert(CIPtr && "CIPtr must be initialized before calling this method");
502 auto &CI = *CIPtr;
503
504 // We need to reset the diagnostics, so that the diagnostics issued
505 // during a previous computeDependencies call do not affect the current call.
506 // If we do not reset, we may inherit fatal errors from a previous call.
507 CI.getDiagnostics().Reset();
508
509 // We create this cleanup object because computeDependencies may exit
510 // early with errors.
511 llvm::scope_exit CleanUp([&]() {
512 CI.clearDependencyCollectors();
513 // The preprocessor may not be created at the entry of this method,
514 // but it must have been created when this method returns, whether
515 // there are errors during scanning or not.
516 CI.getPreprocessor().removePPCallbacks();
517 });
518
520 CI, std::make_unique<DependencyOutputOptions>(*OutputOpts),
521 Worker.Service,
522 /* The MDC's constructor makes a copy of the OriginalInvocation, so
523 we can pass it in without worrying that it might be changed across
524 invocations of computeDependencies. */
525 *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs);
526
527 CompilerInvocation ModuleInvocation(*OriginalInvocation);
528 if (!Controller.initialize(CI, ModuleInvocation))
529 return false;
530
531 if (!SrcLocOffset) {
532 // When SrcLocOffset is zero, we are at the beginning of the fake source
533 // file. In this case, we call BeginSourceFile to initialize.
534 std::unique_ptr<FrontendAction> Action =
535 std::make_unique<PreprocessOnlyAction>();
536 auto *InputFile = CI.getFrontendOpts().Inputs.begin();
537 bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile);
538 assert(ActionBeginSucceeded && "Action BeginSourceFile must succeed");
539 (void)ActionBeginSucceeded;
540 }
541
542 Preprocessor &PP = CI.getPreprocessor();
544 FileID MainFileID = SM.getMainFileID();
545 SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID);
546 SourceLocation IDLocation = FileStart.getLocWithOffset(SrcLocOffset);
547 PPCallbacks *CB = nullptr;
548 if (!SrcLocOffset) {
549 // We need to call EnterSourceFile when SrcLocOffset is zero to initialize
550 // the preprocessor.
551 bool PPFailed = PP.EnterSourceFile(MainFileID, nullptr, SourceLocation());
552 assert(!PPFailed && "Preprocess must be able to enter the main file.");
553 (void)PPFailed;
554 CB = MDC->getPPCallbacks();
555 } else {
556 // When SrcLocOffset is non-zero, the preprocessor has already been
557 // initialized through a previous call of computeDependencies. We want to
558 // preserve the PP's state, hence we do not call EnterSourceFile again.
559 MDC->attachToPreprocessor(PP);
560 CB = MDC->getPPCallbacks();
561
562 FileID PrevFID;
563 SrcMgr::CharacteristicKind FileType = SM.getFileCharacteristic(IDLocation);
564 CB->LexedFileChanged(MainFileID,
566 FileType, PrevFID, IDLocation);
567 }
568
569 // FIXME: Scan modules asynchronously here as well.
570
571 SrcLocOffset++;
573 IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName);
574 Path.emplace_back(IDLocation, ModuleID);
575 auto ModResult = CI.loadModule(IDLocation, Path, Module::Hidden, false);
576
577 assert(CB && "Must have PPCallbacks after module loading");
578 CB->moduleImport(SourceLocation(), Path, ModResult);
579
580 if (!ModResult)
581 return false;
582
583 if (CI.getDiagnostics().hasErrorOccurred())
584 return false;
585
586 MDC->run(Consumer);
587 MDC->applyDiscoveredDependencies(ModuleInvocation);
588
589 if (!Controller.finalize(CI, ModuleInvocation))
590 return false;
591
592 Consumer.handleBuildCommand(
593 {CommandLine[0], ModuleInvocation.getCC1CommandLine()});
594
595 return true;
596}
Defines the Diagnostic-related interfaces.
static std::pair< IntrusiveRefCntPtr< llvm::vfs::FileSystem >, std::vector< std::string > > initVFSForByNameScanning(ArrayRef< std::string > CommandLine)
static std::optional< SmallVector< std::string, 0 > > getFirstCC1CommandLine(ArrayRef< std::string > CommandLine, DiagnosticsEngine &Diags, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS)
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 bool computeDependenciesForDriverCommandLine(DependencyScanningWorker &Worker, StringRef WorkingDirectory, ArrayRef< std::string > CommandLine, DependencyConsumer &Consumer, DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer, IntrusiveRefCntPtr< llvm::vfs::FileSystem > OverlayFS)
static llvm::Error makeErrorFromDiagnosticsOS(TextDiagnosticsPrinterWithOutput &DiagPrinterWithOS)
static std::pair< IntrusiveRefCntPtr< llvm::vfs::FileSystem >, std::vector< std::string > > initVFSForTUBufferScanning(ArrayRef< std::string > CommandLine, llvm::MemoryBufferRef TUBuffer)
static SmallVector< std::string, 0 > buildCC1CommandLine(const driver::Command &Cmd)
Constructs the full frontend command line, including executable, for the given driver Cmd.
#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.
DependencyOutputFormat OutputFormat
The format for the dependency file.
std::string OutputFile
The file to write dependency output to.
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:233
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:645
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition PPCallbacks.h:37
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...
virtual bool initialize(CompilerInstance &ScanInstance, CompilerInvocation &NewInvocation)
Initializes the scan instance and modifies the resulting TU invocation.
virtual bool finalize(CompilerInstance &ScanInstance, CompilerInvocation &NewInvocation)
Finalizes the scan instance and modifies the resulting TU invocation.
virtual void handleBuildCommand(Command Cmd)
An individual dependency scanning worker that is able to run on its own thread.
IntrusiveRefCntPtr< llvm::vfs::FileSystem > makeEffectiveVFS(StringRef WorkingDirectory, IntrusiveRefCntPtr< llvm::vfs::FileSystem > OverlayFS=nullptr) const
Creates the effective VFS that will be used for the scan.
Command - An executable path/name and argument vector to execute.
Definition Job.h:106
const llvm::opt::ArgStringList & getArguments() const
Definition Job.h:232
const char * getExecutable() const
Definition Job.h:230
static std::optional< CompilerInstanceWithContext > initializeFromCommandline(DependencyScanningTool &Tool, StringRef CWD, ArrayRef< std::string > CommandLine, dependencies::DependencyActionController &Controller, DiagnosticConsumer &DC)
Initialize the tool's compiler instance from the commandline.
static llvm::Expected< CompilerInstanceWithContext > initializeOrError(DependencyScanningTool &Tool, StringRef CWD, ArrayRef< std::string > CommandLine, dependencies::DependencyActionController &Controller)
Initializing the context and the compiler instance.
bool computeDependencies(StringRef ModuleName, dependencies::DependencyConsumer &Consumer, dependencies::DependencyActionController &Controller)
llvm::Expected< dependencies::TranslationUnitDeps > computeDependenciesByNameOrError(StringRef ModuleName, const llvm::DenseSet< dependencies::ModuleID > &AlreadySeen, dependencies::DependencyActionController &Controller)
Computes the dependeny for the module named ModuleName.
The high-level implementation of the dependency discovery tool that runs on an individual worker thre...
std::optional< std::string > getDependencyFile(ArrayRef< std::string > CommandLine, StringRef CWD, dependencies::LookupModuleOutputCallback LookupModuleOutput, DiagnosticConsumer &DiagConsumer)
Print out the dependency information into a string using the dependency file format that is specified...
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 ...
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.
llvm::Expected< dependencies::TranslationUnitDeps > getModuleDependencies(StringRef ModuleName, ArrayRef< std::string > CommandLine, StringRef CWD, const llvm::DenseSet< dependencies::ModuleID > &AlreadySeen, dependencies::DependencyActionController &Controller)
Given a compilation context specified via the Clang driver command-line, gather modular dependencies ...
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.
std::shared_ptr< CompilerInvocation > createScanCompilerInvocation(const CompilerInvocation &Invocation, const DependencyScanningService &Service, DependencyActionController &Controller)
Creates a CompilerInvocation suitable for the dependency scanner.
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, DependencyScanningService &Service, CompilerInvocation &Inv, DependencyActionController &Controller, PrebuiltModulesAttrsMap PrebuiltModulesASTMap, SmallVector< StringRef > &StableDirs)
Create the dependency collector that will collect the produced dependencies.
llvm::StringRef getDriverMode(StringRef ProgName, ArrayRef< const char * > Args)
Returns the driver mode option's value, i.e.
Definition Driver.cpp:7429
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:7446
bool IsClangCL(StringRef DriverMode)
Checks whether the value produced by getDriverMode is for CL mode.
Definition Driver.cpp:7444
@ 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, IntrusiveRefCntPtr< llvm::vfs::FileSystem > 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.
void forEachFileDep(llvm::function_ref< void(StringRef)> Cb) const
Invokes Cb for all file dependencies of this module.
This is used to identify a specific module.
Specifies the working directory and command of a compilation.