diff clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp @ 150:1d019706d866

LLVM10
author anatofuz
date Thu, 13 Feb 2020 15:10:13 +0900
parents
children 2e18cbf3894f
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp	Thu Feb 13 15:10:13 2020 +0900
@@ -0,0 +1,173 @@
+//===- 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{
+
+std::vector<std::string> FullDependencies::getAdditionalCommandLine(
+    std::function<StringRef(ClangModuleDep)> LookupPCMPath,
+    std::function<const ModuleDeps &(ClangModuleDep)> LookupModuleDeps) const {
+  std::vector<std::string> Ret = AdditionalNonPathCommandLine;
+
+  dependencies::detail::appendCommonModuleArguments(
+      ClangModuleDeps, LookupPCMPath, LookupModuleDeps, Ret);
+
+  return Ret;
+}
+
+DependencyScanningTool::DependencyScanningTool(
+    DependencyScanningService &Service)
+    : Worker(Service) {}
+
+llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
+    const tooling::CompilationDatabase &Compilations, StringRef CWD) {
+  /// Prints out all of the gathered dependencies into a string.
+  class MakeDependencyPrinterConsumer : public DependencyConsumer {
+  public:
+    void handleFileDependency(const DependencyOutputOptions &Opts,
+                              StringRef File) override {
+      if (!this->Opts)
+        this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
+      Dependencies.push_back(std::string(File));
+    }
+
+    void handleModuleDependency(ModuleDeps MD) override {
+      // These are ignored for the make format as it can't support the full
+      // set of deps, and handleFileDependency handles enough for implicitly
+      // built modules to work.
+    }
+
+    void handleContextHash(std::string Hash) override {}
+
+    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;
+  };
+
+  // We expect a single command here because if a source file occurs multiple
+  // times in the original CDB, then `computeDependencies` would run the
+  // `DependencyScanningAction` once for every time the input occured in the
+  // CDB. Instead we split up the CDB into single command chunks to avoid this
+  // behavior.
+  assert(Compilations.getAllCompileCommands().size() == 1 &&
+         "Expected a compilation database with a single command!");
+  std::string Input = Compilations.getAllCompileCommands().front().Filename;
+
+  MakeDependencyPrinterConsumer Consumer;
+  auto Result = Worker.computeDependencies(Input, CWD, Compilations, Consumer);
+  if (Result)
+    return std::move(Result);
+  std::string Output;
+  Consumer.printDependencies(Output);
+  return Output;
+}
+
+llvm::Expected<FullDependenciesResult>
+DependencyScanningTool::getFullDependencies(
+    const tooling::CompilationDatabase &Compilations, StringRef CWD,
+    const llvm::StringSet<> &AlreadySeen) {
+  class FullDependencyPrinterConsumer : public DependencyConsumer {
+  public:
+    FullDependencyPrinterConsumer(const llvm::StringSet<> &AlreadySeen)
+        : AlreadySeen(AlreadySeen) {}
+
+    void handleFileDependency(const DependencyOutputOptions &Opts,
+                              StringRef File) override {
+      Dependencies.push_back(std::string(File));
+    }
+
+    void handleModuleDependency(ModuleDeps MD) override {
+      ClangModuleDeps[MD.ContextHash + MD.ModuleName] = std::move(MD);
+    }
+
+    void handleContextHash(std::string Hash) override {
+      ContextHash = std::move(Hash);
+    }
+
+    FullDependenciesResult getFullDependencies() const {
+      FullDependencies FD;
+
+      FD.ContextHash = std::move(ContextHash);
+
+      FD.FileDeps.assign(Dependencies.begin(), Dependencies.end());
+
+      for (auto &&M : ClangModuleDeps) {
+        auto &MD = M.second;
+        if (MD.ImportedByMainFile)
+          FD.ClangModuleDeps.push_back({MD.ModuleName, ContextHash});
+      }
+
+      FullDependenciesResult FDR;
+
+      for (auto &&M : ClangModuleDeps) {
+        // TODO: Avoid handleModuleDependency even being called for modules
+        //   we've already seen.
+        if (AlreadySeen.count(M.first))
+          continue;
+        FDR.DiscoveredModules.push_back(std::move(M.second));
+      }
+
+      FDR.FullDeps = std::move(FD);
+      return FDR;
+    }
+
+  private:
+    std::vector<std::string> Dependencies;
+    std::unordered_map<std::string, ModuleDeps> ClangModuleDeps;
+    std::string ContextHash;
+    std::vector<std::string> OutputPaths;
+    const llvm::StringSet<> &AlreadySeen;
+  };
+
+  // We expect a single command here because if a source file occurs multiple
+  // times in the original CDB, then `computeDependencies` would run the
+  // `DependencyScanningAction` once for every time the input occured in the
+  // CDB. Instead we split up the CDB into single command chunks to avoid this
+  // behavior.
+  assert(Compilations.getAllCompileCommands().size() == 1 &&
+         "Expected a compilation database with a single command!");
+  std::string Input = Compilations.getAllCompileCommands().front().Filename;
+
+  FullDependencyPrinterConsumer Consumer(AlreadySeen);
+  llvm::Error Result =
+      Worker.computeDependencies(Input, CWD, Compilations, Consumer);
+  if (Result)
+    return std::move(Result);
+  return Consumer.getFullDependencies();
+}
+
+} // end namespace dependencies
+} // end namespace tooling
+} // end namespace clang