Coverage Report

Created: 2019-01-18 03:29

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