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