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