Coverage Report

Created: 2022-05-14 11:35

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