Refactor DependencyScanningTool to its own file

Summary:
There's no behavior change - just moving DependencyScanningTool to its own file
since this tool can be reused across both clang-scan-deps binary and an interface
exposed as part of libClang APIs.

Reviewers: arphaman, jkorous, Bigcheese, dexonsmith

Subscribers: mgorny, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D69186

llvm-svn: 375483
This commit is contained in:
Kousik Kumar 2019-10-22 05:05:18 +00:00
parent 114de1eab2
commit fb042b094f
4 changed files with 147 additions and 98 deletions

View File

@ -0,0 +1,48 @@
//===- DependencyScanningTool.h - clang-scan-deps service ------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_TOOL_H
#define LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_TOOL_H
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
#include "clang/Tooling/JSONCompilationDatabase.h"
#include <string>
namespace clang{
namespace tooling{
namespace dependencies{
/// The high-level implementation of the dependency discovery tool that runs on
/// an individual worker thread.
class DependencyScanningTool {
public:
/// Construct a dependency scanning tool.
///
/// \param Compilations The reference to the compilation database that's
/// used by the clang tool.
DependencyScanningTool(DependencyScanningService &Service, const clang::tooling::CompilationDatabase &Compilations);
/// Print out the dependency information into a string using the dependency
/// file format that is specified in the options (-MD is the default) and
/// return it.
///
/// \returns A \c StringError with the diagnostic output if clang errors
/// occurred, dependency file contents otherwise.
llvm::Expected<std::string> getDependencyFile(const std::string &Input, StringRef CWD);
private:
DependencyScanningWorker Worker;
const tooling::CompilationDatabase &Compilations;
};
} // end namespace dependencies
} // end namespace tooling
} // end namespace clang
#endif // LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_TOOL_H

View File

@ -7,6 +7,7 @@ add_clang_library(clangDependencyScanning
DependencyScanningFilesystem.cpp
DependencyScanningService.cpp
DependencyScanningWorker.cpp
DependencyScanningTool.cpp
DEPENDS
ClangDriverOptions

View File

@ -0,0 +1,71 @@
//===- DependencyScanningTool.cpp - clang-scan-deps service ------------===//
//
// 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/DependencyScanning/DependencyScanningTool.h"
#include "clang/Frontend/Utils.h"
namespace clang{
namespace tooling{
namespace dependencies{
DependencyScanningTool::DependencyScanningTool(DependencyScanningService &Service,
const tooling::CompilationDatabase &Compilations) : Worker(Service), Compilations(Compilations) {}
llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(const std::string &Input,
StringRef CWD) {
/// Prints out all of the gathered dependencies into a string.
class DependencyPrinterConsumer : public DependencyConsumer {
public:
void handleFileDependency(const DependencyOutputOptions &Opts,
StringRef File) override {
if (!this->Opts)
this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
Dependencies.push_back(File);
}
void printDependencies(std::string &S) {
if (!Opts)
return;
class DependencyPrinter : public DependencyFileGenerator {
public:
DependencyPrinter(DependencyOutputOptions &Opts,
ArrayRef<std::string> Dependencies)
: DependencyFileGenerator(Opts) {
for (const auto &Dep : Dependencies)
addDependency(Dep);
}
void printDependencies(std::string &S) {
llvm::raw_string_ostream OS(S);
outputDependencyFile(OS);
}
};
DependencyPrinter Generator(*Opts, Dependencies);
Generator.printDependencies(S);
}
private:
std::unique_ptr<DependencyOutputOptions> Opts;
std::vector<std::string> Dependencies;
};
DependencyPrinterConsumer Consumer;
auto Result =
Worker.computeDependencies(Input, CWD, Compilations, Consumer);
if (Result)
return std::move(Result);
std::string Output;
Consumer.printDependencies(Output);
return Output;
}
} // end namespace dependencies
} // end namespace tooling
} // end namespace clang

View File

@ -9,6 +9,7 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
#include "clang/Tooling/JSONCompilationDatabase.h"
#include "llvm/Support/InitLLVM.h"
@ -38,101 +39,6 @@ private:
raw_ostream &OS;
};
/// The high-level implementation of the dependency discovery tool that runs on
/// an individual worker thread.
class DependencyScanningTool {
public:
/// Construct a dependency scanning tool.
///
/// \param Compilations The reference to the compilation database that's
/// used by the clang tool.
DependencyScanningTool(DependencyScanningService &Service,
const tooling::CompilationDatabase &Compilations,
SharedStream &OS, SharedStream &Errs)
: Worker(Service), Compilations(Compilations), OS(OS), Errs(Errs) {}
/// Print out the dependency information into a string using the dependency
/// file format that is specified in the options (-MD is the default) and
/// return it.
///
/// \returns A \c StringError with the diagnostic output if clang errors
/// occurred, dependency file contents otherwise.
llvm::Expected<std::string> getDependencyFile(const std::string &Input,
StringRef CWD) {
/// Prints out all of the gathered dependencies into a string.
class DependencyPrinterConsumer : public DependencyConsumer {
public:
void handleFileDependency(const DependencyOutputOptions &Opts,
StringRef File) override {
if (!this->Opts)
this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
Dependencies.push_back(File);
}
void printDependencies(std::string &S) {
if (!Opts)
return;
class DependencyPrinter : public DependencyFileGenerator {
public:
DependencyPrinter(DependencyOutputOptions &Opts,
ArrayRef<std::string> Dependencies)
: DependencyFileGenerator(Opts) {
for (const auto &Dep : Dependencies)
addDependency(Dep);
}
void printDependencies(std::string &S) {
llvm::raw_string_ostream OS(S);
outputDependencyFile(OS);
}
};
DependencyPrinter Generator(*Opts, Dependencies);
Generator.printDependencies(S);
}
private:
std::unique_ptr<DependencyOutputOptions> Opts;
std::vector<std::string> Dependencies;
};
DependencyPrinterConsumer Consumer;
auto Result =
Worker.computeDependencies(Input, CWD, Compilations, Consumer);
if (Result)
return std::move(Result);
std::string Output;
Consumer.printDependencies(Output);
return Output;
}
/// Computes the dependencies for the given file and prints them out.
///
/// \returns True on error.
bool runOnFile(const std::string &Input, StringRef CWD) {
auto MaybeFile = getDependencyFile(Input, CWD);
if (!MaybeFile) {
llvm::handleAllErrors(
MaybeFile.takeError(), [this, &Input](llvm::StringError &Err) {
Errs.applyLocked([&](raw_ostream &OS) {
OS << "Error while scanning dependencies for " << Input << ":\n";
OS << Err.getMessage();
});
});
return true;
}
OS.applyLocked([&](raw_ostream &OS) { OS << *MaybeFile; });
return false;
}
private:
DependencyScanningWorker Worker;
const tooling::CompilationDatabase &Compilations;
SharedStream &OS;
SharedStream &Errs;
};
llvm::cl::opt<bool> Help("h", llvm::cl::desc("Alias for -help"),
llvm::cl::Hidden);
@ -191,6 +97,27 @@ static std::string getObjFilePath(StringRef SrcFile) {
return ObjFileName.str();
}
/// Takes the result of a dependency scan and prints error / dependency files
/// based on the result.
///
/// \returns True on error.
static bool handleDependencyToolResult(const std::string &Input,
llvm::Expected<std::string> &MaybeFile,
SharedStream &OS, SharedStream &Errs) {
if (!MaybeFile) {
llvm::handleAllErrors(
MaybeFile.takeError(), [&Input, &Errs](llvm::StringError &Err) {
Errs.applyLocked([&](raw_ostream &OS) {
OS << "Error while scanning dependencies for " << Input << ":\n";
OS << Err.getMessage();
});
});
return true;
}
OS.applyLocked([&](raw_ostream &OS) { OS << *MaybeFile; });
return false;
}
int main(int argc, const char **argv) {
llvm::InitLLVM X(argc, argv);
llvm::cl::HideUnrelatedOptions(DependencyScannerCategory);
@ -284,7 +211,7 @@ int main(int argc, const char **argv) {
std::vector<std::unique_ptr<DependencyScanningTool>> WorkerTools;
for (unsigned I = 0; I < NumWorkers; ++I)
WorkerTools.push_back(std::make_unique<DependencyScanningTool>(
Service, *AdjustingCompilations, DependencyOS, Errs));
Service, *AdjustingCompilations));
std::vector<std::thread> WorkerThreads;
std::atomic<bool> HadErrors(false);
@ -296,7 +223,8 @@ int main(int argc, const char **argv) {
<< " files using " << NumWorkers << " workers\n";
}
for (unsigned I = 0; I < NumWorkers; ++I) {
auto Worker = [I, &Lock, &Index, &Inputs, &HadErrors, &WorkerTools]() {
auto Worker = [I, &Lock, &Index, &Inputs, &HadErrors, &WorkerTools,
&DependencyOS, &Errs]() {
while (true) {
std::string Input;
StringRef CWD;
@ -310,7 +238,8 @@ int main(int argc, const char **argv) {
CWD = Compilation.second;
}
// Run the tool on it.
if (WorkerTools[I]->runOnFile(Input, CWD))
auto MaybeFile = WorkerTools[I]->getDependencyFile(Input, CWD);
if (handleDependencyToolResult(Input, MaybeFile, DependencyOS, Errs))
HadErrors = true;
}
};