Coverage Report

Created: 2018-01-17 21:32

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/llvm-cov/CodeCoverage.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- CodeCoverage.cpp - Coverage tool based on profiling instrumentation-===//
2
//
3
//                     The LLVM Compiler Infrastructure
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
//
10
// The 'CodeCoverageTool' class implements a command line tool to analyze and
11
// report coverage information using the profiling instrumentation and code
12
// coverage mapping.
13
//
14
//===----------------------------------------------------------------------===//
15
16
#include "CoverageExporterJson.h"
17
#include "CoverageFilters.h"
18
#include "CoverageReport.h"
19
#include "CoverageSummaryInfo.h"
20
#include "CoverageViewOptions.h"
21
#include "RenderingSupport.h"
22
#include "SourceCoverageView.h"
23
#include "llvm/ADT/SmallString.h"
24
#include "llvm/ADT/StringRef.h"
25
#include "llvm/ADT/Triple.h"
26
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
27
#include "llvm/ProfileData/InstrProfReader.h"
28
#include "llvm/Support/CommandLine.h"
29
#include "llvm/Support/FileSystem.h"
30
#include "llvm/Support/Format.h"
31
#include "llvm/Support/MemoryBuffer.h"
32
#include "llvm/Support/Path.h"
33
#include "llvm/Support/Process.h"
34
#include "llvm/Support/Program.h"
35
#include "llvm/Support/ScopedPrinter.h"
36
#include "llvm/Support/ThreadPool.h"
37
#include "llvm/Support/Threading.h"
38
#include "llvm/Support/ToolOutputFile.h"
39
40
#include <functional>
41
#include <map>
42
#include <system_error>
43
44
using namespace llvm;
45
using namespace coverage;
46
47
void exportCoverageDataToJson(const coverage::CoverageMapping &CoverageMapping,
48
                              const CoverageViewOptions &Options,
49
                              raw_ostream &OS);
50
51
namespace {
52
/// \brief The implementation of the coverage tool.
53
class CodeCoverageTool {
54
public:
55
  enum Command {
56
    /// \brief The show command.
57
    Show,
58
    /// \brief The report command.
59
    Report,
60
    /// \brief The export command.
61
    Export
62
  };
63
64
  int run(Command Cmd, int argc, const char **argv);
65
66
private:
67
  /// \brief Print the error message to the error output stream.
68
  void error(const Twine &Message, StringRef Whence = "");
69
70
  /// \brief Print the warning message to the error output stream.
71
  void warning(const Twine &Message, StringRef Whence = "");
72
73
  /// \brief Convert \p Path into an absolute path and append it to the list
74
  /// of collected paths.
75
  void addCollectedPath(const std::string &Path);
76
77
  /// \brief If \p Path is a regular file, collect the path. If it's a
78
  /// directory, recursively collect all of the paths within the directory.
79
  void collectPaths(const std::string &Path);
80
81
  /// \brief Return a memory buffer for the given source file.
82
  ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
83
84
  /// \brief Create source views for the expansions of the view.
85
  void attachExpansionSubViews(SourceCoverageView &View,
86
                               ArrayRef<ExpansionRecord> Expansions,
87
                               const CoverageMapping &Coverage);
88
89
  /// \brief Create the source view of a particular function.
90
  std::unique_ptr<SourceCoverageView>
91
  createFunctionView(const FunctionRecord &Function,
92
                     const CoverageMapping &Coverage);
93
94
  /// \brief Create the main source view of a particular source file.
95
  std::unique_ptr<SourceCoverageView>
96
  createSourceFileView(StringRef SourceFile, const CoverageMapping &Coverage);
97
98
  /// \brief Load the coverage mapping data. Return nullptr if an error occurred.
99
  std::unique_ptr<CoverageMapping> load();
100
101
  /// \brief Create a mapping from files in the Coverage data to local copies
102
  /// (path-equivalence).
103
  void remapPathNames(const CoverageMapping &Coverage);
104
105
  /// \brief Remove input source files which aren't mapped by \p Coverage.
106
  void removeUnmappedInputs(const CoverageMapping &Coverage);
107
108
  /// \brief If a demangler is available, demangle all symbol names.
109
  void demangleSymbols(const CoverageMapping &Coverage);
110
111
  /// \brief Write out a source file view to the filesystem.
112
  void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage,
113
                           CoveragePrinter *Printer, bool ShowFilenames);
114
115
  typedef llvm::function_ref<int(int, const char **)> CommandLineParserType;
116
117
  int doShow(int argc, const char **argv,
118
             CommandLineParserType commandLineParser);
119
120
  int doReport(int argc, const char **argv,
121
               CommandLineParserType commandLineParser);
122
123
  int doExport(int argc, const char **argv,
124
               CommandLineParserType commandLineParser);
125
126
  std::vector<StringRef> ObjectFilenames;
127
  CoverageViewOptions ViewOpts;
128
  CoverageFiltersMatchAll Filters;
129
130
  /// The path to the indexed profile.
131
  std::string PGOFilename;
132
133
  /// A list of input source files.
134
  std::vector<std::string> SourceFiles;
135
136
  /// In -path-equivalence mode, this maps the absolute paths from the coverage
137
  /// mapping data to the input source files.
138
  StringMap<std::string> RemappedFilenames;
139
140
  /// The coverage data path to be remapped from, and the source path to be
141
  /// remapped to, when using -path-equivalence.
142
  Optional<std::pair<std::string, std::string>> PathRemapping;
143
144
  /// The architecture the coverage mapping data targets.
145
  std::vector<StringRef> CoverageArches;
146
147
  /// A cache for demangled symbols.
148
  DemangleCache DC;
149
150
  /// A lock which guards printing to stderr.
151
  std::mutex ErrsLock;
152
153
  /// A container for input source file buffers.
154
  std::mutex LoadedSourceFilesLock;
155
  std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
156
      LoadedSourceFiles;
157
158
  /// Whitelist from -name-whitelist to be used for filtering.
159
  std::unique_ptr<SpecialCaseList> NameWhitelist;
160
};
161
}
162
163
static std::string getErrorString(const Twine &Message, StringRef Whence,
164
27
                                  bool Warning) {
165
27
  std::string Str = (Warning ? 
"warning"12
:
"error"15
);
166
27
  Str += ": ";
167
27
  if (!Whence.empty())
168
13
    Str += Whence.str() + ": ";
169
27
  Str += Message.str() + "\n";
170
27
  return Str;
171
27
}
172
173
15
void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
174
15
  std::unique_lock<std::mutex> Guard{ErrsLock};
175
15
  ViewOpts.colored_ostream(errs(), raw_ostream::RED)
176
15
      << getErrorString(Message, Whence, false);
177
15
}
178
179
12
void CodeCoverageTool::warning(const Twine &Message, StringRef Whence) {
180
12
  std::unique_lock<std::mutex> Guard{ErrsLock};
181
12
  ViewOpts.colored_ostream(errs(), raw_ostream::RED)
182
12
      << getErrorString(Message, Whence, true);
183
12
}
184
185
44
void CodeCoverageTool::addCollectedPath(const std::string &Path) {
186
44
  SmallString<128> EffectivePath(Path);
187
44
  if (std::error_code EC = sys::fs::make_absolute(EffectivePath)) {
188
0
    error(EC.message(), Path);
189
0
    return;
190
0
  }
191
44
  sys::path::remove_dots(EffectivePath, /*remove_dot_dots=*/true);
192
44
  SourceFiles.emplace_back(EffectivePath.str());
193
44
}
194
195
43
void CodeCoverageTool::collectPaths(const std::string &Path) {
196
43
  llvm::sys::fs::file_status Status;
197
43
  llvm::sys::fs::status(Path, Status);
198
43
  if (!llvm::sys::fs::exists(Status)) {
199
7
    if (PathRemapping)
200
7
      addCollectedPath(Path);
201
0
    else
202
0
      error("Missing source file", Path);
203
7
    return;
204
7
  }
205
36
206
36
  if (llvm::sys::fs::is_regular_file(Status)) {
207
29
    addCollectedPath(Path);
208
29
    return;
209
29
  }
210
7
211
7
  if (llvm::sys::fs::is_directory(Status)) {
212
4
    std::error_code EC;
213
4
    for (llvm::sys::fs::recursive_directory_iterator F(Path, EC), E;
214
16
         F != E && 
!EC12
;
F.increment(EC)12
) {
215
12
      if (llvm::sys::fs::is_regular_file(F->path()))
216
8
        addCollectedPath(F->path());
217
12
    }
218
4
    if (EC)
219
0
      warning(EC.message(), Path);
220
4
  }
221
7
}
222
223
ErrorOr<const MemoryBuffer &>
224
86
CodeCoverageTool::getSourceFile(StringRef SourceFile) {
225
86
  // If we've remapped filenames, look up the real location for this file.
226
86
  std::unique_lock<std::mutex> Guard{LoadedSourceFilesLock};
227
86
  if (!RemappedFilenames.empty()) {
228
82
    auto Loc = RemappedFilenames.find(SourceFile);
229
82
    if (Loc != RemappedFilenames.end())
230
82
      SourceFile = Loc->second;
231
82
  }
232
86
  for (const auto &Files : LoadedSourceFiles)
233
136
    if (sys::fs::equivalent(SourceFile, Files.first))
234
4
      return *Files.second;
235
86
  auto Buffer = MemoryBuffer::getFile(SourceFile);
236
82
  if (auto EC = Buffer.getError()) {
237
11
    error(EC.message(), SourceFile);
238
11
    return EC;
239
11
  }
240
71
  LoadedSourceFiles.emplace_back(SourceFile, std::move(Buffer.get()));
241
71
  return *LoadedSourceFiles.back().second;
242
71
}
243
244
void CodeCoverageTool::attachExpansionSubViews(
245
    SourceCoverageView &View, ArrayRef<ExpansionRecord> Expansions,
246
109
    const CoverageMapping &Coverage) {
247
109
  if (!ViewOpts.ShowExpandedRegions)
248
105
    return;
249
4
  for (const auto &Expansion : Expansions) {
250
3
    auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
251
3
    if (ExpansionCoverage.empty())
252
0
      continue;
253
3
    auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
254
3
    if (!SourceBuffer)
255
0
      continue;
256
3
257
3
    auto SubViewExpansions = ExpansionCoverage.getExpansions();
258
3
    auto SubView =
259
3
        SourceCoverageView::create(Expansion.Function.Name, SourceBuffer.get(),
260
3
                                   ViewOpts, std::move(ExpansionCoverage));
261
3
    attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
262
3
    View.addExpansion(Expansion.Region, std::move(SubView));
263
3
  }
264
4
}
265
266
std::unique_ptr<SourceCoverageView>
267
CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
268
16
                                     const CoverageMapping &Coverage) {
269
16
  auto FunctionCoverage = Coverage.getCoverageForFunction(Function);
270
16
  if (FunctionCoverage.empty())
271
0
    return nullptr;
272
16
  auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename());
273
16
  if (!SourceBuffer)
274
3
    return nullptr;
275
13
276
13
  auto Expansions = FunctionCoverage.getExpansions();
277
13
  auto View = SourceCoverageView::create(DC.demangle(Function.Name),
278
13
                                         SourceBuffer.get(), ViewOpts,
279
13
                                         std::move(FunctionCoverage));
280
13
  attachExpansionSubViews(*View, Expansions, Coverage);
281
13
282
13
  return View;
283
13
}
284
285
std::unique_ptr<SourceCoverageView>
286
CodeCoverageTool::createSourceFileView(StringRef SourceFile,
287
67
                                       const CoverageMapping &Coverage) {
288
67
  auto SourceBuffer = getSourceFile(SourceFile);
289
67
  if (!SourceBuffer)
290
8
    return nullptr;
291
59
  auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
292
59
  if (FileCoverage.empty())
293
0
    return nullptr;
294
59
295
59
  auto Expansions = FileCoverage.getExpansions();
296
59
  auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
297
59
                                         ViewOpts, std::move(FileCoverage));
298
59
  attachExpansionSubViews(*View, Expansions, Coverage);
299
59
  if (!ViewOpts.ShowFunctionInstantiations)
300
0
    return View;
301
59
302
70
  
for (const auto &Group : Coverage.getInstantiationGroups(SourceFile))59
{
303
70
    // Skip functions which have a single instantiation.
304
70
    if (Group.size() < 2)
305
55
      continue;
306
15
307
36
    
for (const FunctionRecord *Function : Group.getInstantiations())15
{
308
36
      std::unique_ptr<SourceCoverageView> SubView{nullptr};
309
36
310
36
      StringRef Funcname = DC.demangle(Function->Name);
311
36
312
36
      if (Function->ExecutionCount > 0) {
313
34
        auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
314
34
        auto SubViewExpansions = SubViewCoverage.getExpansions();
315
34
        SubView = SourceCoverageView::create(
316
34
            Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
317
34
        attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
318
34
      }
319
36
320
36
      unsigned FileID = Function->CountedRegions.front().FileID;
321
36
      unsigned Line = 0;
322
36
      for (const auto &CR : Function->CountedRegions)
323
248
        if (CR.FileID == FileID)
324
248
          Line = std::max(CR.LineEnd, Line);
325
36
      View->addInstantiation(Funcname, Line, std::move(SubView));
326
36
    }
327
15
  }
328
59
  return View;
329
59
}
330
331
60
static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
332
60
  sys::fs::file_status Status;
333
60
  if (sys::fs::status(LHS, Status))
334
0
    return false;
335
60
  auto LHSTime = Status.getLastModificationTime();
336
60
  if (sys::fs::status(RHS, Status))
337
0
    return false;
338
60
  auto RHSTime = Status.getLastModificationTime();
339
60
  return LHSTime > RHSTime;
340
60
}
341
342
59
std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
343
59
  for (StringRef ObjectFilename : ObjectFilenames)
344
60
    if (modifiedTimeGT(ObjectFilename, PGOFilename))
345
0
      warning("profile data may be out of date - object is newer",
346
0
              ObjectFilename);
347
59
  auto CoverageOrErr =
348
59
      CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches);
349
59
  if (Error E = CoverageOrErr.takeError()) {
350
1
    error("Failed to load coverage: " + toString(std::move(E)),
351
1
          join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "));
352
1
    return nullptr;
353
1
  }
354
58
  auto Coverage = std::move(CoverageOrErr.get());
355
58
  unsigned Mismatched = Coverage->getMismatchedCount();
356
58
  if (Mismatched) {
357
1
    warning(Twine(Mismatched) + " functions have mismatched data");
358
1
359
1
    if (ViewOpts.Debug) {
360
1
      for (const auto &HashMismatch : Coverage->getHashMismatches())
361
1
        errs() << "hash-mismatch: "
362
1
               << "No profile record found for '" << HashMismatch.first << "'"
363
1
               << " with hash = 0x" << Twine::utohexstr(HashMismatch.second)
364
1
               << '\n';
365
1
366
1
      for (const auto &CounterMismatch : Coverage->getCounterMismatches())
367
0
        errs() << "counter-mismatch: "
368
0
               << "Coverage mapping for " << CounterMismatch.first
369
0
               << " only has " << CounterMismatch.second
370
0
               << " valid counter expressions\n";
371
1
    }
372
1
  }
373
58
374
58
  remapPathNames(*Coverage);
375
58
376
58
  if (!SourceFiles.empty())
377
27
    removeUnmappedInputs(*Coverage);
378
58
379
58
  demangleSymbols(*Coverage);
380
58
381
58
  return Coverage;
382
58
}
383
384
58
void CodeCoverageTool::remapPathNames(const CoverageMapping &Coverage) {
385
58
  if (!PathRemapping)
386
15
    return;
387
43
388
43
  // Convert remapping paths to native paths with trailing seperators.
389
86
  
auto nativeWithTrailing = [](StringRef Path) -> std::string 43
{
390
86
    if (Path.empty())
391
0
      return "";
392
86
    SmallString<128> NativePath;
393
86
    sys::path::native(Path, NativePath);
394
86
    if (!sys::path::is_separator(NativePath.back()))
395
85
      NativePath += sys::path::get_separator();
396
86
    return NativePath.c_str();
397
86
  };
398
43
  std::string RemapFrom = nativeWithTrailing(PathRemapping->first);
399
43
  std::string RemapTo = nativeWithTrailing(PathRemapping->second);
400
43
401
43
  // Create a mapping from coverage data file paths to local paths.
402
113
  for (StringRef Filename : Coverage.getUniqueSourceFiles()) {
403
113
    SmallString<128> NativeFilename;
404
113
    sys::path::native(Filename, NativeFilename);
405
113
    if (NativeFilename.startswith(RemapFrom)) {
406
112
      RemappedFilenames[Filename] =
407
112
          RemapTo + NativeFilename.substr(RemapFrom.size()).str();
408
112
    }
409
113
  }
410
43
411
43
  // Convert input files from local paths to coverage data file paths.
412
43
  StringMap<std::string> InvRemappedFilenames;
413
43
  for (const auto &RemappedFilename : RemappedFilenames)
414
112
    InvRemappedFilenames[RemappedFilename.getValue()] = RemappedFilename.getKey();
415
43
416
43
  for (std::string &Filename : SourceFiles) {
417
32
    SmallString<128> NativeFilename;
418
32
    sys::path::native(Filename, NativeFilename);
419
32
    auto CovFileName = InvRemappedFilenames.find(NativeFilename);
420
32
    if (CovFileName != InvRemappedFilenames.end())
421
28
      Filename = CovFileName->second;
422
32
  }
423
43
}
424
425
27
void CodeCoverageTool::removeUnmappedInputs(const CoverageMapping &Coverage) {
426
27
  std::vector<StringRef> CoveredFiles = Coverage.getUniqueSourceFiles();
427
27
428
27
  auto UncoveredFilesIt = SourceFiles.end();
429
27
  // The user may have specified source files which aren't in the coverage
430
27
  // mapping. Filter these files away.
431
27
  UncoveredFilesIt = std::remove_if(
432
32
      SourceFiles.begin(), SourceFiles.end(), [&](const std::string &SF) {
433
32
        return !std::binary_search(CoveredFiles.begin(), CoveredFiles.end(),
434
32
                                   SF);
435
32
      });
436
27
437
27
  SourceFiles.erase(UncoveredFilesIt, SourceFiles.end());
438
27
}
439
440
58
void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) {
441
58
  if (!ViewOpts.hasDemangler())
442
56
    return;
443
2
444
2
  // Pass function names to the demangler in a temporary file.
445
2
  int InputFD;
446
2
  SmallString<256> InputPath;
447
2
  std::error_code EC =
448
2
      sys::fs::createTemporaryFile("demangle-in", "list", InputFD, InputPath);
449
2
  if (EC) {
450
0
    error(InputPath, EC.message());
451
0
    return;
452
0
  }
453
2
  ToolOutputFile InputTOF{InputPath, InputFD};
454
2
455
2
  unsigned NumSymbols = 0;
456
6
  for (const auto &Function : Coverage.getCoveredFunctions()) {
457
6
    InputTOF.os() << Function.Name << '\n';
458
6
    ++NumSymbols;
459
6
  }
460
2
  InputTOF.os().close();
461
2
462
2
  // Use another temporary file to store the demangler's output.
463
2
  int OutputFD;
464
2
  SmallString<256> OutputPath;
465
2
  EC = sys::fs::createTemporaryFile("demangle-out", "list", OutputFD,
466
2
                                    OutputPath);
467
2
  if (EC) {
468
0
    error(OutputPath, EC.message());
469
0
    return;
470
0
  }
471
2
  ToolOutputFile OutputTOF{OutputPath, OutputFD};
472
2
  OutputTOF.os().close();
473
2
474
2
  // Invoke the demangler.
475
2
  std::vector<const char *> ArgsV;
476
2
  for (const std::string &Arg : ViewOpts.DemanglerOpts)
477
4
    ArgsV.push_back(Arg.c_str());
478
2
  ArgsV.push_back(nullptr);
479
2
  Optional<StringRef> Redirects[] = {InputPath.str(), OutputPath.str(), {""}};
480
2
  std::string ErrMsg;
481
2
  int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV.data(),
482
2
                               /*env=*/nullptr, Redirects, /*secondsToWait=*/0,
483
2
                               /*memoryLimit=*/0, &ErrMsg);
484
2
  if (RC) {
485
0
    error(ErrMsg, ViewOpts.DemanglerOpts[0]);
486
0
    return;
487
0
  }
488
2
489
2
  // Parse the demangler's output.
490
2
  auto BufOrError = MemoryBuffer::getFile(OutputPath);
491
2
  if (!BufOrError) {
492
0
    error(OutputPath, BufOrError.getError().message());
493
0
    return;
494
0
  }
495
2
496
2
  std::unique_ptr<MemoryBuffer> DemanglerBuf = std::move(*BufOrError);
497
2
498
2
  SmallVector<StringRef, 8> Symbols;
499
2
  StringRef DemanglerData = DemanglerBuf->getBuffer();
500
2
  DemanglerData.split(Symbols, '\n', /*MaxSplit=*/NumSymbols,
501
2
                      /*KeepEmpty=*/false);
502
2
  if (Symbols.size() != NumSymbols) {
503
0
    error("Demangler did not provide expected number of symbols");
504
0
    return;
505
0
  }
506
2
507
2
  // Cache the demangled names.
508
2
  unsigned I = 0;
509
2
  for (const auto &Function : Coverage.getCoveredFunctions())
510
6
    // On Windows, lines in the demangler's output file end with "\r\n".
511
6
    // Splitting by '\n' keeps '\r's, so cut them now.
512
6
    DC.DemangledNames[Function.Name] = Symbols[I++].rtrim();
513
2
}
514
515
void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
516
                                           CoverageMapping *Coverage,
517
                                           CoveragePrinter *Printer,
518
67
                                           bool ShowFilenames) {
519
67
  auto View = createSourceFileView(SourceFile, *Coverage);
520
67
  if (!View) {
521
8
    warning("The file '" + SourceFile + "' isn't covered.");
522
8
    return;
523
8
  }
524
59
525
59
  auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false);
526
59
  if (Error E = OSOrErr.takeError()) {
527
0
    error("Could not create view file!", toString(std::move(E)));
528
0
    return;
529
0
  }
530
59
  auto OS = std::move(OSOrErr.get());
531
59
532
59
  View->print(*OS.get(), /*Wholefile=*/true,
533
59
              /*ShowSourceName=*/ShowFilenames,
534
59
              /*ShowTitle=*/ViewOpts.hasOutputDirectory());
535
59
  Printer->closeViewFile(std::move(OS));
536
59
}
537
538
64
int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
539
64
  cl::opt<std::string> CovFilename(
540
64
      cl::Positional, cl::desc("Covered executable or object file."));
541
64
542
64
  cl::list<std::string> CovFilenames(
543
64
      "object", cl::desc("Coverage executable or object file"), cl::ZeroOrMore,
544
64
      cl::CommaSeparated);
545
64
546
64
  cl::list<std::string> InputSourceFiles(
547
64
      cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
548
64
549
64
  cl::opt<bool> DebugDumpCollectedPaths(
550
64
      "dump-collected-paths", cl::Optional, cl::Hidden,
551
64
      cl::desc("Show the collected paths to source files"));
552
64
553
64
  cl::opt<std::string, true> PGOFilename(
554
64
      "instr-profile", cl::Required, cl::location(this->PGOFilename),
555
64
      cl::desc(
556
64
          "File with the profile data obtained after an instrumented run"));
557
64
558
64
  cl::list<std::string> Arches(
559
64
      "arch", cl::desc("architectures of the coverage mapping binaries"));
560
64
561
64
  cl::opt<bool> DebugDump("dump", cl::Optional,
562
64
                          cl::desc("Show internal debug dump"));
563
64
564
64
  cl::opt<CoverageViewOptions::OutputFormat> Format(
565
64
      "format", cl::desc("Output format for line-based coverage reports"),
566
64
      cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text, "text",
567
64
                            "Text output"),
568
64
                 clEnumValN(CoverageViewOptions::OutputFormat::HTML, "html",
569
64
                            "HTML output")),
570
64
      cl::init(CoverageViewOptions::OutputFormat::Text));
571
64
572
64
  cl::opt<std::string> PathRemap(
573
64
      "path-equivalence", cl::Optional,
574
64
      cl::desc("<from>,<to> Map coverage data paths to local source file "
575
64
               "paths"));
576
64
577
64
  cl::OptionCategory FilteringCategory("Function filtering options");
578
64
579
64
  cl::list<std::string> NameFilters(
580
64
      "name", cl::Optional,
581
64
      cl::desc("Show code coverage only for functions with the given name"),
582
64
      cl::ZeroOrMore, cl::cat(FilteringCategory));
583
64
584
64
  cl::list<std::string> NameFilterFiles(
585
64
      "name-whitelist", cl::Optional,
586
64
      cl::desc("Show code coverage only for functions listed in the given "
587
64
               "file"),
588
64
      cl::ZeroOrMore, cl::cat(FilteringCategory));
589
64
590
64
  cl::list<std::string> NameRegexFilters(
591
64
      "name-regex", cl::Optional,
592
64
      cl::desc("Show code coverage only for functions that match the given "
593
64
               "regular expression"),
594
64
      cl::ZeroOrMore, cl::cat(FilteringCategory));
595
64
596
64
  cl::opt<double> RegionCoverageLtFilter(
597
64
      "region-coverage-lt", cl::Optional,
598
64
      cl::desc("Show code coverage only for functions with region coverage "
599
64
               "less than the given threshold"),
600
64
      cl::cat(FilteringCategory));
601
64
602
64
  cl::opt<double> RegionCoverageGtFilter(
603
64
      "region-coverage-gt", cl::Optional,
604
64
      cl::desc("Show code coverage only for functions with region coverage "
605
64
               "greater than the given threshold"),
606
64
      cl::cat(FilteringCategory));
607
64
608
64
  cl::opt<double> LineCoverageLtFilter(
609
64
      "line-coverage-lt", cl::Optional,
610
64
      cl::desc("Show code coverage only for functions with line coverage less "
611
64
               "than the given threshold"),
612
64
      cl::cat(FilteringCategory));
613
64
614
64
  cl::opt<double> LineCoverageGtFilter(
615
64
      "line-coverage-gt", cl::Optional,
616
64
      cl::desc("Show code coverage only for functions with line coverage "
617
64
               "greater than the given threshold"),
618
64
      cl::cat(FilteringCategory));
619
64
620
64
  cl::opt<cl::boolOrDefault> UseColor(
621
64
      "use-color", cl::desc("Emit colored output (default=autodetect)"),
622
64
      cl::init(cl::BOU_UNSET));
623
64
624
64
  cl::list<std::string> DemanglerOpts(
625
64
      "Xdemangler", cl::desc("<demangler-path>|<demangler-option>"));
626
64
627
64
  cl::opt<bool> RegionSummary(
628
64
      "show-region-summary", cl::Optional,
629
64
      cl::desc("Show region statistics in summary table"),
630
64
      cl::init(true));
631
64
632
64
  cl::opt<bool> InstantiationSummary(
633
64
      "show-instantiation-summary", cl::Optional,
634
64
      cl::desc("Show instantiation statistics in summary table"));
635
64
636
64
  cl::opt<bool> SummaryOnly(
637
64
      "summary-only", cl::Optional,
638
64
      cl::desc("Export only summary information for each source file"));
639
64
640
64
  cl::opt<unsigned> NumThreads(
641
64
      "num-threads", cl::init(0),
642
64
      cl::desc("Number of merge threads to use (default: autodetect)"));
643
64
  cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"),
644
64
                        cl::aliasopt(NumThreads));
645
64
646
64
  auto commandLineParser = [&, this](int argc, const char **argv) -> int {
647
64
    cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
648
64
    ViewOpts.Debug = DebugDump;
649
64
650
64
    if (!CovFilename.empty())
651
63
      ObjectFilenames.emplace_back(CovFilename);
652
64
    for (const std::string &Filename : CovFilenames)
653
1
      ObjectFilenames.emplace_back(Filename);
654
64
    if (ObjectFilenames.empty()) {
655
1
      errs() << "No filenames specified!\n";
656
1
      ::exit(1);
657
1
    }
658
63
659
63
    ViewOpts.Format = Format;
660
63
    switch (ViewOpts.Format) {
661
63
    case CoverageViewOptions::OutputFormat::Text:
662
51
      ViewOpts.Colors = UseColor == cl::BOU_UNSET
663
51
                            ? sys::Process::StandardOutHasColors()
664
51
                            : 
UseColor == cl::BOU_TRUE0
;
665
51
      break;
666
63
    case CoverageViewOptions::OutputFormat::HTML:
667
12
      if (UseColor == cl::BOU_FALSE)
668
0
        errs() << "Color output cannot be disabled when generating html.\n";
669
12
      ViewOpts.Colors = true;
670
12
      break;
671
63
    }
672
63
673
63
    // If path-equivalence was given and is a comma seperated pair then set
674
63
    // PathRemapping.
675
63
    auto EquivPair = StringRef(PathRemap).split(',');
676
63
    if (!(EquivPair.first.empty() && 
EquivPair.second.empty()19
))
677
44
      PathRemapping = EquivPair;
678
63
679
63
    // If a demangler is supplied, check if it exists and register it.
680
63
    if (DemanglerOpts.size()) {
681
2
      auto DemanglerPathOrErr = sys::findProgramByName(DemanglerOpts[0]);
682
2
      if (!DemanglerPathOrErr) {
683
0
        error("Could not find the demangler!",
684
0
              DemanglerPathOrErr.getError().message());
685
0
        return 1;
686
0
      }
687
2
      DemanglerOpts[0] = *DemanglerPathOrErr;
688
2
      ViewOpts.DemanglerOpts.swap(DemanglerOpts);
689
2
    }
690
63
691
63
    // Read in -name-whitelist files.
692
63
    if (!NameFilterFiles.empty()) {
693
1
      std::string SpecialCaseListErr;
694
1
      NameWhitelist =
695
1
          SpecialCaseList::create(NameFilterFiles, SpecialCaseListErr);
696
1
      if (!NameWhitelist)
697
0
        error(SpecialCaseListErr);
698
1
    }
699
63
700
63
    // Create the function filters
701
63
    if (!NameFilters.empty() || 
NameWhitelist52
||
!NameRegexFilters.empty()51
) {
702
13
      auto NameFilterer = llvm::make_unique<CoverageFilters>();
703
13
      for (const auto &Name : NameFilters)
704
13
        NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name));
705
13
      if (NameWhitelist)
706
1
        NameFilterer->push_back(
707
1
            llvm::make_unique<NameWhitelistCoverageFilter>(*NameWhitelist));
708
13
      for (const auto &Regex : NameRegexFilters)
709
1
        NameFilterer->push_back(
710
1
            llvm::make_unique<NameRegexCoverageFilter>(Regex));
711
13
      Filters.push_back(std::move(NameFilterer));
712
13
    }
713
63
    if (RegionCoverageLtFilter.getNumOccurrences() ||
714
63
        RegionCoverageGtFilter.getNumOccurrences() ||
715
63
        LineCoverageLtFilter.getNumOccurrences() ||
716
63
        LineCoverageGtFilter.getNumOccurrences()) {
717
0
      auto StatFilterer = llvm::make_unique<CoverageFilters>();
718
0
      if (RegionCoverageLtFilter.getNumOccurrences())
719
0
        StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
720
0
            RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
721
0
      if (RegionCoverageGtFilter.getNumOccurrences())
722
0
        StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
723
0
            RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
724
0
      if (LineCoverageLtFilter.getNumOccurrences())
725
0
        StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
726
0
            LineCoverageFilter::LessThan, LineCoverageLtFilter));
727
0
      if (LineCoverageGtFilter.getNumOccurrences())
728
0
        StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
729
0
            RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
730
0
      Filters.push_back(std::move(StatFilterer));
731
0
    }
732
63
733
63
    if (!Arches.empty()) {
734
3
      for (const std::string &Arch : Arches) {
735
3
        if (Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
736
0
          error("Unknown architecture: " + Arch);
737
0
          return 1;
738
0
        }
739
3
        CoverageArches.emplace_back(Arch);
740
3
      }
741
2
      if (CoverageArches.size() != ObjectFilenames.size()) {
742
0
        error("Number of architectures doesn't match the number of objects");
743
0
        return 1;
744
0
      }
745
63
    }
746
63
747
63
    for (const std::string &File : InputSourceFiles)
748
43
      collectPaths(File);
749
63
750
63
    if (DebugDumpCollectedPaths) {
751
3
      for (const std::string &SF : SourceFiles)
752
12
        outs() << SF << '\n';
753
3
      ::exit(0);
754
3
    }
755
60
756
60
    ViewOpts.ShowRegionSummary = RegionSummary;
757
60
    ViewOpts.ShowInstantiationSummary = InstantiationSummary;
758
60
    ViewOpts.ExportSummaryOnly = SummaryOnly;
759
60
    ViewOpts.NumThreads = NumThreads;
760
60
761
60
    return 0;
762
60
  };
763
64
764
64
  switch (Cmd) {
765
64
  case Show:
766
42
    return doShow(argc, argv, commandLineParser);
767
64
  case Report:
768
12
    return doReport(argc, argv, commandLineParser);
769
64
  case Export:
770
10
    return doExport(argc, argv, commandLineParser);
771
0
  }
772
0
  return 0;
773
0
}
774
775
int CodeCoverageTool::doShow(int argc, const char **argv,
776
42
                             CommandLineParserType commandLineParser) {
777
42
778
42
  cl::OptionCategory ViewCategory("Viewing options");
779
42
780
42
  cl::opt<bool> ShowLineExecutionCounts(
781
42
      "show-line-counts", cl::Optional,
782
42
      cl::desc("Show the execution counts for each line"), cl::init(true),
783
42
      cl::cat(ViewCategory));
784
42
785
42
  cl::opt<bool> ShowRegions(
786
42
      "show-regions", cl::Optional,
787
42
      cl::desc("Show the execution counts for each region"),
788
42
      cl::cat(ViewCategory));
789
42
790
42
  cl::opt<bool> ShowBestLineRegionsCounts(
791
42
      "show-line-counts-or-regions", cl::Optional,
792
42
      cl::desc("Show the execution counts for each line, or the execution "
793
42
               "counts for each region on lines that have multiple regions"),
794
42
      cl::cat(ViewCategory));
795
42
796
42
  cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
797
42
                               cl::desc("Show expanded source regions"),
798
42
                               cl::cat(ViewCategory));
799
42
800
42
  cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
801
42
                                   cl::desc("Show function instantiations"),
802
42
                                   cl::init(true), cl::cat(ViewCategory));
803
42
804
42
  cl::opt<std::string> ShowOutputDirectory(
805
42
      "output-dir", cl::init(""),
806
42
      cl::desc("Directory in which coverage information is written out"));
807
42
  cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
808
42
                                 cl::aliasopt(ShowOutputDirectory));
809
42
810
42
  cl::opt<uint32_t> TabSize(
811
42
      "tab-size", cl::init(2),
812
42
      cl::desc(
813
42
          "Set tab expansion size for html coverage reports (default = 2)"));
814
42
815
42
  cl::opt<std::string> ProjectTitle(
816
42
      "project-title", cl::Optional,
817
42
      cl::desc("Set project title for the coverage report"));
818
42
819
42
  auto Err = commandLineParser(argc, argv);
820
42
  if (Err)
821
0
    return Err;
822
42
823
42
  ViewOpts.ShowLineNumbers = true;
824
42
  ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
825
42
                           
!ShowRegions39
||
ShowBestLineRegionsCounts0
;
826
42
  ViewOpts.ShowRegionMarkers = ShowRegions || 
ShowBestLineRegionsCounts39
;
827
42
  ViewOpts.ShowExpandedRegions = ShowExpansions;
828
42
  ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
829
42
  ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
830
42
  ViewOpts.TabSize = TabSize;
831
42
  ViewOpts.ProjectTitle = ProjectTitle;
832
42
833
42
  if (ViewOpts.hasOutputDirectory()) {
834
17
    if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) {
835
0
      error("Could not create output directory!", E.message());
836
0
      return 1;
837
0
    }
838
42
  }
839
42
840
42
  sys::fs::file_status Status;
841
42
  if (sys::fs::status(PGOFilename, Status)) {
842
0
    error("profdata file error: can not get the file status. \n");
843
0
    return 1;
844
0
  }
845
42
846
42
  auto ModifiedTime = Status.getLastModificationTime();
847
42
  std::string ModifiedTimeStr = to_string(ModifiedTime);
848
42
  size_t found = ModifiedTimeStr.rfind(':');
849
42
  ViewOpts.CreatedTimeStr = (found != std::string::npos)
850
42
                                ? 
"Created: " + ModifiedTimeStr.substr(0, found)39
851
42
                                : 
"Created: " + ModifiedTimeStr3
;
852
42
853
42
  auto Coverage = load();
854
42
  if (!Coverage)
855
0
    return 1;
856
42
857
42
  auto Printer = CoveragePrinter::create(ViewOpts);
858
42
859
42
  if (SourceFiles.empty())
860
18
    // Get the source files from the function coverage mapping.
861
18
    for (StringRef Filename : Coverage->getUniqueSourceFiles())
862
62
      SourceFiles.push_back(Filename);
863
42
864
42
  // Create an index out of the source files.
865
42
  if (ViewOpts.hasOutputDirectory()) {
866
17
    if (Error E = Printer->createIndexFile(SourceFiles, *Coverage, Filters)) {
867
1
      error("Could not create index file!", toString(std::move(E)));
868
1
      return 1;
869
1
    }
870
41
  }
871
41
872
41
  if (!Filters.empty()) {
873
13
    // Build the map of filenames to functions.
874
13
    std::map<llvm::StringRef, std::vector<const FunctionRecord *>>
875
13
        FilenameFunctionMap;
876
13
    for (const auto &SourceFile : SourceFiles)
877
17
      for (const auto &Function : Coverage->getCoveredFunctions(SourceFile))
878
33
        if (Filters.matches(*Coverage.get(), Function))
879
16
          FilenameFunctionMap[SourceFile].push_back(&Function);
880
13
881
13
    // Only print filter matching functions for each file.
882
13
    for (const auto &FileFunc : FilenameFunctionMap) {
883
13
      StringRef File = FileFunc.first;
884
13
      const auto &Functions = FileFunc.second;
885
13
886
13
      auto OSOrErr = Printer->createViewFile(File, /*InToplevel=*/false);
887
13
      if (Error E = OSOrErr.takeError()) {
888
0
        error("Could not create view file!", toString(std::move(E)));
889
0
        return 1;
890
0
      }
891
13
      auto OS = std::move(OSOrErr.get());
892
13
893
13
      bool ShowTitle = ViewOpts.hasOutputDirectory();
894
16
      for (const auto *Function : Functions) {
895
16
        auto FunctionView = createFunctionView(*Function, *Coverage);
896
16
        if (!FunctionView) {
897
3
          warning("Could not read coverage for '" + Function->Name + "'.");
898
3
          continue;
899
3
        }
900
13
        FunctionView->print(*OS.get(), /*WholeFile=*/false,
901
13
                            /*ShowSourceName=*/true, ShowTitle);
902
13
        ShowTitle = false;
903
13
      }
904
13
905
13
      Printer->closeViewFile(std::move(OS));
906
13
    }
907
13
    return 0;
908
28
  }
909
28
910
28
  // Show files
911
28
  bool ShowFilenames =
912
28
      (SourceFiles.size() != 1) || 
ViewOpts.hasOutputDirectory()14
||
913
28
      
(ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML)9
;
914
28
915
28
  auto NumThreads = ViewOpts.NumThreads;
916
28
917
28
  // If NumThreads is not specified, auto-detect a good default.
918
28
  if (NumThreads == 0)
919
16
    NumThreads =
920
16
        std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(),
921
16
                              unsigned(SourceFiles.size())));
922
28
923
28
  if (!ViewOpts.hasOutputDirectory() || 
NumThreads == 19
) {
924
23
    for (const std::string &SourceFile : SourceFiles)
925
59
      writeSourceFileView(SourceFile, Coverage.get(), Printer.get(),
926
59
                          ShowFilenames);
927
23
  } else {
928
5
    // In -output-dir mode, it's safe to use multiple threads to print files.
929
5
    ThreadPool Pool(NumThreads);
930
5
    for (const std::string &SourceFile : SourceFiles)
931
8
      Pool.async(&CodeCoverageTool::writeSourceFileView, this, SourceFile,
932
8
                 Coverage.get(), Printer.get(), ShowFilenames);
933
5
    Pool.wait();
934
5
  }
935
28
936
28
  return 0;
937
28
}
938
939
int CodeCoverageTool::doReport(int argc, const char **argv,
940
12
                               CommandLineParserType commandLineParser) {
941
12
  cl::opt<bool> ShowFunctionSummaries(
942
12
      "show-functions", cl::Optional, cl::init(false),
943
12
      cl::desc("Show coverage summaries for each function"));
944
12
945
12
  auto Err = commandLineParser(argc, argv);
946
12
  if (Err)
947
0
    return Err;
948
12
949
12
  if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) {
950
1
    error("HTML output for summary reports is not yet supported.");
951
1
    return 1;
952
1
  }
953
11
954
11
  auto Coverage = load();
955
11
  if (!Coverage)
956
1
    return 1;
957
10
958
10
  CoverageReport Report(ViewOpts, *Coverage.get());
959
10
  if (!ShowFunctionSummaries) {
960
6
    if (SourceFiles.empty())
961
6
      Report.renderFileReports(llvm::outs());
962
0
    else
963
0
      Report.renderFileReports(llvm::outs(), SourceFiles);
964
6
  } else {
965
4
    if (SourceFiles.empty()) {
966
1
      error("Source files must be specified when -show-functions=true is "
967
1
            "specified");
968
1
      return 1;
969
1
    }
970
3
971
3
    Report.renderFunctionReports(SourceFiles, DC, llvm::outs());
972
3
  }
973
10
  
return 09
;
974
10
}
975
976
int CodeCoverageTool::doExport(int argc, const char **argv,
977
10
                               CommandLineParserType commandLineParser) {
978
10
979
10
  auto Err = commandLineParser(argc, argv);
980
10
  if (Err)
981
0
    return Err;
982
10
983
10
  if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text) {
984
0
    error("Coverage data can only be exported as textual JSON.");
985
0
    return 1;
986
0
  }
987
10
988
10
  auto Coverage = load();
989
10
  if (!Coverage) {
990
0
    error("Could not load coverage information");
991
0
    return 1;
992
0
  }
993
10
994
10
  auto Exporter = CoverageExporterJson(*Coverage.get(), ViewOpts, outs());
995
10
996
10
  if (SourceFiles.empty())
997
9
    Exporter.renderRoot();
998
1
  else
999
1
    Exporter.renderRoot(SourceFiles);
1000
10
1001
10
  return 0;
1002
10
}
1003
1004
42
int showMain(int argc, const char *argv[]) {
1005
42
  CodeCoverageTool Tool;
1006
42
  return Tool.run(CodeCoverageTool::Show, argc, argv);
1007
42
}
1008
1009
12
int reportMain(int argc, const char *argv[]) {
1010
12
  CodeCoverageTool Tool;
1011
12
  return Tool.run(CodeCoverageTool::Report, argc, argv);
1012
12
}
1013
1014
10
int exportMain(int argc, const char *argv[]) {
1015
10
  CodeCoverageTool Tool;
1016
10
  return Tool.run(CodeCoverageTool::Export, argc, argv);
1017
10
}