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 llvm::make_unique<AllTUsToolExecutor>(std::move(OptionsParser), ExecutorConcurrency); }
llvm::Expected<URI> URI::create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme) { if (!llvm::sys::path::is_absolute(AbsolutePath)) return make_string_error("Not a valid absolute path: " + AbsolutePath); auto S = findSchemeByName(Scheme); if (!S) return S.takeError(); return S->get()->uriFromAbsolutePath(AbsolutePath); }
llvm::Expected<URI> URI::create(llvm::StringRef AbsolutePath, const std::vector<std::string> &Schemes) { if (!llvm::sys::path::is_absolute(AbsolutePath)) return make_string_error("Not a valid absolute path: " + AbsolutePath); for (const auto &Scheme : Schemes) { auto URI = URI::create(AbsolutePath, Scheme); // For some paths, conversion to different URI schemes is impossible. These // should be just skipped. if (!URI) { // Ignore the error. llvm::consumeError(URI.takeError()); continue; } return URI; } return make_string_error( "Couldn't convert " + AbsolutePath + " to any given scheme: " + llvm::join(Schemes, ", ")); }
llvm::Expected<URI> URI::parse(llvm::StringRef OrigUri) { URI U; llvm::StringRef Uri = OrigUri; auto Pos = Uri.find(':'); if (Pos == 0 || Pos == llvm::StringRef::npos) return make_string_error("Scheme must be provided in URI: " + OrigUri); U.Scheme = percentDecode(Uri.substr(0, Pos)); Uri = Uri.substr(Pos + 1); if (Uri.consume_front("//")) { Pos = Uri.find('/'); U.Authority = percentDecode(Uri.substr(0, Pos)); Uri = Uri.substr(Pos); } U.Body = percentDecode(Uri); return U; }
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); llvm::SmallString<128> InitialWorkingDir; if (auto EC = llvm::sys::fs::current_path(InitialWorkingDir)) { InitialWorkingDir = ""; llvm::errs() << "Error while getting current working directory: " << EC.message() << "\n"; } for (std::string File : Files) { Pool.async( [&](std::string Path) { Log("[" + std::to_string(Count()) + "/" + TotalNumStr + "] Processing file " + Path); ClangTool Tool(Compilations, {Path}); Tool.appendArgumentsAdjuster(Action.second); Tool.appendArgumentsAdjuster(getDefaultArgumentsAdjusters()); for (const auto &FileAndContent : OverlayFiles) Tool.mapVirtualFile(FileAndContent.first(), FileAndContent.second); // Do not restore working dir from multiple threads to avoid races. Tool.setRestoreWorkingDir(false); 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 (!InitialWorkingDir.empty()) { if (auto EC = llvm::sys::fs::set_current_path(InitialWorkingDir)) llvm::errs() << "Error while restoring working directory: " << EC.message() << "\n"; } } if (!ErrorMsg.empty()) return make_string_error(ErrorMsg); return llvm::Error::success(); }