brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.2 KiB · 9cad868 Raw
181 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Tooling/AllTUsExecution.h"10#include "clang/Tooling/ToolExecutorPluginRegistry.h"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 27ArgumentsAdjuster getDefaultArgumentsAdjusters() {28  return combineAdjusters(29      getClangStripOutputAdjuster(),30      combineAdjusters(getClangSyntaxOnlyAdjuster(),31                       getClangStripDependencyFileAdjuster()));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} // namespace57 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 64AllTUsToolExecutor::AllTUsToolExecutor(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 70AllTUsToolExecutor::AllTUsToolExecutor(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 78llvm::Error AllTUsToolExecutor::execute(79    llvm::ArrayRef<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 different125            // concurrent working directories.126            IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =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 158class AllTUsToolExecutorPlugin : public ToolExecutorPlugin {159public:160  llvm::Expected<std::unique_ptr<ToolExecutor>>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),167                                                 ExecutorConcurrency);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 file176// and thus register the plugin.177volatile int AllTUsToolExecutorAnchorSource = 0;178 179} // end namespace tooling180} // end namespace clang181