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