clang  8.0.0svn
AllTUsExecution.cpp
Go to the documentation of this file.
1 //===- lib/Tooling/AllTUsExecution.cpp - Execute actions on all TUs. ------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
12 #include "llvm/Support/ThreadPool.h"
13 
14 namespace clang {
15 namespace tooling {
16 
17 const char *AllTUsToolExecutor::ExecutorName = "AllTUsToolExecutor";
18 
19 namespace {
20 llvm::Error make_string_error(const llvm::Twine &Message) {
21  return llvm::make_error<llvm::StringError>(Message,
22  llvm::inconvertibleErrorCode());
23 }
24 
26  return combineAdjusters(
30 }
31 
32 class ThreadSafeToolResults : public ToolResults {
33 public:
34  void addResult(StringRef Key, StringRef Value) override {
35  std::unique_lock<std::mutex> LockGuard(Mutex);
36  Results.addResult(Key, Value);
37  }
38 
39  std::vector<std::pair<llvm::StringRef, llvm::StringRef>>
40  AllKVResults() override {
41  return Results.AllKVResults();
42  }
43 
44  void forEachResult(llvm::function_ref<void(StringRef Key, StringRef Value)>
45  Callback) override {
46  Results.forEachResult(Callback);
47  }
48 
49 private:
50  InMemoryToolResults Results;
51  std::mutex Mutex;
52 };
53 
54 } // namespace
55 
57  const CompilationDatabase &Compilations, unsigned ThreadCount,
58  std::shared_ptr<PCHContainerOperations> PCHContainerOps)
59  : Compilations(Compilations), Results(new ThreadSafeToolResults),
60  Context(Results.get()), ThreadCount(ThreadCount) {}
61 
63  CommonOptionsParser Options, unsigned ThreadCount,
64  std::shared_ptr<PCHContainerOperations> PCHContainerOps)
65  : OptionsParser(std::move(Options)),
66  Compilations(OptionsParser->getCompilations()),
67  Results(new ThreadSafeToolResults), Context(Results.get()),
68  ThreadCount(ThreadCount) {}
69 
72  std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
73  Actions) {
74  if (Actions.empty())
75  return make_string_error("No action to execute.");
76 
77  if (Actions.size() != 1)
78  return make_string_error(
79  "Only support executing exactly 1 action at this point.");
80 
81  std::string ErrorMsg;
82  std::mutex TUMutex;
83  auto AppendError = [&](llvm::Twine Err) {
84  std::unique_lock<std::mutex> LockGuard(TUMutex);
85  ErrorMsg += Err.str();
86  };
87 
88  auto Log = [&](llvm::Twine Msg) {
89  std::unique_lock<std::mutex> LockGuard(TUMutex);
90  llvm::errs() << Msg.str() << "\n";
91  };
92 
93  auto Files = Compilations.getAllFiles();
94  // Add a counter to track the progress.
95  const std::string TotalNumStr = std::to_string(Files.size());
96  unsigned Counter = 0;
97  auto Count = [&]() {
98  std::unique_lock<std::mutex> LockGuard(TUMutex);
99  return ++Counter;
100  };
101 
102  auto &Action = Actions.front();
103 
104  {
105  llvm::ThreadPool Pool(ThreadCount == 0 ? llvm::hardware_concurrency()
106  : ThreadCount);
107  llvm::SmallString<128> InitialWorkingDir;
108  if (auto EC = llvm::sys::fs::current_path(InitialWorkingDir)) {
109  InitialWorkingDir = "";
110  llvm::errs() << "Error while getting current working directory: "
111  << EC.message() << "\n";
112  }
113  for (std::string File : Files) {
114  Pool.async(
115  [&](std::string Path) {
116  Log("[" + std::to_string(Count()) + "/" + TotalNumStr +
117  "] Processing file " + Path);
118  ClangTool Tool(Compilations, {Path});
119  Tool.appendArgumentsAdjuster(Action.second);
120  Tool.appendArgumentsAdjuster(getDefaultArgumentsAdjusters());
121  for (const auto &FileAndContent : OverlayFiles)
122  Tool.mapVirtualFile(FileAndContent.first(),
123  FileAndContent.second);
124  // Do not restore working dir from multiple threads to avoid races.
125  Tool.setRestoreWorkingDir(false);
126  if (Tool.run(Action.first.get()))
127  AppendError(llvm::Twine("Failed to run action on ") + Path +
128  "\n");
129  },
130  File);
131  }
132  // Make sure all tasks have finished before resetting the working directory.
133  Pool.wait();
134  if (!InitialWorkingDir.empty()) {
135  if (auto EC = llvm::sys::fs::set_current_path(InitialWorkingDir))
136  llvm::errs() << "Error while restoring working directory: "
137  << EC.message() << "\n";
138  }
139  }
140 
141  if (!ErrorMsg.empty())
142  return make_string_error(ErrorMsg);
143 
144  return llvm::Error::success();
145 }
146 
147 static llvm::cl::opt<unsigned> ExecutorConcurrency(
148  "execute-concurrency",
149  llvm::cl::desc("The number of threads used to process all files in "
150  "parallel. Set to 0 for hardware concurrency."),
151  llvm::cl::init(0));
152 
154 public:
156  create(CommonOptionsParser &OptionsParser) override {
157  if (OptionsParser.getSourcePathList().empty())
158  return make_string_error(
159  "[AllTUsToolExecutorPlugin] Please provide a directory/file path in "
160  "the compilation database.");
161  return llvm::make_unique<AllTUsToolExecutor>(std::move(OptionsParser),
163  }
164 };
165 
166 static ToolExecutorPluginRegistry::Add<AllTUsToolExecutorPlugin>
167  X("all-TUs", "Runs FrontendActions on all TUs in the compilation database. "
168  "Tool results are stored in memory.");
169 
170 // This anchor is used to force the linker to link in the generated object file
171 // and thus register the plugin.
173 
174 } // end namespace tooling
175 } // end namespace clang
static llvm::Error make_string_error(const llvm::Twine &Message)
Utility to run a FrontendAction over a set of files.
Definition: Tooling.h:306
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."), llvm::cl::init(0))
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:2031
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.
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:157
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:393
const std::vector< std::string > & getSourcePathList() const
Returns a list of source file paths to process.
static ArgumentsAdjuster getDefaultArgumentsAdjusters()