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