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