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