1*480093f4SDimitry Andric //===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===// 2a7dea167SDimitry Andric // 3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7dea167SDimitry Andric // 7a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8a7dea167SDimitry Andric 9a7dea167SDimitry Andric #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" 10a7dea167SDimitry Andric #include "clang/Frontend/Utils.h" 11*480093f4SDimitry Andric #include "llvm/Support/JSON.h" 12*480093f4SDimitry Andric 13*480093f4SDimitry Andric static llvm::json::Array toJSONSorted(const llvm::StringSet<> &Set) { 14*480093f4SDimitry Andric std::vector<llvm::StringRef> Strings; 15*480093f4SDimitry Andric for (auto &&I : Set) 16*480093f4SDimitry Andric Strings.push_back(I.getKey()); 17*480093f4SDimitry Andric std::sort(Strings.begin(), Strings.end()); 18*480093f4SDimitry Andric return llvm::json::Array(Strings); 19*480093f4SDimitry Andric } 20a7dea167SDimitry Andric 21a7dea167SDimitry Andric namespace clang{ 22a7dea167SDimitry Andric namespace tooling{ 23a7dea167SDimitry Andric namespace dependencies{ 24a7dea167SDimitry Andric 25*480093f4SDimitry Andric DependencyScanningTool::DependencyScanningTool( 26*480093f4SDimitry Andric DependencyScanningService &Service) 27*480093f4SDimitry Andric : Format(Service.getFormat()), Worker(Service) { 28*480093f4SDimitry Andric } 29a7dea167SDimitry Andric 30*480093f4SDimitry Andric llvm::Expected<std::string> DependencyScanningTool::getDependencyFile( 31*480093f4SDimitry Andric const tooling::CompilationDatabase &Compilations, StringRef CWD) { 32a7dea167SDimitry Andric /// Prints out all of the gathered dependencies into a string. 33*480093f4SDimitry Andric class MakeDependencyPrinterConsumer : public DependencyConsumer { 34a7dea167SDimitry Andric public: 35a7dea167SDimitry Andric void handleFileDependency(const DependencyOutputOptions &Opts, 36a7dea167SDimitry Andric StringRef File) override { 37a7dea167SDimitry Andric if (!this->Opts) 38a7dea167SDimitry Andric this->Opts = std::make_unique<DependencyOutputOptions>(Opts); 39a7dea167SDimitry Andric Dependencies.push_back(File); 40a7dea167SDimitry Andric } 41a7dea167SDimitry Andric 42*480093f4SDimitry Andric void handleModuleDependency(ModuleDeps MD) override { 43*480093f4SDimitry Andric // These are ignored for the make format as it can't support the full 44*480093f4SDimitry Andric // set of deps, and handleFileDependency handles enough for implicitly 45*480093f4SDimitry Andric // built modules to work. 46*480093f4SDimitry Andric } 47*480093f4SDimitry Andric 48*480093f4SDimitry Andric void handleContextHash(std::string Hash) override {} 49*480093f4SDimitry Andric 50a7dea167SDimitry Andric void printDependencies(std::string &S) { 51a7dea167SDimitry Andric if (!Opts) 52a7dea167SDimitry Andric return; 53a7dea167SDimitry Andric 54a7dea167SDimitry Andric class DependencyPrinter : public DependencyFileGenerator { 55a7dea167SDimitry Andric public: 56a7dea167SDimitry Andric DependencyPrinter(DependencyOutputOptions &Opts, 57a7dea167SDimitry Andric ArrayRef<std::string> Dependencies) 58a7dea167SDimitry Andric : DependencyFileGenerator(Opts) { 59a7dea167SDimitry Andric for (const auto &Dep : Dependencies) 60a7dea167SDimitry Andric addDependency(Dep); 61a7dea167SDimitry Andric } 62a7dea167SDimitry Andric 63a7dea167SDimitry Andric void printDependencies(std::string &S) { 64a7dea167SDimitry Andric llvm::raw_string_ostream OS(S); 65a7dea167SDimitry Andric outputDependencyFile(OS); 66a7dea167SDimitry Andric } 67a7dea167SDimitry Andric }; 68a7dea167SDimitry Andric 69a7dea167SDimitry Andric DependencyPrinter Generator(*Opts, Dependencies); 70a7dea167SDimitry Andric Generator.printDependencies(S); 71a7dea167SDimitry Andric } 72a7dea167SDimitry Andric 73a7dea167SDimitry Andric private: 74a7dea167SDimitry Andric std::unique_ptr<DependencyOutputOptions> Opts; 75a7dea167SDimitry Andric std::vector<std::string> Dependencies; 76a7dea167SDimitry Andric }; 77a7dea167SDimitry Andric 78*480093f4SDimitry Andric class FullDependencyPrinterConsumer : public DependencyConsumer { 79*480093f4SDimitry Andric public: 80*480093f4SDimitry Andric void handleFileDependency(const DependencyOutputOptions &Opts, 81*480093f4SDimitry Andric StringRef File) override { 82*480093f4SDimitry Andric Dependencies.push_back(File); 83*480093f4SDimitry Andric } 84*480093f4SDimitry Andric 85*480093f4SDimitry Andric void handleModuleDependency(ModuleDeps MD) override { 86*480093f4SDimitry Andric ClangModuleDeps[MD.ContextHash + MD.ModuleName] = std::move(MD); 87*480093f4SDimitry Andric } 88*480093f4SDimitry Andric 89*480093f4SDimitry Andric void handleContextHash(std::string Hash) override { 90*480093f4SDimitry Andric ContextHash = std::move(Hash); 91*480093f4SDimitry Andric } 92*480093f4SDimitry Andric 93*480093f4SDimitry Andric void printDependencies(std::string &S, StringRef MainFile) { 94*480093f4SDimitry Andric // Sort the modules by name to get a deterministic order. 95*480093f4SDimitry Andric std::vector<StringRef> Modules; 96*480093f4SDimitry Andric for (auto &&Dep : ClangModuleDeps) 97*480093f4SDimitry Andric Modules.push_back(Dep.first); 98*480093f4SDimitry Andric std::sort(Modules.begin(), Modules.end()); 99*480093f4SDimitry Andric 100*480093f4SDimitry Andric llvm::raw_string_ostream OS(S); 101*480093f4SDimitry Andric 102*480093f4SDimitry Andric using namespace llvm::json; 103*480093f4SDimitry Andric 104*480093f4SDimitry Andric Array Imports; 105*480093f4SDimitry Andric for (auto &&ModName : Modules) { 106*480093f4SDimitry Andric auto &MD = ClangModuleDeps[ModName]; 107*480093f4SDimitry Andric if (MD.ImportedByMainFile) 108*480093f4SDimitry Andric Imports.push_back(MD.ModuleName); 109*480093f4SDimitry Andric } 110*480093f4SDimitry Andric 111*480093f4SDimitry Andric Array Mods; 112*480093f4SDimitry Andric for (auto &&ModName : Modules) { 113*480093f4SDimitry Andric auto &MD = ClangModuleDeps[ModName]; 114*480093f4SDimitry Andric Object Mod{ 115*480093f4SDimitry Andric {"name", MD.ModuleName}, 116*480093f4SDimitry Andric {"file-deps", toJSONSorted(MD.FileDeps)}, 117*480093f4SDimitry Andric {"clang-module-deps", toJSONSorted(MD.ClangModuleDeps)}, 118*480093f4SDimitry Andric {"clang-modulemap-file", MD.ClangModuleMapFile}, 119*480093f4SDimitry Andric }; 120*480093f4SDimitry Andric Mods.push_back(std::move(Mod)); 121*480093f4SDimitry Andric } 122*480093f4SDimitry Andric 123*480093f4SDimitry Andric Object O{ 124*480093f4SDimitry Andric {"input-file", MainFile}, 125*480093f4SDimitry Andric {"clang-context-hash", ContextHash}, 126*480093f4SDimitry Andric {"file-deps", Dependencies}, 127*480093f4SDimitry Andric {"clang-module-deps", std::move(Imports)}, 128*480093f4SDimitry Andric {"clang-modules", std::move(Mods)}, 129*480093f4SDimitry Andric }; 130*480093f4SDimitry Andric 131*480093f4SDimitry Andric S = llvm::formatv("{0:2},\n", Value(std::move(O))).str(); 132*480093f4SDimitry Andric return; 133*480093f4SDimitry Andric } 134*480093f4SDimitry Andric 135*480093f4SDimitry Andric private: 136*480093f4SDimitry Andric std::vector<std::string> Dependencies; 137*480093f4SDimitry Andric std::unordered_map<std::string, ModuleDeps> ClangModuleDeps; 138*480093f4SDimitry Andric std::string ContextHash; 139*480093f4SDimitry Andric }; 140*480093f4SDimitry Andric 141*480093f4SDimitry Andric 142*480093f4SDimitry Andric // We expect a single command here because if a source file occurs multiple 143*480093f4SDimitry Andric // times in the original CDB, then `computeDependencies` would run the 144*480093f4SDimitry Andric // `DependencyScanningAction` once for every time the input occured in the 145*480093f4SDimitry Andric // CDB. Instead we split up the CDB into single command chunks to avoid this 146*480093f4SDimitry Andric // behavior. 147*480093f4SDimitry Andric assert(Compilations.getAllCompileCommands().size() == 1 && 148*480093f4SDimitry Andric "Expected a compilation database with a single command!"); 149*480093f4SDimitry Andric std::string Input = Compilations.getAllCompileCommands().front().Filename; 150*480093f4SDimitry Andric 151*480093f4SDimitry Andric if (Format == ScanningOutputFormat::Make) { 152*480093f4SDimitry Andric MakeDependencyPrinterConsumer Consumer; 153a7dea167SDimitry Andric auto Result = 154a7dea167SDimitry Andric Worker.computeDependencies(Input, CWD, Compilations, Consumer); 155a7dea167SDimitry Andric if (Result) 156a7dea167SDimitry Andric return std::move(Result); 157a7dea167SDimitry Andric std::string Output; 158a7dea167SDimitry Andric Consumer.printDependencies(Output); 159a7dea167SDimitry Andric return Output; 160*480093f4SDimitry Andric } else { 161*480093f4SDimitry Andric FullDependencyPrinterConsumer Consumer; 162*480093f4SDimitry Andric auto Result = 163*480093f4SDimitry Andric Worker.computeDependencies(Input, CWD, Compilations, Consumer); 164*480093f4SDimitry Andric if (Result) 165*480093f4SDimitry Andric return std::move(Result); 166*480093f4SDimitry Andric std::string Output; 167*480093f4SDimitry Andric Consumer.printDependencies(Output, Input); 168*480093f4SDimitry Andric return Output; 169*480093f4SDimitry Andric } 170a7dea167SDimitry Andric } 171a7dea167SDimitry Andric 172a7dea167SDimitry Andric } // end namespace dependencies 173a7dea167SDimitry Andric } // end namespace tooling 174a7dea167SDimitry Andric } // end namespace clang 175