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