clang 22.0.0git
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/Regex.h"
12#include "llvm/Support/ThreadPool.h"
13#include "llvm/Support/Threading.h"
14#include "llvm/Support/VirtualFileSystem.h"
15
16namespace clang {
17namespace tooling {
18
19const char *AllTUsToolExecutor::ExecutorName = "AllTUsToolExecutor";
20
21namespace {
22llvm::Error make_string_error(const llvm::Twine &Message) {
23 return llvm::make_error<llvm::StringError>(Message,
24 llvm::inconvertibleErrorCode());
25}
26
28 return combineAdjusters(
32}
33
34class ThreadSafeToolResults : public ToolResults {
35public:
36 void addResult(StringRef Key, StringRef Value) override {
37 std::unique_lock<std::mutex> LockGuard(Mutex);
38 Results.addResult(Key, Value);
39 }
40
41 std::vector<std::pair<llvm::StringRef, llvm::StringRef>>
42 AllKVResults() override {
43 return Results.AllKVResults();
44 }
45
46 void forEachResult(llvm::function_ref<void(StringRef Key, StringRef Value)>
47 Callback) override {
48 Results.forEachResult(Callback);
49 }
50
51private:
52 InMemoryToolResults Results;
53 std::mutex Mutex;
54};
55
56} // namespace
57
58llvm::cl::opt<std::string>
59 Filter("filter",
60 llvm::cl::desc("Only process files that match this filter. "
61 "This flag only applies to all-TUs."),
62 llvm::cl::init(".*"));
63
65 const CompilationDatabase &Compilations, unsigned ThreadCount,
66 std::shared_ptr<PCHContainerOperations> PCHContainerOps)
67 : Compilations(Compilations), Results(new ThreadSafeToolResults),
68 Context(Results.get()), ThreadCount(ThreadCount) {}
69
71 CommonOptionsParser Options, unsigned ThreadCount,
72 std::shared_ptr<PCHContainerOperations> PCHContainerOps)
73 : OptionsParser(std::move(Options)),
74 Compilations(OptionsParser->getCompilations()),
75 Results(new ThreadSafeToolResults), Context(Results.get()),
76 ThreadCount(ThreadCount) {}
77
80 std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
81 Actions) {
82 if (Actions.empty())
83 return make_string_error("No action to execute.");
84
85 if (Actions.size() != 1)
86 return make_string_error(
87 "Only support executing exactly 1 action at this point.");
88
89 std::string ErrorMsg;
90 std::mutex TUMutex;
91 auto AppendError = [&](llvm::Twine Err) {
92 std::unique_lock<std::mutex> LockGuard(TUMutex);
93 ErrorMsg += Err.str();
94 };
95
96 auto Log = [&](llvm::Twine Msg) {
97 std::unique_lock<std::mutex> LockGuard(TUMutex);
98 llvm::errs() << Msg.str() << "\n";
99 };
100
101 std::vector<std::string> Files;
102 llvm::Regex RegexFilter(Filter);
103 for (const auto& File : Compilations.getAllFiles()) {
104 if (RegexFilter.match(File))
105 Files.push_back(File);
106 }
107 // Add a counter to track the progress.
108 const std::string TotalNumStr = std::to_string(Files.size());
109 unsigned Counter = 0;
110 auto Count = [&]() {
111 std::unique_lock<std::mutex> LockGuard(TUMutex);
112 return ++Counter;
113 };
114
115 auto &Action = Actions.front();
116
117 {
118 llvm::DefaultThreadPool Pool(llvm::hardware_concurrency(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 independent copy of a VFS to allow different
125 // concurrent working directories.
127 llvm::vfs::createPhysicalFileSystem();
128 ClangTool Tool(Compilations, {Path},
129 std::make_shared<PCHContainerOperations>(), FS);
130 Tool.appendArgumentsAdjuster(Action.second);
131 Tool.appendArgumentsAdjuster(getDefaultArgumentsAdjusters());
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
151llvm::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
159public:
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
171static 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
#define X(type, name)
Definition Value.h:97
llvm::Expected< std::unique_ptr< ToolExecutor > > create(CommonOptionsParser &OptionsParser) override
Create an ToolExecutor.
AllTUsToolExecutor(const CompilationDatabase &Compilations, unsigned ThreadCount, std::shared_ptr< PCHContainerOperations > PCHContainerOps=std::make_shared< PCHContainerOperations >())
Init with CompilationDatabase.
llvm::Error execute(llvm::ArrayRef< std::pair< std::unique_ptr< FrontendActionFactory >, ArgumentsAdjuster > > Actions) override
Executes each action with a corresponding arguments adjuster.
Utility to run a FrontendAction over a set of files.
Definition Tooling.h:319
void appendArgumentsAdjuster(ArgumentsAdjuster Adjuster)
Append a command line arguments adjuster to the adjuster chain.
Definition Tooling.cpp:498
A parser for options common to all command-line Clang tools.
const std::vector< std::string > & getSourcePathList() const
Returns a list of source file paths to process.
Interface for compilation databases.
Interface for factories that create specific executors.
Definition Execution.h:151
An abstraction for the result of a tool execution.
Definition Execution.h:46
volatile int AllTUsToolExecutorAnchorSource
ArgumentsAdjuster getClangSyntaxOnlyAdjuster()
Gets an argument adjuster that converts input command line arguments to the "syntax check only" varia...
std::function< CommandLineArguments( const CommandLineArguments &, StringRef Filename)> ArgumentsAdjuster
A prototype of a command line adjuster.
static ArgumentsAdjuster getDefaultArgumentsAdjusters()
ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First, ArgumentsAdjuster Second)
Gets an argument adjuster which adjusts the arguments in sequence with the First adjuster and then wi...
llvm::cl::opt< unsigned > ExecutorConcurrency
ArgumentsAdjuster getClangStripDependencyFileAdjuster()
Gets an argument adjuster which removes dependency-file related command line arguments.
llvm::cl::opt< std::string > Filter
static llvm::Error make_string_error(const llvm::Twine &Message)
ArgumentsAdjuster getClangStripOutputAdjuster()
Gets an argument adjuster which removes output-related command line arguments.
The JSON file list parser is used to communicate input to InstallAPI.