[clang-scan-deps] NFC, refactor the DependencyScanningWorker to use a consumer
authorAlex Lorenz <arphaman@gmail.com>
Fri, 30 Aug 2019 01:25:57 +0000 (01:25 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Fri, 30 Aug 2019 01:25:57 +0000 (01:25 +0000)
to report the dependencies to the client

This will allow the scanner to report modular dependencies to the consumer.
This will also allow the scanner to accept regular cc1 clang invocations, e.g.
in an implementation of a libclang C API for clang-scan-deps, that I will add
follow-up patches for in the future.

llvm-svn: 370425

clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
clang/tools/clang-scan-deps/ClangScanDeps.cpp

index d56f5395da167e213310900fced4f9b4c8ee7212..5b42741ecb61b31721cc36b2921499411d122171 100644 (file)
 #include <string>
 
 namespace clang {
+
+class DependencyOutputOptions;
+
 namespace tooling {
 namespace dependencies {
 
 class DependencyScanningService;
 class DependencyScanningWorkerFilesystem;
 
+class DependencyConsumer {
+public:
+  virtual ~DependencyConsumer() {}
+
+  virtual void handleFileDependency(const DependencyOutputOptions &Opts,
+                                    StringRef Filename) = 0;
+
+  // FIXME: Add support for reporting modular dependencies.
+};
+
 /// An individual dependency scanning worker that is able to run on its own
 /// thread.
 ///
@@ -35,15 +48,16 @@ class DependencyScanningWorker {
 public:
   DependencyScanningWorker(DependencyScanningService &Service);
 
-  /// 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.
+  /// Run the dependency scanning tool for a given clang driver invocation (as
+  /// specified for the given Input in the CDB), and report the discovered
+  /// dependencies to the provided consumer.
   ///
   /// \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 WorkingDirectory,
-                                                const CompilationDatabase &CDB);
+  /// occurred, success otherwise.
+  llvm::Error computeDependencies(const std::string &Input,
+                                  StringRef WorkingDirectory,
+                                  const CompilationDatabase &CDB,
+                                  DependencyConsumer &Consumer);
 
 private:
   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
index 2d49e0d794af6086363ae08f48f40b140de40651..f6033de4618d2151d563bcc715150a460c9bd238 100644 (file)
@@ -21,21 +21,21 @@ using namespace dependencies;
 
 namespace {
 
-/// Prints out all of the gathered dependencies into a string.
-class DependencyPrinter : public DependencyFileGenerator {
+/// Forwards the gatherered dependencies to the consumer.
+class DependencyConsumerForwarder : public DependencyFileGenerator {
 public:
-  DependencyPrinter(std::unique_ptr<DependencyOutputOptions> Opts,
-                    std::string &S)
-      : DependencyFileGenerator(*Opts), Opts(std::move(Opts)), S(S) {}
+  DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts,
+                              DependencyConsumer &C)
+      : DependencyFileGenerator(*Opts), Opts(std::move(Opts)), C(C) {}
 
   void finishedMainFile(DiagnosticsEngine &Diags) override {
-    llvm::raw_string_ostream OS(S);
-    outputDependencyFile(OS);
+    for (const auto &File : getDependencies())
+      C.handleFileDependency(*Opts, File);
   }
 
 private:
   std::unique_ptr<DependencyOutputOptions> Opts;
-  std::string &S;
+  DependencyConsumer &C;
 };
 
 /// A proxy file system that doesn't call `chdir` when changing the working
@@ -65,10 +65,9 @@ private:
 class DependencyScanningAction : public tooling::ToolAction {
 public:
   DependencyScanningAction(
-      StringRef WorkingDirectory, std::string &DependencyFileContents,
+      StringRef WorkingDirectory, DependencyConsumer &Consumer,
       llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS)
-      : WorkingDirectory(WorkingDirectory),
-        DependencyFileContents(DependencyFileContents),
+      : WorkingDirectory(WorkingDirectory), Consumer(Consumer),
         DepFS(std::move(DepFS)) {}
 
   bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
@@ -121,8 +120,9 @@ public:
     // We need at least one -MT equivalent for the generator to work.
     if (Opts->Targets.empty())
       Opts->Targets = {"clang-scan-deps dependency"};
-    Compiler.addDependencyCollector(std::make_shared<DependencyPrinter>(
-        std::move(Opts), DependencyFileContents));
+    Compiler.addDependencyCollector(
+        std::make_shared<DependencyConsumerForwarder>(std::move(Opts),
+                                                      Consumer));
 
     auto Action = std::make_unique<PreprocessOnlyAction>();
     const bool Result = Compiler.ExecuteAction(*Action);
@@ -133,8 +133,7 @@ public:
 
 private:
   StringRef WorkingDirectory;
-  /// The dependency file will be written to this string.
-  std::string &DependencyFileContents;
+  DependencyConsumer &Consumer;
   llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
 };
 
@@ -152,30 +151,35 @@ DependencyScanningWorker::DependencyScanningWorker(
     Files = new FileManager(FileSystemOptions(), RealFS);
 }
 
-llvm::Expected<std::string>
-DependencyScanningWorker::getDependencyFile(const std::string &Input,
-                                            StringRef WorkingDirectory,
-                                            const CompilationDatabase &CDB) {
+static llvm::Error runWithDiags(
+    DiagnosticOptions *DiagOpts,
+    llvm::function_ref<bool(DiagnosticConsumer &DC)> BodyShouldSucceed) {
   // Capture the emitted diagnostics and report them to the client
   // in the case of a failure.
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
-  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.get());
+  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts);
 
+  if (BodyShouldSucceed(DiagPrinter))
+    return llvm::Error::success();
+  return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
+                                             llvm::inconvertibleErrorCode());
+}
+
+llvm::Error DependencyScanningWorker::computeDependencies(
+    const std::string &Input, StringRef WorkingDirectory,
+    const CompilationDatabase &CDB, DependencyConsumer &Consumer) {
   RealFS->setCurrentWorkingDirectory(WorkingDirectory);
-  /// Create the tool that uses the underlying file system to ensure that any
-  /// file system requests that are made by the driver do not go through the
-  /// dependency scanning filesystem.
-  tooling::ClangTool Tool(CDB, Input, PCHContainerOps, RealFS, Files);
-  Tool.clearArgumentsAdjusters();
-  Tool.setRestoreWorkingDir(false);
-  Tool.setPrintErrorMessage(false);
-  Tool.setDiagnosticConsumer(&DiagPrinter);
-  std::string Output;
-  DependencyScanningAction Action(WorkingDirectory, Output, DepFS);
-  if (Tool.run(&Action)) {
-    return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
-                                               llvm::inconvertibleErrorCode());
-  }
-  return Output;
+  return runWithDiags(DiagOpts.get(), [&](DiagnosticConsumer &DC) {
+    /// Create the tool that uses the underlying file system to ensure that any
+    /// file system requests that are made by the driver do not go through the
+    /// dependency scanning filesystem.
+    tooling::ClangTool Tool(CDB, Input, PCHContainerOps, RealFS, Files);
+    Tool.clearArgumentsAdjusters();
+    Tool.setRestoreWorkingDir(false);
+    Tool.setPrintErrorMessage(false);
+    Tool.setDiagnosticConsumer(&DC);
+    DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS);
+    return !Tool.run(&Action);
+  });
 }
index 5e567fef9dae36c5e64e043239945021d4f5de5a..bee4b479b2d184f7526abc754221efedc2497ae9 100644 (file)
@@ -51,11 +51,67 @@ public:
                          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 = Worker.getDependencyFile(Input, CWD, Compilations);
+    auto MaybeFile = getDependencyFile(Input, CWD);
     if (!MaybeFile) {
       llvm::handleAllErrors(
           MaybeFile.takeError(), [this, &Input](llvm::StringError &Err) {