clang  10.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/Threading.h"
12 #include "llvm/Support/ThreadPool.h"
13 #include "llvm/Support/VirtualFileSystem.h"
14 
15 namespace clang {
16 namespace tooling {
17 
18 const char *AllTUsToolExecutor::ExecutorName = "AllTUsToolExecutor";
19 
20 namespace {
21 llvm::Error make_string_error(const llvm::Twine &Message) {
22  return llvm::make_error<llvm::StringError>(Message,
23  llvm::inconvertibleErrorCode());
24 }
25 
27  return combineAdjusters(
31 }
32 
33 class ThreadSafeToolResults : public ToolResults {
34 public:
35  void addResult(StringRef Key, StringRef Value) override {
36  std::unique_lock<std::mutex> LockGuard(Mutex);
37  Results.addResult(Key, Value);
38  }
39 
40  std::vector<std::pair<llvm::StringRef, llvm::StringRef>>
41  AllKVResults() override {
42  return Results.AllKVResults();
43  }
44 
45  void forEachResult(llvm::function_ref<void(StringRef Key, StringRef Value)>
46  Callback) override {
47  Results.forEachResult(Callback);
48  }
49 
50 private:
51  InMemoryToolResults Results;
52  std::mutex Mutex;
53 };
54 
55 } // namespace
56 
57 llvm::cl::opt<std::string>
58  Filter("filter",
59  llvm::cl::desc("Only process files that match this filter. "
60  "This flag only applies to all-TUs."),
61  llvm::cl::init(".*"));
62 
64  const CompilationDatabase &Compilations, unsigned ThreadCount,
65  std::shared_ptr<PCHContainerOperations> PCHContainerOps)
66  : Compilations(Compilations), Results(new ThreadSafeToolResults),
67  Context(Results.get()), ThreadCount(ThreadCount) {}
68 
70  CommonOptionsParser Options, unsigned ThreadCount,
71  std::shared_ptr<PCHContainerOperations> PCHContainerOps)
72  : OptionsParser(std::move(Options)),
73  Compilations(OptionsParser->getCompilations()),
74  Results(new ThreadSafeToolResults), Context(Results.get()),
75  ThreadCount(ThreadCount) {}
76 
79  std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
80  Actions) {
81  if (Actions.empty())
82  return make_string_error("No action to execute.");
83 
84  if (Actions.size() != 1)
85  return make_string_error(
86  "Only support executing exactly 1 action at this point.");
87 
88  std::string ErrorMsg;
89  std::mutex TUMutex;
90  auto AppendError = [&](llvm::Twine Err) {
91  std::unique_lock<std::mutex> LockGuard(TUMutex);
92  ErrorMsg += Err.str();
93  };
94 
95  auto Log = [&](llvm::Twine Msg) {
96  std::unique_lock<std::mutex> LockGuard(TUMutex);
97  llvm::errs() << Msg.str() << "\n";
98  };
99 
100  std::vector<std::string> Files;
101  llvm::Regex RegexFilter(Filter);
102  for (const auto& File : Compilations.getAllFiles()) {
103  if (RegexFilter.match(File))
104  Files.push_back(File);
105  }
106  // Add a counter to track the progress.
107  const std::string TotalNumStr = std::to_string(Files.size());
108  unsigned Counter = 0;
109  auto Count = [&]() {
110  std::unique_lock<std::mutex> LockGuard(TUMutex);
111  return ++Counter;
112  };
113 
114  auto &Action = Actions.front();
115 
116  {
117  llvm::ThreadPool Pool(ThreadCount == 0 ? llvm::hardware_concurrency()
118  : ThreadCount);
119  for (std::string File : Files) {
120  Pool.async(
121  [&](std::string Path) {
122  Log("[" + std::to_string(Count()) + "/" + TotalNumStr +
123  "] Processing file " + Path);
124  // Each thread gets an indepent copy of a VFS to allow different
125  // concurrent working directories.
127  llvm::vfs::createPhysicalFileSystem().release();
128  ClangTool Tool(Compilations, {Path},
129  std::make_shared<PCHContainerOperations>(), FS);
130  Tool.appendArgumentsAdjuster(Action.second);
132  for (const auto &FileAndContent : OverlayFiles)
133  Tool.mapVirtualFile(FileAndContent.first(),
134  FileAndContent.second);
135  if (Tool.run(Action.first.get()))
136  AppendError(llvm::Twine("Failed to run action on ") + Path +
137  "\n");
138  },
139  File);
140  }
141  // Make sure all tasks have finished before resetting the working directory.
142  Pool.wait();
143  }
144 
145  if (!ErrorMsg.empty())
146  return make_string_error(ErrorMsg);
147 
148  return llvm::Error::success();
149 }
150 
151 llvm::cl::opt<unsigned> ExecutorConcurrency(
152  "execute-concurrency",
153  llvm::cl::desc("The number of threads used to process all files in "
154  "parallel. Set to 0 for hardware concurrency. "
155  "This flag only applies to all-TUs."),
156  llvm::cl::init(0));
157 
159 public:
161  create(CommonOptionsParser &OptionsParser) override {
162  if (OptionsParser.getSourcePathList().empty())
163  return make_string_error(
164  "[AllTUsToolExecutorPlugin] Please provide a directory/file path in "
165  "the compilation database.");
166  return std::make_unique<AllTUsToolExecutor>(std::move(OptionsParser),
168  }
169 };
170 
171 static ToolExecutorPluginRegistry::Add<AllTUsToolExecutorPlugin>
172  X("all-TUs", "Runs FrontendActions on all TUs in the compilation database. "
173  "Tool results are stored in memory.");
174 
175 // This anchor is used to force the linker to link in the generated object file
176 // and thus register the plugin.
178 
179 } // end namespace tooling
180 } // 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:303
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:2392
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.
int run(ToolAction *Action)
Runs an action over all files specified in the command line.
Definition: Tooling.cpp:448
void mapVirtualFile(StringRef FilePath, StringRef Content)
Map a virtual file to be used while running the tool.
Definition: Tooling.cpp:424
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:151
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:428
const std::vector< std::string > & getSourcePathList() const
Returns a list of source file paths to process.
static ArgumentsAdjuster getDefaultArgumentsAdjusters()
llvm::cl::opt< unsigned > ExecutorConcurrency