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/Regex.h"
 | |
| #include "llvm/Support/ThreadPool.h"
 | |
| #include "llvm/Support/Threading.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(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
 |