Path: blob/main/contrib/llvm-project/clang/lib/Tooling/AllTUsExecution.cpp
35234 views
//===- lib/Tooling/AllTUsExecution.cpp - Execute actions on all TUs. ------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/Tooling/AllTUsExecution.h"9#include "clang/Tooling/ToolExecutorPluginRegistry.h"10#include "llvm/Support/Regex.h"11#include "llvm/Support/ThreadPool.h"12#include "llvm/Support/Threading.h"13#include "llvm/Support/VirtualFileSystem.h"1415namespace clang {16namespace tooling {1718const char *AllTUsToolExecutor::ExecutorName = "AllTUsToolExecutor";1920namespace {21llvm::Error make_string_error(const llvm::Twine &Message) {22return llvm::make_error<llvm::StringError>(Message,23llvm::inconvertibleErrorCode());24}2526ArgumentsAdjuster getDefaultArgumentsAdjusters() {27return combineAdjusters(28getClangStripOutputAdjuster(),29combineAdjusters(getClangSyntaxOnlyAdjuster(),30getClangStripDependencyFileAdjuster()));31}3233class ThreadSafeToolResults : public ToolResults {34public:35void addResult(StringRef Key, StringRef Value) override {36std::unique_lock<std::mutex> LockGuard(Mutex);37Results.addResult(Key, Value);38}3940std::vector<std::pair<llvm::StringRef, llvm::StringRef>>41AllKVResults() override {42return Results.AllKVResults();43}4445void forEachResult(llvm::function_ref<void(StringRef Key, StringRef Value)>46Callback) override {47Results.forEachResult(Callback);48}4950private:51InMemoryToolResults Results;52std::mutex Mutex;53};5455} // namespace5657llvm::cl::opt<std::string>58Filter("filter",59llvm::cl::desc("Only process files that match this filter. "60"This flag only applies to all-TUs."),61llvm::cl::init(".*"));6263AllTUsToolExecutor::AllTUsToolExecutor(64const CompilationDatabase &Compilations, unsigned ThreadCount,65std::shared_ptr<PCHContainerOperations> PCHContainerOps)66: Compilations(Compilations), Results(new ThreadSafeToolResults),67Context(Results.get()), ThreadCount(ThreadCount) {}6869AllTUsToolExecutor::AllTUsToolExecutor(70CommonOptionsParser Options, unsigned ThreadCount,71std::shared_ptr<PCHContainerOperations> PCHContainerOps)72: OptionsParser(std::move(Options)),73Compilations(OptionsParser->getCompilations()),74Results(new ThreadSafeToolResults), Context(Results.get()),75ThreadCount(ThreadCount) {}7677llvm::Error AllTUsToolExecutor::execute(78llvm::ArrayRef<79std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>80Actions) {81if (Actions.empty())82return make_string_error("No action to execute.");8384if (Actions.size() != 1)85return make_string_error(86"Only support executing exactly 1 action at this point.");8788std::string ErrorMsg;89std::mutex TUMutex;90auto AppendError = [&](llvm::Twine Err) {91std::unique_lock<std::mutex> LockGuard(TUMutex);92ErrorMsg += Err.str();93};9495auto Log = [&](llvm::Twine Msg) {96std::unique_lock<std::mutex> LockGuard(TUMutex);97llvm::errs() << Msg.str() << "\n";98};99100std::vector<std::string> Files;101llvm::Regex RegexFilter(Filter);102for (const auto& File : Compilations.getAllFiles()) {103if (RegexFilter.match(File))104Files.push_back(File);105}106// Add a counter to track the progress.107const std::string TotalNumStr = std::to_string(Files.size());108unsigned Counter = 0;109auto Count = [&]() {110std::unique_lock<std::mutex> LockGuard(TUMutex);111return ++Counter;112};113114auto &Action = Actions.front();115116{117llvm::DefaultThreadPool Pool(llvm::hardware_concurrency(ThreadCount));118for (std::string File : Files) {119Pool.async(120[&](std::string Path) {121Log("[" + std::to_string(Count()) + "/" + TotalNumStr +122"] Processing file " + Path);123// Each thread gets an independent copy of a VFS to allow different124// concurrent working directories.125IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =126llvm::vfs::createPhysicalFileSystem();127ClangTool Tool(Compilations, {Path},128std::make_shared<PCHContainerOperations>(), FS);129Tool.appendArgumentsAdjuster(Action.second);130Tool.appendArgumentsAdjuster(getDefaultArgumentsAdjusters());131for (const auto &FileAndContent : OverlayFiles)132Tool.mapVirtualFile(FileAndContent.first(),133FileAndContent.second);134if (Tool.run(Action.first.get()))135AppendError(llvm::Twine("Failed to run action on ") + Path +136"\n");137},138File);139}140// Make sure all tasks have finished before resetting the working directory.141Pool.wait();142}143144if (!ErrorMsg.empty())145return make_string_error(ErrorMsg);146147return llvm::Error::success();148}149150llvm::cl::opt<unsigned> ExecutorConcurrency(151"execute-concurrency",152llvm::cl::desc("The number of threads used to process all files in "153"parallel. Set to 0 for hardware concurrency. "154"This flag only applies to all-TUs."),155llvm::cl::init(0));156157class AllTUsToolExecutorPlugin : public ToolExecutorPlugin {158public:159llvm::Expected<std::unique_ptr<ToolExecutor>>160create(CommonOptionsParser &OptionsParser) override {161if (OptionsParser.getSourcePathList().empty())162return make_string_error(163"[AllTUsToolExecutorPlugin] Please provide a directory/file path in "164"the compilation database.");165return std::make_unique<AllTUsToolExecutor>(std::move(OptionsParser),166ExecutorConcurrency);167}168};169170static ToolExecutorPluginRegistry::Add<AllTUsToolExecutorPlugin>171X("all-TUs", "Runs FrontendActions on all TUs in the compilation database. "172"Tool results are stored in memory.");173174// This anchor is used to force the linker to link in the generated object file175// and thus register the plugin.176volatile int AllTUsToolExecutorAnchorSource = 0;177178} // end namespace tooling179} // end namespace clang180181182