clang  9.0.0
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 
13 #include "clang/Frontend/Utils.h"
14 #include "clang/Tooling/Tooling.h"
15 
16 using namespace clang;
17 using namespace tooling;
18 using namespace dependencies;
19 
20 namespace {
21 
22 /// Prints out all of the gathered dependencies into a string.
23 class DependencyPrinter : public DependencyFileGenerator {
24 public:
25  DependencyPrinter(std::unique_ptr<DependencyOutputOptions> Opts,
26  std::string &S)
27  : DependencyFileGenerator(*Opts), Opts(std::move(Opts)), S(S) {}
28 
29  void finishedMainFile(DiagnosticsEngine &Diags) override {
30  llvm::raw_string_ostream OS(S);
31  outputDependencyFile(OS);
32  }
33 
34 private:
35  std::unique_ptr<DependencyOutputOptions> Opts;
36  std::string &S;
37 };
38 
39 /// A proxy file system that doesn't call `chdir` when changing the working
40 /// directory of a clang tool.
41 class ProxyFileSystemWithoutChdir : public llvm::vfs::ProxyFileSystem {
42 public:
43  ProxyFileSystemWithoutChdir(
45  : ProxyFileSystem(std::move(FS)) {}
46 
47  llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
48  assert(!CWD.empty() && "empty CWD");
49  return CWD;
50  }
51 
52  std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
53  CWD = Path.str();
54  return {};
55  }
56 
57 private:
58  std::string CWD;
59 };
60 
61 /// A clang tool that runs the preprocessor in a mode that's optimized for
62 /// dependency scanning for the given compiler invocation.
63 class DependencyScanningAction : public tooling::ToolAction {
64 public:
65  DependencyScanningAction(StringRef WorkingDirectory,
66  std::string &DependencyFileContents)
67  : WorkingDirectory(WorkingDirectory),
68  DependencyFileContents(DependencyFileContents) {}
69 
70  bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
71  FileManager *FileMgr,
72  std::shared_ptr<PCHContainerOperations> PCHContainerOps,
73  DiagnosticConsumer *DiagConsumer) override {
74  // Create a compiler instance to handle the actual work.
75  CompilerInstance Compiler(std::move(PCHContainerOps));
76  Compiler.setInvocation(std::move(Invocation));
77  FileMgr->getFileSystemOpts().WorkingDir = WorkingDirectory;
78  Compiler.setFileManager(FileMgr);
79 
80  // Don't print 'X warnings and Y errors generated'.
81  Compiler.getDiagnosticOpts().ShowCarets = false;
82  // Create the compiler's actual diagnostics engine.
83  Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
84  if (!Compiler.hasDiagnostics())
85  return false;
86 
87  Compiler.createSourceManager(*FileMgr);
88 
89  // Create the dependency collector that will collect the produced
90  // dependencies.
91  //
92  // This also moves the existing dependency output options from the
93  // invocation to the collector. The options in the invocation are reset,
94  // which ensures that the compiler won't create new dependency collectors,
95  // and thus won't write out the extra '.d' files to disk.
96  auto Opts = llvm::make_unique<DependencyOutputOptions>(
97  std::move(Compiler.getInvocation().getDependencyOutputOpts()));
98  // We need at least one -MT equivalent for the generator to work.
99  if (Opts->Targets.empty())
100  Opts->Targets = {"clang-scan-deps dependency"};
101  Compiler.addDependencyCollector(std::make_shared<DependencyPrinter>(
102  std::move(Opts), DependencyFileContents));
103 
104  auto Action = llvm::make_unique<PreprocessOnlyAction>();
105  const bool Result = Compiler.ExecuteAction(*Action);
106  FileMgr->clearStatCache();
107  return Result;
108  }
109 
110 private:
111  StringRef WorkingDirectory;
112  /// The dependency file will be written to this string.
113  std::string &DependencyFileContents;
114 };
115 
116 } // end anonymous namespace
117 
119  DiagOpts = new DiagnosticOptions();
120  PCHContainerOps = std::make_shared<PCHContainerOperations>();
121  /// FIXME: Use the shared file system from the service for fast scanning
122  /// mode.
123  WorkerFS = new ProxyFileSystemWithoutChdir(llvm::vfs::getRealFileSystem());
124 }
125 
128  StringRef WorkingDirectory,
129  const CompilationDatabase &CDB) {
130  // Capture the emitted diagnostics and report them to the client
131  // in the case of a failure.
132  std::string DiagnosticOutput;
133  llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
134  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.get());
135 
136  WorkerFS->setCurrentWorkingDirectory(WorkingDirectory);
137  tooling::ClangTool Tool(CDB, Input, PCHContainerOps, WorkerFS);
139  Tool.setRestoreWorkingDir(false);
140  Tool.setPrintErrorMessage(false);
141  Tool.setDiagnosticConsumer(&DiagPrinter);
142  std::string Output;
143  DependencyScanningAction Action(WorkingDirectory, Output);
144  if (Tool.run(&Action)) {
145  return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
146  llvm::inconvertibleErrorCode());
147  }
148  return Output;
149 }
Interface to process a clang::CompilerInvocation.
Definition: Tooling.h:73
void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer)
Set a DiagnosticConsumer to use during parsing.
Definition: Tooling.h:327
Implements support for file system lookup, file system caching, and directory search management...
Definition: FileManager.h:116
Utility to run a FrontendAction over a set of files.
Definition: Tooling.h:305
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1496
Definition: Format.h:2274
void clearArgumentsAdjusters()
Clear the command line arguments adjuster chain.
Definition: Tooling.cpp:400
llvm::Expected< std::string > getDependencyFile(const std::string &Input, StringRef WorkingDirectory, const CompilationDatabase &CDB)
Print out the dependency information into a string using the dependency file format that is specified...
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:573
std::string WorkingDir
If set, paths are resolved as if the working directory was set to the value of WorkingDir.
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:221
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:416
Dataflow Directional Tag Classes.
void clearStatCache()
Removes the FileSystemStatCache object from the manager.
Definition: FileManager.cpp:62
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
void setRestoreWorkingDir(bool RestoreCWD)
Sets whether working directory should be restored after calling run().
Definition: Tooling.cpp:569