xref: /llvm-project/clang/lib/Tooling/AllTUsExecution.cpp (revision 716042a63f26cd020eb72960f72fa97b9a197382)
1e25f3676SEric Liu //===- lib/Tooling/AllTUsExecution.cpp - Execute actions on all TUs. ------===//
2e25f3676SEric Liu //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e25f3676SEric Liu //
7e25f3676SEric Liu //===----------------------------------------------------------------------===//
8e25f3676SEric Liu 
9e25f3676SEric Liu #include "clang/Tooling/AllTUsExecution.h"
10e25f3676SEric Liu #include "clang/Tooling/ToolExecutorPluginRegistry.h"
11d7c5037eSReid Kleckner #include "llvm/Support/Regex.h"
12e25f3676SEric Liu #include "llvm/Support/ThreadPool.h"
13d7c5037eSReid Kleckner #include "llvm/Support/Threading.h"
1491e5cdfcSIlya Biryukov #include "llvm/Support/VirtualFileSystem.h"
15e25f3676SEric Liu 
16e25f3676SEric Liu namespace clang {
17e25f3676SEric Liu namespace tooling {
18e25f3676SEric Liu 
19e25f3676SEric Liu const char *AllTUsToolExecutor::ExecutorName = "AllTUsToolExecutor";
20e25f3676SEric Liu 
21e25f3676SEric Liu namespace {
make_string_error(const llvm::Twine & Message)22e25f3676SEric Liu llvm::Error make_string_error(const llvm::Twine &Message) {
23e25f3676SEric Liu   return llvm::make_error<llvm::StringError>(Message,
24e25f3676SEric Liu                                              llvm::inconvertibleErrorCode());
25e25f3676SEric Liu }
26e25f3676SEric Liu 
getDefaultArgumentsAdjusters()27e25f3676SEric Liu ArgumentsAdjuster getDefaultArgumentsAdjusters() {
28e25f3676SEric Liu   return combineAdjusters(
29e25f3676SEric Liu       getClangStripOutputAdjuster(),
30e25f3676SEric Liu       combineAdjusters(getClangSyntaxOnlyAdjuster(),
31e25f3676SEric Liu                        getClangStripDependencyFileAdjuster()));
32e25f3676SEric Liu }
33e25f3676SEric Liu 
34e25f3676SEric Liu class ThreadSafeToolResults : public ToolResults {
35e25f3676SEric Liu public:
addResult(StringRef Key,StringRef Value)36e25f3676SEric Liu   void addResult(StringRef Key, StringRef Value) override {
37e25f3676SEric Liu     std::unique_lock<std::mutex> LockGuard(Mutex);
386828ee3cSEric Liu     Results.addResult(Key, Value);
39e25f3676SEric Liu   }
40e25f3676SEric Liu 
419f36c7e7SHaojian Wu   std::vector<std::pair<llvm::StringRef, llvm::StringRef>>
AllKVResults()429f36c7e7SHaojian Wu   AllKVResults() override {
436828ee3cSEric Liu     return Results.AllKVResults();
44e25f3676SEric Liu   }
45e25f3676SEric Liu 
forEachResult(llvm::function_ref<void (StringRef Key,StringRef Value)> Callback)46e25f3676SEric Liu   void forEachResult(llvm::function_ref<void(StringRef Key, StringRef Value)>
47e25f3676SEric Liu                          Callback) override {
486828ee3cSEric Liu     Results.forEachResult(Callback);
49e25f3676SEric Liu   }
50e25f3676SEric Liu 
51e25f3676SEric Liu private:
526828ee3cSEric Liu   InMemoryToolResults Results;
53e25f3676SEric Liu   std::mutex Mutex;
54e25f3676SEric Liu };
55e25f3676SEric Liu 
56e25f3676SEric Liu } // namespace
57e25f3676SEric Liu 
58cd5e59f5SHaojian Wu llvm::cl::opt<std::string>
59cd5e59f5SHaojian Wu     Filter("filter",
60cd5e59f5SHaojian Wu            llvm::cl::desc("Only process files that match this filter. "
61cd5e59f5SHaojian Wu                           "This flag only applies to all-TUs."),
62cd5e59f5SHaojian Wu            llvm::cl::init(".*"));
63cd5e59f5SHaojian Wu 
AllTUsToolExecutor(const CompilationDatabase & Compilations,unsigned ThreadCount,std::shared_ptr<PCHContainerOperations> PCHContainerOps)64e25f3676SEric Liu AllTUsToolExecutor::AllTUsToolExecutor(
65e25f3676SEric Liu     const CompilationDatabase &Compilations, unsigned ThreadCount,
66e25f3676SEric Liu     std::shared_ptr<PCHContainerOperations> PCHContainerOps)
67e25f3676SEric Liu     : Compilations(Compilations), Results(new ThreadSafeToolResults),
68e25f3676SEric Liu       Context(Results.get()), ThreadCount(ThreadCount) {}
69e25f3676SEric Liu 
AllTUsToolExecutor(CommonOptionsParser Options,unsigned ThreadCount,std::shared_ptr<PCHContainerOperations> PCHContainerOps)70e25f3676SEric Liu AllTUsToolExecutor::AllTUsToolExecutor(
71e25f3676SEric Liu     CommonOptionsParser Options, unsigned ThreadCount,
72e25f3676SEric Liu     std::shared_ptr<PCHContainerOperations> PCHContainerOps)
73e25f3676SEric Liu     : OptionsParser(std::move(Options)),
74e25f3676SEric Liu       Compilations(OptionsParser->getCompilations()),
75e25f3676SEric Liu       Results(new ThreadSafeToolResults), Context(Results.get()),
76e25f3676SEric Liu       ThreadCount(ThreadCount) {}
77e25f3676SEric Liu 
execute(llvm::ArrayRef<std::pair<std::unique_ptr<FrontendActionFactory>,ArgumentsAdjuster>> Actions)78e25f3676SEric Liu llvm::Error AllTUsToolExecutor::execute(
79e25f3676SEric Liu     llvm::ArrayRef<
80e25f3676SEric Liu         std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
81e25f3676SEric Liu         Actions) {
82e25f3676SEric Liu   if (Actions.empty())
83e25f3676SEric Liu     return make_string_error("No action to execute.");
84e25f3676SEric Liu 
85e25f3676SEric Liu   if (Actions.size() != 1)
86e25f3676SEric Liu     return make_string_error(
87e25f3676SEric Liu         "Only support executing exactly 1 action at this point.");
88e25f3676SEric Liu 
89e25f3676SEric Liu   std::string ErrorMsg;
90e25f3676SEric Liu   std::mutex TUMutex;
91e25f3676SEric Liu   auto AppendError = [&](llvm::Twine Err) {
92e25f3676SEric Liu     std::unique_lock<std::mutex> LockGuard(TUMutex);
93e25f3676SEric Liu     ErrorMsg += Err.str();
94e25f3676SEric Liu   };
95e25f3676SEric Liu 
96e25f3676SEric Liu   auto Log = [&](llvm::Twine Msg) {
97e25f3676SEric Liu     std::unique_lock<std::mutex> LockGuard(TUMutex);
98e25f3676SEric Liu     llvm::errs() << Msg.str() << "\n";
99e25f3676SEric Liu   };
100e25f3676SEric Liu 
10163ecf073SHaojian Wu   std::vector<std::string> Files;
10263ecf073SHaojian Wu   llvm::Regex RegexFilter(Filter);
10363ecf073SHaojian Wu   for (const auto& File : Compilations.getAllFiles()) {
10463ecf073SHaojian Wu     if (RegexFilter.match(File))
10563ecf073SHaojian Wu       Files.push_back(File);
10663ecf073SHaojian Wu   }
107e25f3676SEric Liu   // Add a counter to track the progress.
108e25f3676SEric Liu   const std::string TotalNumStr = std::to_string(Files.size());
109e25f3676SEric Liu   unsigned Counter = 0;
110e25f3676SEric Liu   auto Count = [&]() {
111e25f3676SEric Liu     std::unique_lock<std::mutex> LockGuard(TUMutex);
112e25f3676SEric Liu     return ++Counter;
113e25f3676SEric Liu   };
114e25f3676SEric Liu 
115e25f3676SEric Liu   auto &Action = Actions.front();
116e25f3676SEric Liu 
117e25f3676SEric Liu   {
118*716042a6SMehdi Amini     llvm::DefaultThreadPool Pool(llvm::hardware_concurrency(ThreadCount));
119e25f3676SEric Liu     for (std::string File : Files) {
120e25f3676SEric Liu       Pool.async(
121e25f3676SEric Liu           [&](std::string Path) {
122e25f3676SEric Liu             Log("[" + std::to_string(Count()) + "/" + TotalNumStr +
123e25f3676SEric Liu                 "] Processing file " + Path);
1245674a3c8SGabriel Ravier             // Each thread gets an independent copy of a VFS to allow different
12591e5cdfcSIlya Biryukov             // concurrent working directories.
12691e5cdfcSIlya Biryukov             IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
1275207f19dSDuncan P. N. Exon Smith                 llvm::vfs::createPhysicalFileSystem();
12891e5cdfcSIlya Biryukov             ClangTool Tool(Compilations, {Path},
12991e5cdfcSIlya Biryukov                            std::make_shared<PCHContainerOperations>(), FS);
130e25f3676SEric Liu             Tool.appendArgumentsAdjuster(Action.second);
131e25f3676SEric Liu             Tool.appendArgumentsAdjuster(getDefaultArgumentsAdjusters());
132e25f3676SEric Liu             for (const auto &FileAndContent : OverlayFiles)
133e25f3676SEric Liu               Tool.mapVirtualFile(FileAndContent.first(),
134e25f3676SEric Liu                                   FileAndContent.second);
135e25f3676SEric Liu             if (Tool.run(Action.first.get()))
136e25f3676SEric Liu               AppendError(llvm::Twine("Failed to run action on ") + Path +
137e25f3676SEric Liu                           "\n");
138e25f3676SEric Liu           },
139e25f3676SEric Liu           File);
140e25f3676SEric Liu     }
14168576926SEric Liu     // Make sure all tasks have finished before resetting the working directory.
14268576926SEric Liu     Pool.wait();
143e25f3676SEric Liu   }
144e25f3676SEric Liu 
145e25f3676SEric Liu   if (!ErrorMsg.empty())
146e25f3676SEric Liu     return make_string_error(ErrorMsg);
147e25f3676SEric Liu 
148e25f3676SEric Liu   return llvm::Error::success();
149e25f3676SEric Liu }
150e25f3676SEric Liu 
151ba55970cSDiego Astiazaran llvm::cl::opt<unsigned> ExecutorConcurrency(
152e25f3676SEric Liu     "execute-concurrency",
153e25f3676SEric Liu     llvm::cl::desc("The number of threads used to process all files in "
154cd5e59f5SHaojian Wu                    "parallel. Set to 0 for hardware concurrency. "
155cd5e59f5SHaojian Wu                    "This flag only applies to all-TUs."),
156e25f3676SEric Liu     llvm::cl::init(0));
157e25f3676SEric Liu 
158e25f3676SEric Liu class AllTUsToolExecutorPlugin : public ToolExecutorPlugin {
159e25f3676SEric Liu public:
160e25f3676SEric Liu   llvm::Expected<std::unique_ptr<ToolExecutor>>
create(CommonOptionsParser & OptionsParser)161e25f3676SEric Liu   create(CommonOptionsParser &OptionsParser) override {
162e25f3676SEric Liu     if (OptionsParser.getSourcePathList().empty())
163e25f3676SEric Liu       return make_string_error(
164e25f3676SEric Liu           "[AllTUsToolExecutorPlugin] Please provide a directory/file path in "
165e25f3676SEric Liu           "the compilation database.");
1662b3d49b6SJonas Devlieghere     return std::make_unique<AllTUsToolExecutor>(std::move(OptionsParser),
167e25f3676SEric Liu                                                  ExecutorConcurrency);
168e25f3676SEric Liu   }
169e25f3676SEric Liu };
170e25f3676SEric Liu 
171e25f3676SEric Liu static ToolExecutorPluginRegistry::Add<AllTUsToolExecutorPlugin>
1726828ee3cSEric Liu     X("all-TUs", "Runs FrontendActions on all TUs in the compilation database. "
1736828ee3cSEric Liu                  "Tool results are stored in memory.");
174e25f3676SEric Liu 
175e25f3676SEric Liu // This anchor is used to force the linker to link in the generated object file
176e25f3676SEric Liu // and thus register the plugin.
177e25f3676SEric Liu volatile int AllTUsToolExecutorAnchorSource = 0;
178e25f3676SEric Liu 
179e25f3676SEric Liu } // end namespace tooling
180e25f3676SEric Liu } // end namespace clang
181