clang  9.0.0svn
AllTUsExecution.cpp
Go to the documentation of this file.
1 //===- lib/Tooling/AllTUsExecution.cpp - Execute actions on all TUs. ------===//
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 
11 #include "llvm/Support/ThreadPool.h"
12 
13 namespace clang {
14 namespace tooling {
15 
16 const char *AllTUsToolExecutor::ExecutorName = "AllTUsToolExecutor";
17 
18 namespace {
19 llvm::Error make_string_error(const llvm::Twine &Message) {
20  return llvm::make_error<llvm::StringError>(Message,
21  llvm::inconvertibleErrorCode());
22 }
23 
25  return combineAdjusters(
29 }
30 
31 class ThreadSafeToolResults : public ToolResults {
32 public:
33  void addResult(StringRef Key, StringRef Value) override {
34  std::unique_lock<std::mutex> LockGuard(Mutex);
35  Results.addResult(Key, Value);
36  }
37 
38  std::vector<std::pair<llvm::StringRef, llvm::StringRef>>
39  AllKVResults() override {
40  return Results.AllKVResults();
41  }
42 
43  void forEachResult(llvm::function_ref<void(StringRef Key, StringRef Value)>
44  Callback) override {
45  Results.forEachResult(Callback);
46  }
47 
48 private:
49  InMemoryToolResults Results;
50  std::mutex Mutex;
51 };
52 
53 } // namespace
54 
55 llvm::cl::opt<std::string>
56  Filter("filter",
57  llvm::cl::desc("Only process files that match this filter. "
58  "This flag only applies to all-TUs."),
59  llvm::cl::init(".*"));
60 
62  const CompilationDatabase &Compilations, unsigned ThreadCount,
63  std::shared_ptr<PCHContainerOperations> PCHContainerOps)
64  : Compilations(Compilations), Results(new ThreadSafeToolResults),
65  Context(Results.get()), ThreadCount(ThreadCount) {}
66 
68  CommonOptionsParser Options, unsigned ThreadCount,
69  std::shared_ptr<PCHContainerOperations> PCHContainerOps)
70  : OptionsParser(std::move(Options)),
71  Compilations(OptionsParser->getCompilations()),
72  Results(new ThreadSafeToolResults), Context(Results.get()),
73  ThreadCount(ThreadCount) {}
74 
77  std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
78  Actions) {
79  if (Actions.empty())
80  return make_string_error("No action to execute.");
81 
82  if (Actions.size() != 1)
83  return make_string_error(
84  "Only support executing exactly 1 action at this point.");
85 
86  std::string ErrorMsg;
87  std::mutex TUMutex;
88  auto AppendError = [&](llvm::Twine Err) {
89  std::unique_lock<std::mutex> LockGuard(TUMutex);
90  ErrorMsg += Err.str();
91  };
92 
93  auto Log = [&](llvm::Twine Msg) {
94  std::unique_lock<std::mutex> LockGuard(TUMutex);
95  llvm::errs() << Msg.str() << "\n";
96  };
97 
98  std::vector<std::string> Files;
99  llvm::Regex RegexFilter(Filter);
100  for (const auto& File : Compilations.getAllFiles()) {
101  if (RegexFilter.match(File))
102  Files.push_back(File);
103  }
104  // Add a counter to track the progress.
105  const std::string TotalNumStr = std::to_string(Files.size());
106  unsigned Counter = 0;
107  auto Count = [&]() {
108  std::unique_lock<std::mutex> LockGuard(TUMutex);
109  return ++Counter;
110  };
111 
112  auto &Action = Actions.front();
113 
114  {
115  llvm::ThreadPool Pool(ThreadCount == 0 ? llvm::hardware_concurrency()
116  : ThreadCount);
117  llvm::SmallString<128> InitialWorkingDir;
118  if (auto EC = llvm::sys::fs::current_path(InitialWorkingDir)) {
119  InitialWorkingDir = "";
120  llvm::errs() << "Error while getting current working directory: "
121  << EC.message() << "\n";
122  }
123  for (std::string File : Files) {
124  Pool.async(
125  [&](std::string Path) {
126  Log("[" + std::to_string(Count()) + "/" + TotalNumStr +
127  "] Processing file " + Path);
128  ClangTool Tool(Compilations, {Path});
129  Tool.appendArgumentsAdjuster(Action.second);
130  Tool.appendArgumentsAdjuster(getDefaultArgumentsAdjusters());
131  for (const auto &FileAndContent : OverlayFiles)
132  Tool.mapVirtualFile(FileAndContent.first(),
133  FileAndContent.second);
134  // Do not restore working dir from multiple threads to avoid races.
135  Tool.setRestoreWorkingDir(false);
136  if (Tool.run(Action.first.get()))
137  AppendError(llvm::Twine("Failed to run action on ") + Path +
138  "\n");
139  },
140  File);
141  }
142  // Make sure all tasks have finished before resetting the working directory.
143  Pool.wait();
144  if (!InitialWorkingDir.empty()) {
145  if (auto EC = llvm::sys::fs::set_current_path(InitialWorkingDir))
146  llvm::errs() << "Error while restoring working directory: "
147  << EC.message() << "\n";
148  }
149  }
150 
151  if (!ErrorMsg.empty())
152  return make_string_error(ErrorMsg);
153 
154  return llvm::Error::success();
155 }
156 
157 static llvm::cl::opt<unsigned> ExecutorConcurrency(
158  "execute-concurrency",
159  llvm::cl::desc("The number of threads used to process all files in "
160  "parallel. Set to 0 for hardware concurrency. "
161  "This flag only applies to all-TUs."),
162  llvm::cl::init(0));
163 
165 public:
167  create(CommonOptionsParser &OptionsParser) override {
168  if (OptionsParser.getSourcePathList().empty())
169  return make_string_error(
170  "[AllTUsToolExecutorPlugin] Please provide a directory/file path in "
171  "the compilation database.");
172  return llvm::make_unique<AllTUsToolExecutor>(std::move(OptionsParser),
174  }
175 };
176 
177 static ToolExecutorPluginRegistry::Add<AllTUsToolExecutorPlugin>
178  X("all-TUs", "Runs FrontendActions on all TUs in the compilation database. "
179  "Tool results are stored in memory.");
180 
181 // This anchor is used to force the linker to link in the generated object file
182 // and thus register the plugin.
184 
185 } // end namespace tooling
186 } // end namespace clang
static llvm::Error make_string_error(const llvm::Twine &Message)
static llvm::cl::opt< unsigned > ExecutorConcurrency("execute-concurrency", llvm::cl::desc("The number of threads used to process all files in " "parallel. Set to 0 for hardware concurrency. " "This flag only applies to all-TUs."), llvm::cl::init(0))
Utility to run a FrontendAction over a set of files.
Definition: Tooling.h:305
ArgumentsAdjuster getClangStripDependencyFileAdjuster()
Gets an argument adjuster which removes dependency-file related command line arguments.
ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First, ArgumentsAdjuster Second)
Gets an argument adjuster which adjusts the arguments in sequence with the First adjuster and then wi...
virtual std::vector< std::string > getAllFiles() const
Returns the list of all files available in the compilation database.
Definition: Format.h:2071
llvm::Expected< std::unique_ptr< ToolExecutor > > create(CommonOptionsParser &OptionsParser) override
Create an ToolExecutor.
ArgumentsAdjuster getClangStripOutputAdjuster()
Gets an argument adjuster which removes output-related command line arguments.
std::function< CommandLineArguments(const CommandLineArguments &, StringRef Filename)> ArgumentsAdjuster
A prototype of a command line adjuster.
llvm::Error execute(llvm::ArrayRef< std::pair< std::unique_ptr< FrontendActionFactory >, ArgumentsAdjuster >> Actions) override
Executes each action with a corresponding arguments adjuster.
volatile int AllTUsToolExecutorAnchorSource
Interface for compilation databases.
llvm::cl::opt< std::string > Filter
A parser for options common to all command-line Clang tools.
Dataflow Directional Tag Classes.
AllTUsToolExecutor(const CompilationDatabase &Compilations, unsigned ThreadCount, std::shared_ptr< PCHContainerOperations > PCHContainerOps=std::make_shared< PCHContainerOperations >())
Init with CompilationDatabase.
Interface for factories that create specific executors.
Definition: Execution.h:158
ArgumentsAdjuster getClangSyntaxOnlyAdjuster()
Gets an argument adjuster that converts input command line arguments to the "syntax check only" varia...
static ToolExecutorPluginRegistry::Add< AllTUsToolExecutorPlugin > X("all-TUs", "Runs FrontendActions on all TUs in the compilation database. " "Tool results are stored in memory.")
void appendArgumentsAdjuster(ArgumentsAdjuster Adjuster)
Append a command line arguments adjuster to the adjuster chain.
Definition: Tooling.cpp:396
const std::vector< std::string > & getSourcePathList() const
Returns a list of source file paths to process.
static ArgumentsAdjuster getDefaultArgumentsAdjusters()