summaryrefslogtreecommitdiff
path: root/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp')
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp131
1 files changed, 117 insertions, 14 deletions
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
index 82b3ae806c65..f643c538f8f9 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -1,4 +1,4 @@
-//===- DependencyScanningTool.cpp - clang-scan-deps service ------------===//
+//===- 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.
@@ -8,18 +8,29 @@
#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
#include "clang/Frontend/Utils.h"
+#include "llvm/Support/JSON.h"
+
+static llvm::json::Array toJSONSorted(const llvm::StringSet<> &Set) {
+ std::vector<llvm::StringRef> Strings;
+ for (auto &&I : Set)
+ Strings.push_back(I.getKey());
+ std::sort(Strings.begin(), Strings.end());
+ return llvm::json::Array(Strings);
+}
namespace clang{
namespace tooling{
namespace dependencies{
-DependencyScanningTool::DependencyScanningTool(DependencyScanningService &Service,
-const tooling::CompilationDatabase &Compilations) : Worker(Service), Compilations(Compilations) {}
+DependencyScanningTool::DependencyScanningTool(
+ DependencyScanningService &Service)
+ : Format(Service.getFormat()), Worker(Service) {
+}
-llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(const std::string &Input,
- StringRef CWD) {
+llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
+ const tooling::CompilationDatabase &Compilations, StringRef CWD) {
/// Prints out all of the gathered dependencies into a string.
- class DependencyPrinterConsumer : public DependencyConsumer {
+ class MakeDependencyPrinterConsumer : public DependencyConsumer {
public:
void handleFileDependency(const DependencyOutputOptions &Opts,
StringRef File) override {
@@ -28,6 +39,14 @@ llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(const std:
Dependencies.push_back(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;
@@ -56,14 +75,98 @@ llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(const std:
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;
+ class FullDependencyPrinterConsumer : public DependencyConsumer {
+ public:
+ void handleFileDependency(const DependencyOutputOptions &Opts,
+ StringRef File) override {
+ Dependencies.push_back(File);
+ }
+
+ void handleModuleDependency(ModuleDeps MD) override {
+ ClangModuleDeps[MD.ContextHash + MD.ModuleName] = std::move(MD);
+ }
+
+ void handleContextHash(std::string Hash) override {
+ ContextHash = std::move(Hash);
+ }
+
+ void printDependencies(std::string &S, StringRef MainFile) {
+ // Sort the modules by name to get a deterministic order.
+ std::vector<StringRef> Modules;
+ for (auto &&Dep : ClangModuleDeps)
+ Modules.push_back(Dep.first);
+ std::sort(Modules.begin(), Modules.end());
+
+ llvm::raw_string_ostream OS(S);
+
+ using namespace llvm::json;
+
+ Array Imports;
+ for (auto &&ModName : Modules) {
+ auto &MD = ClangModuleDeps[ModName];
+ if (MD.ImportedByMainFile)
+ Imports.push_back(MD.ModuleName);
+ }
+
+ Array Mods;
+ for (auto &&ModName : Modules) {
+ auto &MD = ClangModuleDeps[ModName];
+ Object Mod{
+ {"name", MD.ModuleName},
+ {"file-deps", toJSONSorted(MD.FileDeps)},
+ {"clang-module-deps", toJSONSorted(MD.ClangModuleDeps)},
+ {"clang-modulemap-file", MD.ClangModuleMapFile},
+ };
+ Mods.push_back(std::move(Mod));
+ }
+
+ Object O{
+ {"input-file", MainFile},
+ {"clang-context-hash", ContextHash},
+ {"file-deps", Dependencies},
+ {"clang-module-deps", std::move(Imports)},
+ {"clang-modules", std::move(Mods)},
+ };
+
+ S = llvm::formatv("{0:2},\n", Value(std::move(O))).str();
+ return;
+ }
+
+ private:
+ std::vector<std::string> Dependencies;
+ std::unordered_map<std::string, ModuleDeps> ClangModuleDeps;
+ std::string ContextHash;
+ };
+
+
+ // 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;
+
+ if (Format == ScanningOutputFormat::Make) {
+ MakeDependencyPrinterConsumer Consumer;
+ auto Result =
+ Worker.computeDependencies(Input, CWD, Compilations, Consumer);
+ if (Result)
+ return std::move(Result);
+ std::string Output;
+ Consumer.printDependencies(Output);
+ return Output;
+ } else {
+ FullDependencyPrinterConsumer Consumer;
+ auto Result =
+ Worker.computeDependencies(Input, CWD, Compilations, Consumer);
+ if (Result)
+ return std::move(Result);
+ std::string Output;
+ Consumer.printDependencies(Output, Input);
+ return Output;
+ }
}
} // end namespace dependencies