Coverage Report

Created: 2022-07-16 07:03

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
Line
Count
Source (jump to first uncovered line)
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
9
#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
10
#include "clang/Frontend/Utils.h"
11
12
using namespace clang;
13
using namespace tooling;
14
using namespace dependencies;
15
16
std::vector<std::string> FullDependencies::getCommandLine(
17
    llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)>
18
31
        LookupModuleOutput) const {
19
31
  std::vector<std::string> Ret = getCommandLineWithoutModulePaths();
20
21
31
  for (ModuleID MID : ClangModuleDeps) {
22
31
    auto PCM = LookupModuleOutput(MID, ModuleOutputKind::ModuleFile);
23
31
    Ret.push_back("-fmodule-file=" + PCM);
24
31
  }
25
26
31
  return Ret;
27
31
}
28
29
std::vector<std::string>
30
54
FullDependencies::getCommandLineWithoutModulePaths() const {
31
54
  std::vector<std::string> Args = OriginalCommandLine;
32
33
54
  Args.push_back("-fno-implicit-modules");
34
54
  Args.push_back("-fno-implicit-module-maps");
35
54
  for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps)
36
2
    Args.push_back("-fmodule-file=" + PMD.PCMFile);
37
38
  // These arguments are unused in explicit compiles.
39
686
  llvm::erase_if(Args, [](StringRef Arg) {
40
686
    if (Arg.consume_front("-fmodules-")) {
41
51
      return Arg.startswith("cache-path=") ||
42
51
             
Arg.startswith("prune-interval=")3
||
43
51
             
Arg.startswith("prune-after=")2
||
44
51
             
Arg == "validate-once-per-build-session"1
;
45
51
    }
46
635
    return Arg.startswith("-fbuild-session-file=");
47
686
  });
48
49
54
  return Args;
50
54
}
51
52
DependencyScanningTool::DependencyScanningTool(
53
    DependencyScanningService &Service)
54
574
    : Worker(Service) {}
55
56
llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
57
    const std::vector<std::string> &CommandLine, StringRef CWD,
58
137
    llvm::Optional<StringRef> ModuleName) {
59
  /// Prints out all of the gathered dependencies into a string.
60
137
  class MakeDependencyPrinterConsumer : public DependencyConsumer {
61
137
  public:
62
137
    void
63
137
    handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {
64
135
      this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
65
135
    }
66
67
388
    void handleFileDependency(StringRef File) override {
68
388
      Dependencies.push_back(std::string(File));
69
388
    }
70
71
137
    void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {
72
      // Same as `handleModuleDependency`.
73
0
    }
74
75
137
    void handleModuleDependency(ModuleDeps MD) override {
76
      // These are ignored for the make format as it can't support the full
77
      // set of deps, and handleFileDependency handles enough for implicitly
78
      // built modules to work.
79
0
    }
80
81
137
    void handleContextHash(std::string Hash) override 
{}0
82
83
137
    void printDependencies(std::string &S) {
84
129
      assert(Opts && "Handled dependency output options.");
85
86
0
      class DependencyPrinter : public DependencyFileGenerator {
87
129
      public:
88
129
        DependencyPrinter(DependencyOutputOptions &Opts,
89
129
                          ArrayRef<std::string> Dependencies)
90
129
            : DependencyFileGenerator(Opts) {
91
129
          for (const auto &Dep : Dependencies)
92
380
            addDependency(Dep);
93
129
        }
94
95
130
        void printDependencies(std::string &S) {
96
130
          llvm::raw_string_ostream OS(S);
97
130
          outputDependencyFile(OS);
98
130
        }
99
129
      };
100
101
129
      DependencyPrinter Generator(*Opts, Dependencies);
102
129
      Generator.printDependencies(S);
103
129
    }
104
105
137
  private:
106
137
    std::unique_ptr<DependencyOutputOptions> Opts;
107
137
    std::vector<std::string> Dependencies;
108
137
  };
109
110
137
  MakeDependencyPrinterConsumer Consumer;
111
137
  auto Result =
112
137
      Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
113
137
  if (Result)
114
7
    return std::move(Result);
115
130
  std::string Output;
116
130
  Consumer.printDependencies(Output);
117
130
  return Output;
118
137
}
119
120
llvm::Expected<FullDependenciesResult>
121
DependencyScanningTool::getFullDependencies(
122
    const std::vector<std::string> &CommandLine, StringRef CWD,
123
    const llvm::StringSet<> &AlreadySeen,
124
54
    llvm::Optional<StringRef> ModuleName) {
125
54
  class FullDependencyPrinterConsumer : public DependencyConsumer {
126
54
  public:
127
54
    FullDependencyPrinterConsumer(const llvm::StringSet<> &AlreadySeen)
128
54
        : AlreadySeen(AlreadySeen) {}
129
130
54
    void
131
54
    handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {}
132
133
59
    void handleFileDependency(StringRef File) override {
134
59
      Dependencies.push_back(std::string(File));
135
59
    }
136
137
54
    void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {
138
2
      PrebuiltModuleDeps.emplace_back(std::move(PMD));
139
2
    }
140
141
85
    void handleModuleDependency(ModuleDeps MD) override {
142
85
      ClangModuleDeps[MD.ID.ContextHash + MD.ID.ModuleName] = std::move(MD);
143
85
    }
144
145
54
    void handleContextHash(std::string Hash) override {
146
50
      ContextHash = std::move(Hash);
147
50
    }
148
149
54
    FullDependenciesResult getFullDependencies(
150
54
        const std::vector<std::string> &OriginalCommandLine) const {
151
54
      FullDependencies FD;
152
153
54
      FD.OriginalCommandLine =
154
54
          ArrayRef<std::string>(OriginalCommandLine).slice(1);
155
156
54
      FD.ID.ContextHash = std::move(ContextHash);
157
158
54
      FD.FileDeps.assign(Dependencies.begin(), Dependencies.end());
159
160
85
      for (auto &&M : ClangModuleDeps) {
161
85
        auto &MD = M.second;
162
85
        if (MD.ImportedByMainFile)
163
55
          FD.ClangModuleDeps.push_back(MD.ID);
164
85
      }
165
166
54
      FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps);
167
168
54
      FullDependenciesResult FDR;
169
170
85
      for (auto &&M : ClangModuleDeps) {
171
        // TODO: Avoid handleModuleDependency even being called for modules
172
        //   we've already seen.
173
85
        if (AlreadySeen.count(M.first))
174
0
          continue;
175
85
        FDR.DiscoveredModules.push_back(std::move(M.second));
176
85
      }
177
178
54
      FDR.FullDeps = std::move(FD);
179
54
      return FDR;
180
54
    }
181
182
54
  private:
183
54
    std::vector<std::string> Dependencies;
184
54
    std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
185
54
    llvm::MapVector<std::string, ModuleDeps, llvm::StringMap<unsigned>> ClangModuleDeps;
186
54
    std::string ContextHash;
187
54
    std::vector<std::string> OutputPaths;
188
54
    const llvm::StringSet<> &AlreadySeen;
189
54
  };
190
191
54
  FullDependencyPrinterConsumer Consumer(AlreadySeen);
192
54
  llvm::Error Result =
193
54
      Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
194
54
  if (Result)
195
0
    return std::move(Result);
196
54
  return Consumer.getFullDependencies(CommandLine);
197
54
}