clang 20.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
IndirectLocalPath & Path
#define X(type, name)
Definition: Value.h:144
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:311
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.
virtual std::vector< std::string > getAllFiles() const
Returns the list of all files available in the compilation database.
Interface for factories that create specific executors.
Definition: Execution.h:151
volatile int AllTUsToolExecutorAnchorSource
ArgumentsAdjuster getClangSyntaxOnlyAdjuster()
Gets an argument adjuster that converts input command line arguments to the "syntax check only" varia...
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.
std::function< CommandLineArguments(const CommandLineArguments &, StringRef Filename)> ArgumentsAdjuster
A prototype of a command line adjuster.
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.