forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			181 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			181 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- lib/Tooling/AllTUsExecution.cpp - Execute actions on all TUs. ------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "clang/Tooling/AllTUsExecution.h"
 | 
						|
#include "clang/Tooling/ToolExecutorPluginRegistry.h"
 | 
						|
#include "llvm/Support/Threading.h"
 | 
						|
#include "llvm/Support/ThreadPool.h"
 | 
						|
#include "llvm/Support/VirtualFileSystem.h"
 | 
						|
 | 
						|
namespace clang {
 | 
						|
namespace tooling {
 | 
						|
 | 
						|
const char *AllTUsToolExecutor::ExecutorName = "AllTUsToolExecutor";
 | 
						|
 | 
						|
namespace {
 | 
						|
llvm::Error make_string_error(const llvm::Twine &Message) {
 | 
						|
  return llvm::make_error<llvm::StringError>(Message,
 | 
						|
                                             llvm::inconvertibleErrorCode());
 | 
						|
}
 | 
						|
 | 
						|
ArgumentsAdjuster getDefaultArgumentsAdjusters() {
 | 
						|
  return combineAdjusters(
 | 
						|
      getClangStripOutputAdjuster(),
 | 
						|
      combineAdjusters(getClangSyntaxOnlyAdjuster(),
 | 
						|
                       getClangStripDependencyFileAdjuster()));
 | 
						|
}
 | 
						|
 | 
						|
class ThreadSafeToolResults : public ToolResults {
 | 
						|
public:
 | 
						|
  void addResult(StringRef Key, StringRef Value) override {
 | 
						|
    std::unique_lock<std::mutex> LockGuard(Mutex);
 | 
						|
    Results.addResult(Key, Value);
 | 
						|
  }
 | 
						|
 | 
						|
  std::vector<std::pair<llvm::StringRef, llvm::StringRef>>
 | 
						|
  AllKVResults() override {
 | 
						|
    return Results.AllKVResults();
 | 
						|
  }
 | 
						|
 | 
						|
  void forEachResult(llvm::function_ref<void(StringRef Key, StringRef Value)>
 | 
						|
                         Callback) override {
 | 
						|
    Results.forEachResult(Callback);
 | 
						|
  }
 | 
						|
 | 
						|
private:
 | 
						|
  InMemoryToolResults Results;
 | 
						|
  std::mutex Mutex;
 | 
						|
};
 | 
						|
 | 
						|
} // namespace
 | 
						|
 | 
						|
llvm::cl::opt<std::string>
 | 
						|
    Filter("filter",
 | 
						|
           llvm::cl::desc("Only process files that match this filter. "
 | 
						|
                          "This flag only applies to all-TUs."),
 | 
						|
           llvm::cl::init(".*"));
 | 
						|
 | 
						|
AllTUsToolExecutor::AllTUsToolExecutor(
 | 
						|
    const CompilationDatabase &Compilations, unsigned ThreadCount,
 | 
						|
    std::shared_ptr<PCHContainerOperations> PCHContainerOps)
 | 
						|
    : Compilations(Compilations), Results(new ThreadSafeToolResults),
 | 
						|
      Context(Results.get()), ThreadCount(ThreadCount) {}
 | 
						|
 | 
						|
AllTUsToolExecutor::AllTUsToolExecutor(
 | 
						|
    CommonOptionsParser Options, unsigned ThreadCount,
 | 
						|
    std::shared_ptr<PCHContainerOperations> PCHContainerOps)
 | 
						|
    : OptionsParser(std::move(Options)),
 | 
						|
      Compilations(OptionsParser->getCompilations()),
 | 
						|
      Results(new ThreadSafeToolResults), Context(Results.get()),
 | 
						|
      ThreadCount(ThreadCount) {}
 | 
						|
 | 
						|
llvm::Error AllTUsToolExecutor::execute(
 | 
						|
    llvm::ArrayRef<
 | 
						|
        std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
 | 
						|
        Actions) {
 | 
						|
  if (Actions.empty())
 | 
						|
    return make_string_error("No action to execute.");
 | 
						|
 | 
						|
  if (Actions.size() != 1)
 | 
						|
    return make_string_error(
 | 
						|
        "Only support executing exactly 1 action at this point.");
 | 
						|
 | 
						|
  std::string ErrorMsg;
 | 
						|
  std::mutex TUMutex;
 | 
						|
  auto AppendError = [&](llvm::Twine Err) {
 | 
						|
    std::unique_lock<std::mutex> LockGuard(TUMutex);
 | 
						|
    ErrorMsg += Err.str();
 | 
						|
  };
 | 
						|
 | 
						|
  auto Log = [&](llvm::Twine Msg) {
 | 
						|
    std::unique_lock<std::mutex> LockGuard(TUMutex);
 | 
						|
    llvm::errs() << Msg.str() << "\n";
 | 
						|
  };
 | 
						|
 | 
						|
  std::vector<std::string> Files;
 | 
						|
  llvm::Regex RegexFilter(Filter);
 | 
						|
  for (const auto& File : Compilations.getAllFiles()) {
 | 
						|
    if (RegexFilter.match(File))
 | 
						|
      Files.push_back(File);
 | 
						|
  }
 | 
						|
  // Add a counter to track the progress.
 | 
						|
  const std::string TotalNumStr = std::to_string(Files.size());
 | 
						|
  unsigned Counter = 0;
 | 
						|
  auto Count = [&]() {
 | 
						|
    std::unique_lock<std::mutex> LockGuard(TUMutex);
 | 
						|
    return ++Counter;
 | 
						|
  };
 | 
						|
 | 
						|
  auto &Action = Actions.front();
 | 
						|
 | 
						|
  {
 | 
						|
    llvm::ThreadPool Pool(ThreadCount == 0 ? llvm::hardware_concurrency()
 | 
						|
                                           : ThreadCount);
 | 
						|
    for (std::string File : Files) {
 | 
						|
      Pool.async(
 | 
						|
          [&](std::string Path) {
 | 
						|
            Log("[" + std::to_string(Count()) + "/" + TotalNumStr +
 | 
						|
                "] Processing file " + Path);
 | 
						|
            // Each thread gets an indepent copy of a VFS to allow different
 | 
						|
            // concurrent working directories.
 | 
						|
            IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
 | 
						|
                llvm::vfs::createPhysicalFileSystem().release();
 | 
						|
            ClangTool Tool(Compilations, {Path},
 | 
						|
                           std::make_shared<PCHContainerOperations>(), FS);
 | 
						|
            Tool.appendArgumentsAdjuster(Action.second);
 | 
						|
            Tool.appendArgumentsAdjuster(getDefaultArgumentsAdjusters());
 | 
						|
            for (const auto &FileAndContent : OverlayFiles)
 | 
						|
              Tool.mapVirtualFile(FileAndContent.first(),
 | 
						|
                                  FileAndContent.second);
 | 
						|
            if (Tool.run(Action.first.get()))
 | 
						|
              AppendError(llvm::Twine("Failed to run action on ") + Path +
 | 
						|
                          "\n");
 | 
						|
          },
 | 
						|
          File);
 | 
						|
    }
 | 
						|
    // Make sure all tasks have finished before resetting the working directory.
 | 
						|
    Pool.wait();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ErrorMsg.empty())
 | 
						|
    return make_string_error(ErrorMsg);
 | 
						|
 | 
						|
  return llvm::Error::success();
 | 
						|
}
 | 
						|
 | 
						|
llvm::cl::opt<unsigned> ExecutorConcurrency(
 | 
						|
    "execute-concurrency",
 | 
						|
    llvm::cl::desc("The number of threads used to process all files in "
 | 
						|
                   "parallel. Set to 0 for hardware concurrency. "
 | 
						|
                   "This flag only applies to all-TUs."),
 | 
						|
    llvm::cl::init(0));
 | 
						|
 | 
						|
class AllTUsToolExecutorPlugin : public ToolExecutorPlugin {
 | 
						|
public:
 | 
						|
  llvm::Expected<std::unique_ptr<ToolExecutor>>
 | 
						|
  create(CommonOptionsParser &OptionsParser) override {
 | 
						|
    if (OptionsParser.getSourcePathList().empty())
 | 
						|
      return make_string_error(
 | 
						|
          "[AllTUsToolExecutorPlugin] Please provide a directory/file path in "
 | 
						|
          "the compilation database.");
 | 
						|
    return std::make_unique<AllTUsToolExecutor>(std::move(OptionsParser),
 | 
						|
                                                 ExecutorConcurrency);
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
static ToolExecutorPluginRegistry::Add<AllTUsToolExecutorPlugin>
 | 
						|
    X("all-TUs", "Runs FrontendActions on all TUs in the compilation database. "
 | 
						|
                 "Tool results are stored in memory.");
 | 
						|
 | 
						|
// This anchor is used to force the linker to link in the generated object file
 | 
						|
// and thus register the plugin.
 | 
						|
volatile int AllTUsToolExecutorAnchorSource = 0;
 | 
						|
 | 
						|
} // end namespace tooling
 | 
						|
} // end namespace clang
 |