clang  10.0.0svn
DependencyScanningWorker.cpp
Go to the documentation of this file.
1 //===- DependencyScanningWorker.cpp - clang-scan-deps worker --------------===//
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/Frontend/Utils.h"
17 #include "clang/Tooling/Tooling.h"
18 
19 using namespace clang;
20 using namespace tooling;
21 using namespace dependencies;
22 
23 namespace {
24 
25 /// Forwards the gatherered dependencies to the consumer.
26 class DependencyConsumerForwarder : public DependencyFileGenerator {
27 public:
28  DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts,
30  : DependencyFileGenerator(*Opts), Opts(std::move(Opts)), C(C) {}
31 
32  void finishedMainFile(DiagnosticsEngine &Diags) override {
33  llvm::SmallString<256> CanonPath;
34  for (const auto &File : getDependencies()) {
35  CanonPath = File;
36  llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true);
37  C.handleFileDependency(*Opts, CanonPath);
38  }
39  }
40 
41 private:
42  std::unique_ptr<DependencyOutputOptions> Opts;
44 };
45 
46 /// A proxy file system that doesn't call `chdir` when changing the working
47 /// directory of a clang tool.
48 class ProxyFileSystemWithoutChdir : public llvm::vfs::ProxyFileSystem {
49 public:
50  ProxyFileSystemWithoutChdir(
52  : ProxyFileSystem(std::move(FS)) {}
53 
54  llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
55  assert(!CWD.empty() && "empty CWD");
56  return CWD;
57  }
58 
59  std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
60  CWD = Path.str();
61  return {};
62  }
63 
64 private:
65  std::string CWD;
66 };
67 
68 /// A clang tool that runs the preprocessor in a mode that's optimized for
69 /// dependency scanning for the given compiler invocation.
70 class DependencyScanningAction : public tooling::ToolAction {
71 public:
72  DependencyScanningAction(
73  StringRef WorkingDirectory, DependencyConsumer &Consumer,
76  : WorkingDirectory(WorkingDirectory), Consumer(Consumer),
77  DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings) {}
78 
79  bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
80  FileManager *FileMgr,
81  std::shared_ptr<PCHContainerOperations> PCHContainerOps,
82  DiagnosticConsumer *DiagConsumer) override {
83  // Create a compiler instance to handle the actual work.
84  CompilerInstance Compiler(std::move(PCHContainerOps));
85  Compiler.setInvocation(std::move(Invocation));
86 
87  // Don't print 'X warnings and Y errors generated'.
88  Compiler.getDiagnosticOpts().ShowCarets = false;
89  // Create the compiler's actual diagnostics engine.
90  Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
91  if (!Compiler.hasDiagnostics())
92  return false;
93 
94  // Use the dependency scanning optimized file system if we can.
95  if (DepFS) {
96  const CompilerInvocation &CI = Compiler.getInvocation();
97  // Add any filenames that were explicity passed in the build settings and
98  // that might be opened, as we want to ensure we don't run source
99  // minimization on them.
100  DepFS->IgnoredFiles.clear();
101  for (const auto &Entry : CI.getHeaderSearchOpts().UserEntries)
102  DepFS->IgnoredFiles.insert(Entry.Path);
103  for (const auto &Entry : CI.getHeaderSearchOpts().VFSOverlayFiles)
104  DepFS->IgnoredFiles.insert(Entry);
105 
106  // Support for virtual file system overlays on top of the caching
107  // filesystem.
109  CI, Compiler.getDiagnostics(), DepFS));
110 
111  // Pass the skip mappings which should speed up excluded conditional block
112  // skipping in the preprocessor.
113  if (PPSkipMappings)
114  Compiler.getPreprocessorOpts()
115  .ExcludedConditionalDirectiveSkipMappings = PPSkipMappings;
116  }
117 
118  FileMgr->getFileSystemOpts().WorkingDir = WorkingDirectory;
119  Compiler.setFileManager(FileMgr);
120  Compiler.createSourceManager(*FileMgr);
121 
122  // Create the dependency collector that will collect the produced
123  // dependencies.
124  //
125  // This also moves the existing dependency output options from the
126  // invocation to the collector. The options in the invocation are reset,
127  // which ensures that the compiler won't create new dependency collectors,
128  // and thus won't write out the extra '.d' files to disk.
129  auto Opts = std::make_unique<DependencyOutputOptions>(
130  std::move(Compiler.getInvocation().getDependencyOutputOpts()));
131  // We need at least one -MT equivalent for the generator to work.
132  if (Opts->Targets.empty())
133  Opts->Targets = {"clang-scan-deps dependency"};
134  Compiler.addDependencyCollector(
135  std::make_shared<DependencyConsumerForwarder>(std::move(Opts),
136  Consumer));
137 
138  auto Action = std::make_unique<PreprocessOnlyAction>();
139  const bool Result = Compiler.ExecuteAction(*Action);
140  if (!DepFS)
141  FileMgr->clearStatCache();
142  return Result;
143  }
144 
145 private:
146  StringRef WorkingDirectory;
147  DependencyConsumer &Consumer;
150 };
151 
152 } // end anonymous namespace
153 
155  DependencyScanningService &Service) {
156  DiagOpts = new DiagnosticOptions();
157  PCHContainerOps = std::make_shared<PCHContainerOperations>();
158  RealFS = new ProxyFileSystemWithoutChdir(llvm::vfs::getRealFileSystem());
159  if (Service.canSkipExcludedPPRanges())
160  PPSkipMappings =
161  std::make_unique<ExcludedPreprocessorDirectiveSkipMapping>();
164  Service.getSharedCache(), RealFS, PPSkipMappings.get());
165  if (Service.canReuseFileManager())
166  Files = new FileManager(FileSystemOptions(), RealFS);
167 }
168 
170  DiagnosticOptions *DiagOpts,
171  llvm::function_ref<bool(DiagnosticConsumer &DC)> BodyShouldSucceed) {
172  // Capture the emitted diagnostics and report them to the client
173  // in the case of a failure.
174  std::string DiagnosticOutput;
175  llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
176  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts);
177 
178  if (BodyShouldSucceed(DiagPrinter))
179  return llvm::Error::success();
180  return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
181  llvm::inconvertibleErrorCode());
182 }
183 
185  const std::string &Input, StringRef WorkingDirectory,
186  const CompilationDatabase &CDB, DependencyConsumer &Consumer) {
187  RealFS->setCurrentWorkingDirectory(WorkingDirectory);
188  return runWithDiags(DiagOpts.get(), [&](DiagnosticConsumer &DC) {
189  /// Create the tool that uses the underlying file system to ensure that any
190  /// file system requests that are made by the driver do not go through the
191  /// dependency scanning filesystem.
192  tooling::ClangTool Tool(CDB, Input, PCHContainerOps, RealFS, Files);
194  Tool.setRestoreWorkingDir(false);
195  Tool.setPrintErrorMessage(false);
196  Tool.setDiagnosticConsumer(&DC);
197  DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS,
198  PPSkipMappings.get());
199  return !Tool.run(&Action);
200  });
201 }
HeaderSearchOptions & getHeaderSearchOpts()
Interface to process a clang::CompilerInvocation.
Definition: Tooling.h:73
void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer)
Set a DiagnosticConsumer to use during parsing.
Definition: Tooling.h:328
Implements support for file system lookup, file system caching, and directory search management...
Definition: FileManager.h:171
Utility to run a FrontendAction over a set of files.
Definition: Tooling.h:303
This mode is used to compute the dependencies by running the preprocessor over the source files that ...
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1489
SharedFileSystemEntry & get(StringRef Key)
Returns a cache entry for the corresponding key.
Definition: Format.h:2327
void clearArgumentsAdjusters()
Clear the command line arguments adjuster chain.
Definition: Tooling.cpp:405
std::vector< Entry > UserEntries
User specified include entries.
The dependency scanning service contains the shared state that is used by the invidual dependency sca...
A virtual file system optimized for the dependency discovery.
std::vector< std::string > VFSOverlayFiles
The set of user-provided virtual filesystem overlay files.
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:149
Builds a dependency file when attached to a Preprocessor (for includes) and ASTReader (for module imp...
Definition: Utils.h:122
void setPrintErrorMessage(bool PrintErrorMessage)
Sets whether an error message should be printed out if an action fails.
Definition: Tooling.cpp:578
static llvm::Error runWithDiags(DiagnosticOptions *DiagOpts, llvm::function_ref< bool(DiagnosticConsumer &DC)> BodyShouldSucceed)
std::string WorkingDir
If set, paths are resolved as if the working directory was set to the value of WorkingDir.
DependencyScanningFilesystemSharedCache & getSharedCache()
Interface for compilation databases.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
FileSystemOptions & getFileSystemOpts()
Returns the current file system options.
Definition: FileManager.h:356
Options for controlling the compiler diagnostics engine.
int run(ToolAction *Action)
Runs an action over all files specified in the command line.
Definition: Tooling.cpp:421
void setVirtualFileSystem(IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS)
Definition: FileManager.h:361
Dataflow Directional Tag Classes.
void clearStatCache()
Removes the FileSystemStatCache object from the manager.
Definition: FileManager.cpp:62
llvm::Error computeDependencies(const std::string &Input, StringRef WorkingDirectory, const CompilationDatabase &CDB, DependencyConsumer &Consumer)
Run the dependency scanning tool for a given clang driver invocation (as specified for the given Inpu...
IntrusiveRefCntPtr< llvm::vfs::FileSystem > createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags)
Helper class for holding the data necessary to invoke the compiler.
Keeps track of options that affect how file operations are performed.
void setRestoreWorkingDir(bool RestoreCWD)
Sets whether working directory should be restored after calling run().
Definition: Tooling.cpp:574
llvm::DenseMap< const llvm::MemoryBuffer *, const PreprocessorSkippedRangeMapping * > ExcludedPreprocessorDirectiveSkipMapping
The datastructure that holds the mapping between the active memory buffers and the individual skip ma...