109467b48Spatrick //===- CodeCoverage.cpp - Coverage tool based on profiling instrumentation-===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // The 'CodeCoverageTool' class implements a command line tool to analyze and
1009467b48Spatrick // report coverage information using the profiling instrumentation and code
1109467b48Spatrick // coverage mapping.
1209467b48Spatrick //
1309467b48Spatrick //===----------------------------------------------------------------------===//
1409467b48Spatrick 
1509467b48Spatrick #include "CoverageExporterJson.h"
1609467b48Spatrick #include "CoverageExporterLcov.h"
1709467b48Spatrick #include "CoverageFilters.h"
1809467b48Spatrick #include "CoverageReport.h"
1909467b48Spatrick #include "CoverageSummaryInfo.h"
2009467b48Spatrick #include "CoverageViewOptions.h"
2109467b48Spatrick #include "RenderingSupport.h"
2209467b48Spatrick #include "SourceCoverageView.h"
2309467b48Spatrick #include "llvm/ADT/SmallString.h"
2409467b48Spatrick #include "llvm/ADT/StringRef.h"
2509467b48Spatrick #include "llvm/ADT/Triple.h"
26*d415bd75Srobert #include "llvm/Debuginfod/BuildIDFetcher.h"
27*d415bd75Srobert #include "llvm/Debuginfod/Debuginfod.h"
28*d415bd75Srobert #include "llvm/Debuginfod/HTTPClient.h"
29*d415bd75Srobert #include "llvm/Object/BuildID.h"
3009467b48Spatrick #include "llvm/ProfileData/Coverage/CoverageMapping.h"
3109467b48Spatrick #include "llvm/ProfileData/InstrProfReader.h"
3209467b48Spatrick #include "llvm/Support/CommandLine.h"
3309467b48Spatrick #include "llvm/Support/FileSystem.h"
3409467b48Spatrick #include "llvm/Support/Format.h"
3509467b48Spatrick #include "llvm/Support/MemoryBuffer.h"
3609467b48Spatrick #include "llvm/Support/Path.h"
3709467b48Spatrick #include "llvm/Support/Process.h"
3809467b48Spatrick #include "llvm/Support/Program.h"
3909467b48Spatrick #include "llvm/Support/ScopedPrinter.h"
40097a140dSpatrick #include "llvm/Support/SpecialCaseList.h"
4109467b48Spatrick #include "llvm/Support/ThreadPool.h"
4209467b48Spatrick #include "llvm/Support/Threading.h"
4309467b48Spatrick #include "llvm/Support/ToolOutputFile.h"
4409467b48Spatrick #include "llvm/Support/VirtualFileSystem.h"
4509467b48Spatrick 
4609467b48Spatrick #include <functional>
4709467b48Spatrick #include <map>
48*d415bd75Srobert #include <optional>
4909467b48Spatrick #include <system_error>
5009467b48Spatrick 
5109467b48Spatrick using namespace llvm;
5209467b48Spatrick using namespace coverage;
5309467b48Spatrick 
5409467b48Spatrick void exportCoverageDataToJson(const coverage::CoverageMapping &CoverageMapping,
5509467b48Spatrick                               const CoverageViewOptions &Options,
5609467b48Spatrick                               raw_ostream &OS);
5709467b48Spatrick 
5809467b48Spatrick namespace {
5909467b48Spatrick /// The implementation of the coverage tool.
6009467b48Spatrick class CodeCoverageTool {
6109467b48Spatrick public:
6209467b48Spatrick   enum Command {
6309467b48Spatrick     /// The show command.
6409467b48Spatrick     Show,
6509467b48Spatrick     /// The report command.
6609467b48Spatrick     Report,
6709467b48Spatrick     /// The export command.
6809467b48Spatrick     Export
6909467b48Spatrick   };
7009467b48Spatrick 
7109467b48Spatrick   int run(Command Cmd, int argc, const char **argv);
7209467b48Spatrick 
7309467b48Spatrick private:
7409467b48Spatrick   /// Print the error message to the error output stream.
7509467b48Spatrick   void error(const Twine &Message, StringRef Whence = "");
7609467b48Spatrick 
7709467b48Spatrick   /// Print the warning message to the error output stream.
7809467b48Spatrick   void warning(const Twine &Message, StringRef Whence = "");
7909467b48Spatrick 
8009467b48Spatrick   /// Convert \p Path into an absolute path and append it to the list
8109467b48Spatrick   /// of collected paths.
8209467b48Spatrick   void addCollectedPath(const std::string &Path);
8309467b48Spatrick 
8409467b48Spatrick   /// If \p Path is a regular file, collect the path. If it's a
8509467b48Spatrick   /// directory, recursively collect all of the paths within the directory.
8609467b48Spatrick   void collectPaths(const std::string &Path);
8709467b48Spatrick 
8873471bf0Spatrick   /// Check if the two given files are the same file.
8973471bf0Spatrick   bool isEquivalentFile(StringRef FilePath1, StringRef FilePath2);
9073471bf0Spatrick 
9173471bf0Spatrick   /// Retrieve a file status with a cache.
92*d415bd75Srobert   std::optional<sys::fs::file_status> getFileStatus(StringRef FilePath);
9373471bf0Spatrick 
9409467b48Spatrick   /// Return a memory buffer for the given source file.
9509467b48Spatrick   ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
9609467b48Spatrick 
9709467b48Spatrick   /// Create source views for the expansions of the view.
9809467b48Spatrick   void attachExpansionSubViews(SourceCoverageView &View,
9909467b48Spatrick                                ArrayRef<ExpansionRecord> Expansions,
10009467b48Spatrick                                const CoverageMapping &Coverage);
10109467b48Spatrick 
10273471bf0Spatrick   /// Create source views for the branches of the view.
10373471bf0Spatrick   void attachBranchSubViews(SourceCoverageView &View, StringRef SourceName,
10473471bf0Spatrick                             ArrayRef<CountedRegion> Branches,
10573471bf0Spatrick                             const MemoryBuffer &File,
10673471bf0Spatrick                             CoverageData &CoverageInfo);
10773471bf0Spatrick 
10809467b48Spatrick   /// Create the source view of a particular function.
10909467b48Spatrick   std::unique_ptr<SourceCoverageView>
11009467b48Spatrick   createFunctionView(const FunctionRecord &Function,
11109467b48Spatrick                      const CoverageMapping &Coverage);
11209467b48Spatrick 
11309467b48Spatrick   /// Create the main source view of a particular source file.
11409467b48Spatrick   std::unique_ptr<SourceCoverageView>
11509467b48Spatrick   createSourceFileView(StringRef SourceFile, const CoverageMapping &Coverage);
11609467b48Spatrick 
11709467b48Spatrick   /// Load the coverage mapping data. Return nullptr if an error occurred.
11809467b48Spatrick   std::unique_ptr<CoverageMapping> load();
11909467b48Spatrick 
12009467b48Spatrick   /// Create a mapping from files in the Coverage data to local copies
12109467b48Spatrick   /// (path-equivalence).
12209467b48Spatrick   void remapPathNames(const CoverageMapping &Coverage);
12309467b48Spatrick 
12409467b48Spatrick   /// Remove input source files which aren't mapped by \p Coverage.
12509467b48Spatrick   void removeUnmappedInputs(const CoverageMapping &Coverage);
12609467b48Spatrick 
12709467b48Spatrick   /// If a demangler is available, demangle all symbol names.
12809467b48Spatrick   void demangleSymbols(const CoverageMapping &Coverage);
12909467b48Spatrick 
13009467b48Spatrick   /// Write out a source file view to the filesystem.
13109467b48Spatrick   void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage,
13209467b48Spatrick                            CoveragePrinter *Printer, bool ShowFilenames);
13309467b48Spatrick 
13409467b48Spatrick   typedef llvm::function_ref<int(int, const char **)> CommandLineParserType;
13509467b48Spatrick 
13609467b48Spatrick   int doShow(int argc, const char **argv,
13709467b48Spatrick              CommandLineParserType commandLineParser);
13809467b48Spatrick 
13909467b48Spatrick   int doReport(int argc, const char **argv,
14009467b48Spatrick                CommandLineParserType commandLineParser);
14109467b48Spatrick 
14209467b48Spatrick   int doExport(int argc, const char **argv,
14309467b48Spatrick                CommandLineParserType commandLineParser);
14409467b48Spatrick 
14509467b48Spatrick   std::vector<StringRef> ObjectFilenames;
14609467b48Spatrick   CoverageViewOptions ViewOpts;
14709467b48Spatrick   CoverageFiltersMatchAll Filters;
14809467b48Spatrick   CoverageFilters IgnoreFilenameFilters;
14909467b48Spatrick 
15073471bf0Spatrick   /// True if InputSourceFiles are provided.
15173471bf0Spatrick   bool HadSourceFiles = false;
15273471bf0Spatrick 
15309467b48Spatrick   /// The path to the indexed profile.
15409467b48Spatrick   std::string PGOFilename;
15509467b48Spatrick 
15609467b48Spatrick   /// A list of input source files.
15709467b48Spatrick   std::vector<std::string> SourceFiles;
15809467b48Spatrick 
15909467b48Spatrick   /// In -path-equivalence mode, this maps the absolute paths from the coverage
16009467b48Spatrick   /// mapping data to the input source files.
16109467b48Spatrick   StringMap<std::string> RemappedFilenames;
16209467b48Spatrick 
16309467b48Spatrick   /// The coverage data path to be remapped from, and the source path to be
16409467b48Spatrick   /// remapped to, when using -path-equivalence.
165*d415bd75Srobert   std::optional<std::pair<std::string, std::string>> PathRemapping;
16609467b48Spatrick 
16773471bf0Spatrick   /// File status cache used when finding the same file.
168*d415bd75Srobert   StringMap<std::optional<sys::fs::file_status>> FileStatusCache;
16973471bf0Spatrick 
17009467b48Spatrick   /// The architecture the coverage mapping data targets.
17109467b48Spatrick   std::vector<StringRef> CoverageArches;
17209467b48Spatrick 
17309467b48Spatrick   /// A cache for demangled symbols.
17409467b48Spatrick   DemangleCache DC;
17509467b48Spatrick 
17609467b48Spatrick   /// A lock which guards printing to stderr.
17709467b48Spatrick   std::mutex ErrsLock;
17809467b48Spatrick 
17909467b48Spatrick   /// A container for input source file buffers.
18009467b48Spatrick   std::mutex LoadedSourceFilesLock;
18109467b48Spatrick   std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
18209467b48Spatrick       LoadedSourceFiles;
18309467b48Spatrick 
184*d415bd75Srobert   /// Allowlist from -name-allowlist to be used for filtering.
185*d415bd75Srobert   std::unique_ptr<SpecialCaseList> NameAllowlist;
186*d415bd75Srobert 
187*d415bd75Srobert   std::unique_ptr<object::BuildIDFetcher> BIDFetcher;
18809467b48Spatrick };
18909467b48Spatrick }
19009467b48Spatrick 
getErrorString(const Twine & Message,StringRef Whence,bool Warning)19109467b48Spatrick static std::string getErrorString(const Twine &Message, StringRef Whence,
19209467b48Spatrick                                   bool Warning) {
19309467b48Spatrick   std::string Str = (Warning ? "warning" : "error");
19409467b48Spatrick   Str += ": ";
19509467b48Spatrick   if (!Whence.empty())
19609467b48Spatrick     Str += Whence.str() + ": ";
19709467b48Spatrick   Str += Message.str() + "\n";
19809467b48Spatrick   return Str;
19909467b48Spatrick }
20009467b48Spatrick 
error(const Twine & Message,StringRef Whence)20109467b48Spatrick void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
20209467b48Spatrick   std::unique_lock<std::mutex> Guard{ErrsLock};
20309467b48Spatrick   ViewOpts.colored_ostream(errs(), raw_ostream::RED)
20409467b48Spatrick       << getErrorString(Message, Whence, false);
20509467b48Spatrick }
20609467b48Spatrick 
warning(const Twine & Message,StringRef Whence)20709467b48Spatrick void CodeCoverageTool::warning(const Twine &Message, StringRef Whence) {
20809467b48Spatrick   std::unique_lock<std::mutex> Guard{ErrsLock};
20909467b48Spatrick   ViewOpts.colored_ostream(errs(), raw_ostream::RED)
21009467b48Spatrick       << getErrorString(Message, Whence, true);
21109467b48Spatrick }
21209467b48Spatrick 
addCollectedPath(const std::string & Path)21309467b48Spatrick void CodeCoverageTool::addCollectedPath(const std::string &Path) {
21409467b48Spatrick   SmallString<128> EffectivePath(Path);
21509467b48Spatrick   if (std::error_code EC = sys::fs::make_absolute(EffectivePath)) {
21609467b48Spatrick     error(EC.message(), Path);
21709467b48Spatrick     return;
21809467b48Spatrick   }
219*d415bd75Srobert   sys::path::remove_dots(EffectivePath, /*remove_dot_dot=*/true);
22009467b48Spatrick   if (!IgnoreFilenameFilters.matchesFilename(EffectivePath))
22109467b48Spatrick     SourceFiles.emplace_back(EffectivePath.str());
22273471bf0Spatrick   HadSourceFiles = !SourceFiles.empty();
22309467b48Spatrick }
22409467b48Spatrick 
collectPaths(const std::string & Path)22509467b48Spatrick void CodeCoverageTool::collectPaths(const std::string &Path) {
22609467b48Spatrick   llvm::sys::fs::file_status Status;
22709467b48Spatrick   llvm::sys::fs::status(Path, Status);
22809467b48Spatrick   if (!llvm::sys::fs::exists(Status)) {
22909467b48Spatrick     if (PathRemapping)
23009467b48Spatrick       addCollectedPath(Path);
23109467b48Spatrick     else
23209467b48Spatrick       warning("Source file doesn't exist, proceeded by ignoring it.", Path);
23309467b48Spatrick     return;
23409467b48Spatrick   }
23509467b48Spatrick 
23609467b48Spatrick   if (llvm::sys::fs::is_regular_file(Status)) {
23709467b48Spatrick     addCollectedPath(Path);
23809467b48Spatrick     return;
23909467b48Spatrick   }
24009467b48Spatrick 
24109467b48Spatrick   if (llvm::sys::fs::is_directory(Status)) {
24209467b48Spatrick     std::error_code EC;
24309467b48Spatrick     for (llvm::sys::fs::recursive_directory_iterator F(Path, EC), E;
24409467b48Spatrick          F != E; F.increment(EC)) {
24509467b48Spatrick 
24609467b48Spatrick       auto Status = F->status();
24709467b48Spatrick       if (!Status) {
24809467b48Spatrick         warning(Status.getError().message(), F->path());
24909467b48Spatrick         continue;
25009467b48Spatrick       }
25109467b48Spatrick 
25209467b48Spatrick       if (Status->type() == llvm::sys::fs::file_type::regular_file)
25309467b48Spatrick         addCollectedPath(F->path());
25409467b48Spatrick     }
25509467b48Spatrick   }
25609467b48Spatrick }
25709467b48Spatrick 
258*d415bd75Srobert std::optional<sys::fs::file_status>
getFileStatus(StringRef FilePath)25973471bf0Spatrick CodeCoverageTool::getFileStatus(StringRef FilePath) {
26073471bf0Spatrick   auto It = FileStatusCache.try_emplace(FilePath);
26173471bf0Spatrick   auto &CachedStatus = It.first->getValue();
26273471bf0Spatrick   if (!It.second)
26373471bf0Spatrick     return CachedStatus;
26473471bf0Spatrick 
26573471bf0Spatrick   sys::fs::file_status Status;
26673471bf0Spatrick   if (!sys::fs::status(FilePath, Status))
26773471bf0Spatrick     CachedStatus = Status;
26873471bf0Spatrick   return CachedStatus;
26973471bf0Spatrick }
27073471bf0Spatrick 
isEquivalentFile(StringRef FilePath1,StringRef FilePath2)27173471bf0Spatrick bool CodeCoverageTool::isEquivalentFile(StringRef FilePath1,
27273471bf0Spatrick                                         StringRef FilePath2) {
27373471bf0Spatrick   auto Status1 = getFileStatus(FilePath1);
27473471bf0Spatrick   auto Status2 = getFileStatus(FilePath2);
275*d415bd75Srobert   return Status1 && Status2 && sys::fs::equivalent(*Status1, *Status2);
27673471bf0Spatrick }
27773471bf0Spatrick 
27809467b48Spatrick ErrorOr<const MemoryBuffer &>
getSourceFile(StringRef SourceFile)27909467b48Spatrick CodeCoverageTool::getSourceFile(StringRef SourceFile) {
28009467b48Spatrick   // If we've remapped filenames, look up the real location for this file.
28109467b48Spatrick   std::unique_lock<std::mutex> Guard{LoadedSourceFilesLock};
28209467b48Spatrick   if (!RemappedFilenames.empty()) {
28309467b48Spatrick     auto Loc = RemappedFilenames.find(SourceFile);
28409467b48Spatrick     if (Loc != RemappedFilenames.end())
28509467b48Spatrick       SourceFile = Loc->second;
28609467b48Spatrick   }
28709467b48Spatrick   for (const auto &Files : LoadedSourceFiles)
28873471bf0Spatrick     if (isEquivalentFile(SourceFile, Files.first))
28909467b48Spatrick       return *Files.second;
29009467b48Spatrick   auto Buffer = MemoryBuffer::getFile(SourceFile);
29109467b48Spatrick   if (auto EC = Buffer.getError()) {
29209467b48Spatrick     error(EC.message(), SourceFile);
29309467b48Spatrick     return EC;
29409467b48Spatrick   }
295097a140dSpatrick   LoadedSourceFiles.emplace_back(std::string(SourceFile),
296097a140dSpatrick                                  std::move(Buffer.get()));
29709467b48Spatrick   return *LoadedSourceFiles.back().second;
29809467b48Spatrick }
29909467b48Spatrick 
attachExpansionSubViews(SourceCoverageView & View,ArrayRef<ExpansionRecord> Expansions,const CoverageMapping & Coverage)30009467b48Spatrick void CodeCoverageTool::attachExpansionSubViews(
30109467b48Spatrick     SourceCoverageView &View, ArrayRef<ExpansionRecord> Expansions,
30209467b48Spatrick     const CoverageMapping &Coverage) {
30309467b48Spatrick   if (!ViewOpts.ShowExpandedRegions)
30409467b48Spatrick     return;
30509467b48Spatrick   for (const auto &Expansion : Expansions) {
30609467b48Spatrick     auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
30709467b48Spatrick     if (ExpansionCoverage.empty())
30809467b48Spatrick       continue;
30909467b48Spatrick     auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
31009467b48Spatrick     if (!SourceBuffer)
31109467b48Spatrick       continue;
31209467b48Spatrick 
31373471bf0Spatrick     auto SubViewBranches = ExpansionCoverage.getBranches();
31409467b48Spatrick     auto SubViewExpansions = ExpansionCoverage.getExpansions();
31509467b48Spatrick     auto SubView =
31609467b48Spatrick         SourceCoverageView::create(Expansion.Function.Name, SourceBuffer.get(),
31709467b48Spatrick                                    ViewOpts, std::move(ExpansionCoverage));
31809467b48Spatrick     attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
31973471bf0Spatrick     attachBranchSubViews(*SubView, Expansion.Function.Name, SubViewBranches,
32073471bf0Spatrick                          SourceBuffer.get(), ExpansionCoverage);
32109467b48Spatrick     View.addExpansion(Expansion.Region, std::move(SubView));
32209467b48Spatrick   }
32309467b48Spatrick }
32409467b48Spatrick 
attachBranchSubViews(SourceCoverageView & View,StringRef SourceName,ArrayRef<CountedRegion> Branches,const MemoryBuffer & File,CoverageData & CoverageInfo)32573471bf0Spatrick void CodeCoverageTool::attachBranchSubViews(SourceCoverageView &View,
32673471bf0Spatrick                                             StringRef SourceName,
32773471bf0Spatrick                                             ArrayRef<CountedRegion> Branches,
32873471bf0Spatrick                                             const MemoryBuffer &File,
32973471bf0Spatrick                                             CoverageData &CoverageInfo) {
33073471bf0Spatrick   if (!ViewOpts.ShowBranchCounts && !ViewOpts.ShowBranchPercents)
33173471bf0Spatrick     return;
33273471bf0Spatrick 
33373471bf0Spatrick   const auto *NextBranch = Branches.begin();
33473471bf0Spatrick   const auto *EndBranch = Branches.end();
33573471bf0Spatrick 
33673471bf0Spatrick   // Group branches that have the same line number into the same subview.
33773471bf0Spatrick   while (NextBranch != EndBranch) {
33873471bf0Spatrick     std::vector<CountedRegion> ViewBranches;
33973471bf0Spatrick     unsigned CurrentLine = NextBranch->LineStart;
34073471bf0Spatrick 
34173471bf0Spatrick     while (NextBranch != EndBranch && CurrentLine == NextBranch->LineStart)
34273471bf0Spatrick       ViewBranches.push_back(*NextBranch++);
34373471bf0Spatrick 
34473471bf0Spatrick     if (!ViewBranches.empty()) {
34573471bf0Spatrick       auto SubView = SourceCoverageView::create(SourceName, File, ViewOpts,
34673471bf0Spatrick                                                 std::move(CoverageInfo));
34773471bf0Spatrick       View.addBranch(CurrentLine, ViewBranches, std::move(SubView));
34873471bf0Spatrick     }
34973471bf0Spatrick   }
35073471bf0Spatrick }
35173471bf0Spatrick 
35209467b48Spatrick std::unique_ptr<SourceCoverageView>
createFunctionView(const FunctionRecord & Function,const CoverageMapping & Coverage)35309467b48Spatrick CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
35409467b48Spatrick                                      const CoverageMapping &Coverage) {
35509467b48Spatrick   auto FunctionCoverage = Coverage.getCoverageForFunction(Function);
35609467b48Spatrick   if (FunctionCoverage.empty())
35709467b48Spatrick     return nullptr;
35809467b48Spatrick   auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename());
35909467b48Spatrick   if (!SourceBuffer)
36009467b48Spatrick     return nullptr;
36109467b48Spatrick 
36273471bf0Spatrick   auto Branches = FunctionCoverage.getBranches();
36309467b48Spatrick   auto Expansions = FunctionCoverage.getExpansions();
36409467b48Spatrick   auto View = SourceCoverageView::create(DC.demangle(Function.Name),
36509467b48Spatrick                                          SourceBuffer.get(), ViewOpts,
36609467b48Spatrick                                          std::move(FunctionCoverage));
36709467b48Spatrick   attachExpansionSubViews(*View, Expansions, Coverage);
36873471bf0Spatrick   attachBranchSubViews(*View, DC.demangle(Function.Name), Branches,
36973471bf0Spatrick                        SourceBuffer.get(), FunctionCoverage);
37009467b48Spatrick 
37109467b48Spatrick   return View;
37209467b48Spatrick }
37309467b48Spatrick 
37409467b48Spatrick std::unique_ptr<SourceCoverageView>
createSourceFileView(StringRef SourceFile,const CoverageMapping & Coverage)37509467b48Spatrick CodeCoverageTool::createSourceFileView(StringRef SourceFile,
37609467b48Spatrick                                        const CoverageMapping &Coverage) {
37709467b48Spatrick   auto SourceBuffer = getSourceFile(SourceFile);
37809467b48Spatrick   if (!SourceBuffer)
37909467b48Spatrick     return nullptr;
38009467b48Spatrick   auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
38109467b48Spatrick   if (FileCoverage.empty())
38209467b48Spatrick     return nullptr;
38309467b48Spatrick 
38473471bf0Spatrick   auto Branches = FileCoverage.getBranches();
38509467b48Spatrick   auto Expansions = FileCoverage.getExpansions();
38609467b48Spatrick   auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
38709467b48Spatrick                                          ViewOpts, std::move(FileCoverage));
38809467b48Spatrick   attachExpansionSubViews(*View, Expansions, Coverage);
38973471bf0Spatrick   attachBranchSubViews(*View, SourceFile, Branches, SourceBuffer.get(),
39073471bf0Spatrick                        FileCoverage);
39109467b48Spatrick   if (!ViewOpts.ShowFunctionInstantiations)
39209467b48Spatrick     return View;
39309467b48Spatrick 
39409467b48Spatrick   for (const auto &Group : Coverage.getInstantiationGroups(SourceFile)) {
39509467b48Spatrick     // Skip functions which have a single instantiation.
39609467b48Spatrick     if (Group.size() < 2)
39709467b48Spatrick       continue;
39809467b48Spatrick 
39909467b48Spatrick     for (const FunctionRecord *Function : Group.getInstantiations()) {
40009467b48Spatrick       std::unique_ptr<SourceCoverageView> SubView{nullptr};
40109467b48Spatrick 
40209467b48Spatrick       StringRef Funcname = DC.demangle(Function->Name);
40309467b48Spatrick 
40409467b48Spatrick       if (Function->ExecutionCount > 0) {
40509467b48Spatrick         auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
40609467b48Spatrick         auto SubViewExpansions = SubViewCoverage.getExpansions();
40773471bf0Spatrick         auto SubViewBranches = SubViewCoverage.getBranches();
40809467b48Spatrick         SubView = SourceCoverageView::create(
40909467b48Spatrick             Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
41009467b48Spatrick         attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
41173471bf0Spatrick         attachBranchSubViews(*SubView, SourceFile, SubViewBranches,
41273471bf0Spatrick                              SourceBuffer.get(), SubViewCoverage);
41309467b48Spatrick       }
41409467b48Spatrick 
41509467b48Spatrick       unsigned FileID = Function->CountedRegions.front().FileID;
41609467b48Spatrick       unsigned Line = 0;
41709467b48Spatrick       for (const auto &CR : Function->CountedRegions)
41809467b48Spatrick         if (CR.FileID == FileID)
41909467b48Spatrick           Line = std::max(CR.LineEnd, Line);
42009467b48Spatrick       View->addInstantiation(Funcname, Line, std::move(SubView));
42109467b48Spatrick     }
42209467b48Spatrick   }
42309467b48Spatrick   return View;
42409467b48Spatrick }
42509467b48Spatrick 
modifiedTimeGT(StringRef LHS,StringRef RHS)42609467b48Spatrick static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
42709467b48Spatrick   sys::fs::file_status Status;
42809467b48Spatrick   if (sys::fs::status(LHS, Status))
42909467b48Spatrick     return false;
43009467b48Spatrick   auto LHSTime = Status.getLastModificationTime();
43109467b48Spatrick   if (sys::fs::status(RHS, Status))
43209467b48Spatrick     return false;
43309467b48Spatrick   auto RHSTime = Status.getLastModificationTime();
43409467b48Spatrick   return LHSTime > RHSTime;
43509467b48Spatrick }
43609467b48Spatrick 
load()43709467b48Spatrick std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
43809467b48Spatrick   for (StringRef ObjectFilename : ObjectFilenames)
43909467b48Spatrick     if (modifiedTimeGT(ObjectFilename, PGOFilename))
44009467b48Spatrick       warning("profile data may be out of date - object is newer",
44109467b48Spatrick               ObjectFilename);
44209467b48Spatrick   auto CoverageOrErr =
44373471bf0Spatrick       CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches,
444*d415bd75Srobert                             ViewOpts.CompilationDirectory, BIDFetcher.get());
44509467b48Spatrick   if (Error E = CoverageOrErr.takeError()) {
446*d415bd75Srobert     error("Failed to load coverage: " + toString(std::move(E)));
44709467b48Spatrick     return nullptr;
44809467b48Spatrick   }
44909467b48Spatrick   auto Coverage = std::move(CoverageOrErr.get());
45009467b48Spatrick   unsigned Mismatched = Coverage->getMismatchedCount();
45109467b48Spatrick   if (Mismatched) {
45209467b48Spatrick     warning(Twine(Mismatched) + " functions have mismatched data");
45309467b48Spatrick 
45409467b48Spatrick     if (ViewOpts.Debug) {
45509467b48Spatrick       for (const auto &HashMismatch : Coverage->getHashMismatches())
45609467b48Spatrick         errs() << "hash-mismatch: "
45709467b48Spatrick                << "No profile record found for '" << HashMismatch.first << "'"
45809467b48Spatrick                << " with hash = 0x" << Twine::utohexstr(HashMismatch.second)
45909467b48Spatrick                << '\n';
46009467b48Spatrick     }
46109467b48Spatrick   }
46209467b48Spatrick 
46309467b48Spatrick   remapPathNames(*Coverage);
46409467b48Spatrick 
46509467b48Spatrick   if (!SourceFiles.empty())
46609467b48Spatrick     removeUnmappedInputs(*Coverage);
46709467b48Spatrick 
46809467b48Spatrick   demangleSymbols(*Coverage);
46909467b48Spatrick 
47009467b48Spatrick   return Coverage;
47109467b48Spatrick }
47209467b48Spatrick 
remapPathNames(const CoverageMapping & Coverage)47309467b48Spatrick void CodeCoverageTool::remapPathNames(const CoverageMapping &Coverage) {
47409467b48Spatrick   if (!PathRemapping)
47509467b48Spatrick     return;
47609467b48Spatrick 
47709467b48Spatrick   // Convert remapping paths to native paths with trailing seperators.
47809467b48Spatrick   auto nativeWithTrailing = [](StringRef Path) -> std::string {
47909467b48Spatrick     if (Path.empty())
48009467b48Spatrick       return "";
48109467b48Spatrick     SmallString<128> NativePath;
48209467b48Spatrick     sys::path::native(Path, NativePath);
48373471bf0Spatrick     sys::path::remove_dots(NativePath, true);
48473471bf0Spatrick     if (!NativePath.empty() && !sys::path::is_separator(NativePath.back()))
48509467b48Spatrick       NativePath += sys::path::get_separator();
48609467b48Spatrick     return NativePath.c_str();
48709467b48Spatrick   };
48809467b48Spatrick   std::string RemapFrom = nativeWithTrailing(PathRemapping->first);
48909467b48Spatrick   std::string RemapTo = nativeWithTrailing(PathRemapping->second);
49009467b48Spatrick 
49109467b48Spatrick   // Create a mapping from coverage data file paths to local paths.
49209467b48Spatrick   for (StringRef Filename : Coverage.getUniqueSourceFiles()) {
49309467b48Spatrick     SmallString<128> NativeFilename;
49409467b48Spatrick     sys::path::native(Filename, NativeFilename);
49573471bf0Spatrick     sys::path::remove_dots(NativeFilename, true);
49609467b48Spatrick     if (NativeFilename.startswith(RemapFrom)) {
49709467b48Spatrick       RemappedFilenames[Filename] =
49809467b48Spatrick           RemapTo + NativeFilename.substr(RemapFrom.size()).str();
49909467b48Spatrick     }
50009467b48Spatrick   }
50109467b48Spatrick 
50209467b48Spatrick   // Convert input files from local paths to coverage data file paths.
50309467b48Spatrick   StringMap<std::string> InvRemappedFilenames;
50409467b48Spatrick   for (const auto &RemappedFilename : RemappedFilenames)
505097a140dSpatrick     InvRemappedFilenames[RemappedFilename.getValue()] =
506097a140dSpatrick         std::string(RemappedFilename.getKey());
50709467b48Spatrick 
50809467b48Spatrick   for (std::string &Filename : SourceFiles) {
50909467b48Spatrick     SmallString<128> NativeFilename;
51009467b48Spatrick     sys::path::native(Filename, NativeFilename);
51109467b48Spatrick     auto CovFileName = InvRemappedFilenames.find(NativeFilename);
51209467b48Spatrick     if (CovFileName != InvRemappedFilenames.end())
51309467b48Spatrick       Filename = CovFileName->second;
51409467b48Spatrick   }
51509467b48Spatrick }
51609467b48Spatrick 
removeUnmappedInputs(const CoverageMapping & Coverage)51709467b48Spatrick void CodeCoverageTool::removeUnmappedInputs(const CoverageMapping &Coverage) {
51809467b48Spatrick   std::vector<StringRef> CoveredFiles = Coverage.getUniqueSourceFiles();
51909467b48Spatrick 
52009467b48Spatrick   // The user may have specified source files which aren't in the coverage
52109467b48Spatrick   // mapping. Filter these files away.
52273471bf0Spatrick   llvm::erase_if(SourceFiles, [&](const std::string &SF) {
52373471bf0Spatrick     return !std::binary_search(CoveredFiles.begin(), CoveredFiles.end(), SF);
52409467b48Spatrick   });
52509467b48Spatrick }
52609467b48Spatrick 
demangleSymbols(const CoverageMapping & Coverage)52709467b48Spatrick void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) {
52809467b48Spatrick   if (!ViewOpts.hasDemangler())
52909467b48Spatrick     return;
53009467b48Spatrick 
53109467b48Spatrick   // Pass function names to the demangler in a temporary file.
53209467b48Spatrick   int InputFD;
53309467b48Spatrick   SmallString<256> InputPath;
53409467b48Spatrick   std::error_code EC =
53509467b48Spatrick       sys::fs::createTemporaryFile("demangle-in", "list", InputFD, InputPath);
53609467b48Spatrick   if (EC) {
53709467b48Spatrick     error(InputPath, EC.message());
53809467b48Spatrick     return;
53909467b48Spatrick   }
54009467b48Spatrick   ToolOutputFile InputTOF{InputPath, InputFD};
54109467b48Spatrick 
54209467b48Spatrick   unsigned NumSymbols = 0;
54309467b48Spatrick   for (const auto &Function : Coverage.getCoveredFunctions()) {
54409467b48Spatrick     InputTOF.os() << Function.Name << '\n';
54509467b48Spatrick     ++NumSymbols;
54609467b48Spatrick   }
54709467b48Spatrick   InputTOF.os().close();
54809467b48Spatrick 
54909467b48Spatrick   // Use another temporary file to store the demangler's output.
55009467b48Spatrick   int OutputFD;
55109467b48Spatrick   SmallString<256> OutputPath;
55209467b48Spatrick   EC = sys::fs::createTemporaryFile("demangle-out", "list", OutputFD,
55309467b48Spatrick                                     OutputPath);
55409467b48Spatrick   if (EC) {
55509467b48Spatrick     error(OutputPath, EC.message());
55609467b48Spatrick     return;
55709467b48Spatrick   }
55809467b48Spatrick   ToolOutputFile OutputTOF{OutputPath, OutputFD};
55909467b48Spatrick   OutputTOF.os().close();
56009467b48Spatrick 
56109467b48Spatrick   // Invoke the demangler.
56209467b48Spatrick   std::vector<StringRef> ArgsV;
563*d415bd75Srobert   ArgsV.reserve(ViewOpts.DemanglerOpts.size());
56409467b48Spatrick   for (StringRef Arg : ViewOpts.DemanglerOpts)
56509467b48Spatrick     ArgsV.push_back(Arg);
566*d415bd75Srobert   std::optional<StringRef> Redirects[] = {
567*d415bd75Srobert       InputPath.str(), OutputPath.str(), {""}};
56809467b48Spatrick   std::string ErrMsg;
569*d415bd75Srobert   int RC =
570*d415bd75Srobert       sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV,
571*d415bd75Srobert                           /*env=*/std::nullopt, Redirects, /*secondsToWait=*/0,
57209467b48Spatrick                           /*memoryLimit=*/0, &ErrMsg);
57309467b48Spatrick   if (RC) {
57409467b48Spatrick     error(ErrMsg, ViewOpts.DemanglerOpts[0]);
57509467b48Spatrick     return;
57609467b48Spatrick   }
57709467b48Spatrick 
57809467b48Spatrick   // Parse the demangler's output.
57909467b48Spatrick   auto BufOrError = MemoryBuffer::getFile(OutputPath);
58009467b48Spatrick   if (!BufOrError) {
58109467b48Spatrick     error(OutputPath, BufOrError.getError().message());
58209467b48Spatrick     return;
58309467b48Spatrick   }
58409467b48Spatrick 
58509467b48Spatrick   std::unique_ptr<MemoryBuffer> DemanglerBuf = std::move(*BufOrError);
58609467b48Spatrick 
58709467b48Spatrick   SmallVector<StringRef, 8> Symbols;
58809467b48Spatrick   StringRef DemanglerData = DemanglerBuf->getBuffer();
58909467b48Spatrick   DemanglerData.split(Symbols, '\n', /*MaxSplit=*/NumSymbols,
59009467b48Spatrick                       /*KeepEmpty=*/false);
59109467b48Spatrick   if (Symbols.size() != NumSymbols) {
59209467b48Spatrick     error("Demangler did not provide expected number of symbols");
59309467b48Spatrick     return;
59409467b48Spatrick   }
59509467b48Spatrick 
59609467b48Spatrick   // Cache the demangled names.
59709467b48Spatrick   unsigned I = 0;
59809467b48Spatrick   for (const auto &Function : Coverage.getCoveredFunctions())
59909467b48Spatrick     // On Windows, lines in the demangler's output file end with "\r\n".
60009467b48Spatrick     // Splitting by '\n' keeps '\r's, so cut them now.
601097a140dSpatrick     DC.DemangledNames[Function.Name] = std::string(Symbols[I++].rtrim());
60209467b48Spatrick }
60309467b48Spatrick 
writeSourceFileView(StringRef SourceFile,CoverageMapping * Coverage,CoveragePrinter * Printer,bool ShowFilenames)60409467b48Spatrick void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
60509467b48Spatrick                                            CoverageMapping *Coverage,
60609467b48Spatrick                                            CoveragePrinter *Printer,
60709467b48Spatrick                                            bool ShowFilenames) {
60809467b48Spatrick   auto View = createSourceFileView(SourceFile, *Coverage);
60909467b48Spatrick   if (!View) {
61009467b48Spatrick     warning("The file '" + SourceFile + "' isn't covered.");
61109467b48Spatrick     return;
61209467b48Spatrick   }
61309467b48Spatrick 
61409467b48Spatrick   auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false);
61509467b48Spatrick   if (Error E = OSOrErr.takeError()) {
61609467b48Spatrick     error("Could not create view file!", toString(std::move(E)));
61709467b48Spatrick     return;
61809467b48Spatrick   }
61909467b48Spatrick   auto OS = std::move(OSOrErr.get());
62009467b48Spatrick 
62109467b48Spatrick   View->print(*OS.get(), /*Wholefile=*/true,
62209467b48Spatrick               /*ShowSourceName=*/ShowFilenames,
62309467b48Spatrick               /*ShowTitle=*/ViewOpts.hasOutputDirectory());
62409467b48Spatrick   Printer->closeViewFile(std::move(OS));
62509467b48Spatrick }
62609467b48Spatrick 
run(Command Cmd,int argc,const char ** argv)62709467b48Spatrick int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
62809467b48Spatrick   cl::opt<std::string> CovFilename(
62909467b48Spatrick       cl::Positional, cl::desc("Covered executable or object file."));
63009467b48Spatrick 
63109467b48Spatrick   cl::list<std::string> CovFilenames(
632*d415bd75Srobert       "object", cl::desc("Coverage executable or object file"));
63373471bf0Spatrick 
63473471bf0Spatrick   cl::opt<bool> DebugDumpCollectedObjects(
63573471bf0Spatrick       "dump-collected-objects", cl::Optional, cl::Hidden,
63673471bf0Spatrick       cl::desc("Show the collected coverage object files"));
63709467b48Spatrick 
638*d415bd75Srobert   cl::list<std::string> InputSourceFiles("sources", cl::Positional,
639*d415bd75Srobert                                          cl::desc("<Source files>"));
64009467b48Spatrick 
64109467b48Spatrick   cl::opt<bool> DebugDumpCollectedPaths(
64209467b48Spatrick       "dump-collected-paths", cl::Optional, cl::Hidden,
64309467b48Spatrick       cl::desc("Show the collected paths to source files"));
64409467b48Spatrick 
64509467b48Spatrick   cl::opt<std::string, true> PGOFilename(
64609467b48Spatrick       "instr-profile", cl::Required, cl::location(this->PGOFilename),
64709467b48Spatrick       cl::desc(
64809467b48Spatrick           "File with the profile data obtained after an instrumented run"));
64909467b48Spatrick 
65009467b48Spatrick   cl::list<std::string> Arches(
65109467b48Spatrick       "arch", cl::desc("architectures of the coverage mapping binaries"));
65209467b48Spatrick 
65309467b48Spatrick   cl::opt<bool> DebugDump("dump", cl::Optional,
65409467b48Spatrick                           cl::desc("Show internal debug dump"));
65509467b48Spatrick 
656*d415bd75Srobert   cl::list<std::string> DebugFileDirectory(
657*d415bd75Srobert       "debug-file-directory",
658*d415bd75Srobert       cl::desc("Directories to search for object files by build ID"));
659*d415bd75Srobert   cl::opt<bool> Debuginfod(
660*d415bd75Srobert       "debuginfod", cl::ZeroOrMore,
661*d415bd75Srobert       cl::desc("Use debuginfod to look up object files from profile"),
662*d415bd75Srobert       cl::init(canUseDebuginfod()));
663*d415bd75Srobert 
66409467b48Spatrick   cl::opt<CoverageViewOptions::OutputFormat> Format(
66509467b48Spatrick       "format", cl::desc("Output format for line-based coverage reports"),
66609467b48Spatrick       cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text, "text",
66709467b48Spatrick                             "Text output"),
66809467b48Spatrick                  clEnumValN(CoverageViewOptions::OutputFormat::HTML, "html",
66909467b48Spatrick                             "HTML output"),
67009467b48Spatrick                  clEnumValN(CoverageViewOptions::OutputFormat::Lcov, "lcov",
67109467b48Spatrick                             "lcov tracefile output")),
67209467b48Spatrick       cl::init(CoverageViewOptions::OutputFormat::Text));
67309467b48Spatrick 
67409467b48Spatrick   cl::opt<std::string> PathRemap(
67509467b48Spatrick       "path-equivalence", cl::Optional,
67609467b48Spatrick       cl::desc("<from>,<to> Map coverage data paths to local source file "
67709467b48Spatrick                "paths"));
67809467b48Spatrick 
67909467b48Spatrick   cl::OptionCategory FilteringCategory("Function filtering options");
68009467b48Spatrick 
68109467b48Spatrick   cl::list<std::string> NameFilters(
68209467b48Spatrick       "name", cl::Optional,
68309467b48Spatrick       cl::desc("Show code coverage only for functions with the given name"),
684*d415bd75Srobert       cl::cat(FilteringCategory));
68509467b48Spatrick 
68609467b48Spatrick   cl::list<std::string> NameFilterFiles(
687*d415bd75Srobert       "name-allowlist", cl::Optional,
68809467b48Spatrick       cl::desc("Show code coverage only for functions listed in the given "
68909467b48Spatrick                "file"),
690*d415bd75Srobert       cl::cat(FilteringCategory));
69109467b48Spatrick 
69209467b48Spatrick   cl::list<std::string> NameRegexFilters(
69309467b48Spatrick       "name-regex", cl::Optional,
69409467b48Spatrick       cl::desc("Show code coverage only for functions that match the given "
69509467b48Spatrick                "regular expression"),
696*d415bd75Srobert       cl::cat(FilteringCategory));
69709467b48Spatrick 
69809467b48Spatrick   cl::list<std::string> IgnoreFilenameRegexFilters(
69909467b48Spatrick       "ignore-filename-regex", cl::Optional,
70009467b48Spatrick       cl::desc("Skip source code files with file paths that match the given "
70109467b48Spatrick                "regular expression"),
702*d415bd75Srobert       cl::cat(FilteringCategory));
70309467b48Spatrick 
70409467b48Spatrick   cl::opt<double> RegionCoverageLtFilter(
70509467b48Spatrick       "region-coverage-lt", cl::Optional,
70609467b48Spatrick       cl::desc("Show code coverage only for functions with region coverage "
70709467b48Spatrick                "less than the given threshold"),
70809467b48Spatrick       cl::cat(FilteringCategory));
70909467b48Spatrick 
71009467b48Spatrick   cl::opt<double> RegionCoverageGtFilter(
71109467b48Spatrick       "region-coverage-gt", cl::Optional,
71209467b48Spatrick       cl::desc("Show code coverage only for functions with region coverage "
71309467b48Spatrick                "greater than the given threshold"),
71409467b48Spatrick       cl::cat(FilteringCategory));
71509467b48Spatrick 
71609467b48Spatrick   cl::opt<double> LineCoverageLtFilter(
71709467b48Spatrick       "line-coverage-lt", cl::Optional,
71809467b48Spatrick       cl::desc("Show code coverage only for functions with line coverage less "
71909467b48Spatrick                "than the given threshold"),
72009467b48Spatrick       cl::cat(FilteringCategory));
72109467b48Spatrick 
72209467b48Spatrick   cl::opt<double> LineCoverageGtFilter(
72309467b48Spatrick       "line-coverage-gt", cl::Optional,
72409467b48Spatrick       cl::desc("Show code coverage only for functions with line coverage "
72509467b48Spatrick                "greater than the given threshold"),
72609467b48Spatrick       cl::cat(FilteringCategory));
72709467b48Spatrick 
72809467b48Spatrick   cl::opt<cl::boolOrDefault> UseColor(
72909467b48Spatrick       "use-color", cl::desc("Emit colored output (default=autodetect)"),
73009467b48Spatrick       cl::init(cl::BOU_UNSET));
73109467b48Spatrick 
73209467b48Spatrick   cl::list<std::string> DemanglerOpts(
73309467b48Spatrick       "Xdemangler", cl::desc("<demangler-path>|<demangler-option>"));
73409467b48Spatrick 
73509467b48Spatrick   cl::opt<bool> RegionSummary(
73609467b48Spatrick       "show-region-summary", cl::Optional,
73709467b48Spatrick       cl::desc("Show region statistics in summary table"),
73809467b48Spatrick       cl::init(true));
73909467b48Spatrick 
74073471bf0Spatrick   cl::opt<bool> BranchSummary(
74173471bf0Spatrick       "show-branch-summary", cl::Optional,
74273471bf0Spatrick       cl::desc("Show branch condition statistics in summary table"),
74373471bf0Spatrick       cl::init(true));
74473471bf0Spatrick 
74509467b48Spatrick   cl::opt<bool> InstantiationSummary(
74609467b48Spatrick       "show-instantiation-summary", cl::Optional,
74709467b48Spatrick       cl::desc("Show instantiation statistics in summary table"));
74809467b48Spatrick 
74909467b48Spatrick   cl::opt<bool> SummaryOnly(
75009467b48Spatrick       "summary-only", cl::Optional,
75109467b48Spatrick       cl::desc("Export only summary information for each source file"));
75209467b48Spatrick 
75309467b48Spatrick   cl::opt<unsigned> NumThreads(
75409467b48Spatrick       "num-threads", cl::init(0),
75509467b48Spatrick       cl::desc("Number of merge threads to use (default: autodetect)"));
75609467b48Spatrick   cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"),
75709467b48Spatrick                         cl::aliasopt(NumThreads));
75809467b48Spatrick 
75973471bf0Spatrick   cl::opt<std::string> CompilationDirectory(
76073471bf0Spatrick       "compilation-dir", cl::init(""),
76173471bf0Spatrick       cl::desc("Directory used as a base for relative coverage mapping paths"));
76273471bf0Spatrick 
76309467b48Spatrick   auto commandLineParser = [&, this](int argc, const char **argv) -> int {
76409467b48Spatrick     cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
76509467b48Spatrick     ViewOpts.Debug = DebugDump;
766*d415bd75Srobert     if (Debuginfod) {
767*d415bd75Srobert       HTTPClient::initialize();
768*d415bd75Srobert       BIDFetcher = std::make_unique<DebuginfodFetcher>(DebugFileDirectory);
769*d415bd75Srobert     } else {
770*d415bd75Srobert       BIDFetcher = std::make_unique<object::BuildIDFetcher>(DebugFileDirectory);
771*d415bd75Srobert     }
77209467b48Spatrick 
77309467b48Spatrick     if (!CovFilename.empty())
77409467b48Spatrick       ObjectFilenames.emplace_back(CovFilename);
77509467b48Spatrick     for (const std::string &Filename : CovFilenames)
77609467b48Spatrick       ObjectFilenames.emplace_back(Filename);
777*d415bd75Srobert     if (ObjectFilenames.empty() && !Debuginfod && DebugFileDirectory.empty()) {
77809467b48Spatrick       errs() << "No filenames specified!\n";
77909467b48Spatrick       ::exit(1);
78009467b48Spatrick     }
78109467b48Spatrick 
78273471bf0Spatrick     if (DebugDumpCollectedObjects) {
78373471bf0Spatrick       for (StringRef OF : ObjectFilenames)
78473471bf0Spatrick         outs() << OF << '\n';
78573471bf0Spatrick       ::exit(0);
78673471bf0Spatrick     }
78773471bf0Spatrick 
78809467b48Spatrick     ViewOpts.Format = Format;
78909467b48Spatrick     switch (ViewOpts.Format) {
79009467b48Spatrick     case CoverageViewOptions::OutputFormat::Text:
79109467b48Spatrick       ViewOpts.Colors = UseColor == cl::BOU_UNSET
79209467b48Spatrick                             ? sys::Process::StandardOutHasColors()
79309467b48Spatrick                             : UseColor == cl::BOU_TRUE;
79409467b48Spatrick       break;
79509467b48Spatrick     case CoverageViewOptions::OutputFormat::HTML:
79609467b48Spatrick       if (UseColor == cl::BOU_FALSE)
79709467b48Spatrick         errs() << "Color output cannot be disabled when generating html.\n";
79809467b48Spatrick       ViewOpts.Colors = true;
79909467b48Spatrick       break;
80009467b48Spatrick     case CoverageViewOptions::OutputFormat::Lcov:
80109467b48Spatrick       if (UseColor == cl::BOU_TRUE)
80209467b48Spatrick         errs() << "Color output cannot be enabled when generating lcov.\n";
80309467b48Spatrick       ViewOpts.Colors = false;
80409467b48Spatrick       break;
80509467b48Spatrick     }
80609467b48Spatrick 
80709467b48Spatrick     // If path-equivalence was given and is a comma seperated pair then set
80809467b48Spatrick     // PathRemapping.
809*d415bd75Srobert     if (!PathRemap.empty()) {
81009467b48Spatrick       auto EquivPair = StringRef(PathRemap).split(',');
811*d415bd75Srobert       if (EquivPair.first.empty() || EquivPair.second.empty()) {
812*d415bd75Srobert         error("invalid argument '" + PathRemap +
813*d415bd75Srobert                   "', must be in format 'from,to'",
814*d415bd75Srobert               "-path-equivalence");
815*d415bd75Srobert         return 1;
816*d415bd75Srobert       }
817*d415bd75Srobert 
818097a140dSpatrick       PathRemapping = {std::string(EquivPair.first),
819097a140dSpatrick                        std::string(EquivPair.second)};
820*d415bd75Srobert     }
82109467b48Spatrick 
82209467b48Spatrick     // If a demangler is supplied, check if it exists and register it.
82309467b48Spatrick     if (!DemanglerOpts.empty()) {
82409467b48Spatrick       auto DemanglerPathOrErr = sys::findProgramByName(DemanglerOpts[0]);
82509467b48Spatrick       if (!DemanglerPathOrErr) {
82609467b48Spatrick         error("Could not find the demangler!",
82709467b48Spatrick               DemanglerPathOrErr.getError().message());
82809467b48Spatrick         return 1;
82909467b48Spatrick       }
83009467b48Spatrick       DemanglerOpts[0] = *DemanglerPathOrErr;
83109467b48Spatrick       ViewOpts.DemanglerOpts.swap(DemanglerOpts);
83209467b48Spatrick     }
83309467b48Spatrick 
834*d415bd75Srobert     // Read in -name-allowlist files.
83509467b48Spatrick     if (!NameFilterFiles.empty()) {
83609467b48Spatrick       std::string SpecialCaseListErr;
837*d415bd75Srobert       NameAllowlist = SpecialCaseList::create(
83809467b48Spatrick           NameFilterFiles, *vfs::getRealFileSystem(), SpecialCaseListErr);
839*d415bd75Srobert       if (!NameAllowlist)
84009467b48Spatrick         error(SpecialCaseListErr);
84109467b48Spatrick     }
84209467b48Spatrick 
84309467b48Spatrick     // Create the function filters
844*d415bd75Srobert     if (!NameFilters.empty() || NameAllowlist || !NameRegexFilters.empty()) {
84509467b48Spatrick       auto NameFilterer = std::make_unique<CoverageFilters>();
84609467b48Spatrick       for (const auto &Name : NameFilters)
84709467b48Spatrick         NameFilterer->push_back(std::make_unique<NameCoverageFilter>(Name));
848*d415bd75Srobert       if (NameAllowlist && !NameFilterFiles.empty())
84909467b48Spatrick         NameFilterer->push_back(
850*d415bd75Srobert             std::make_unique<NameAllowlistCoverageFilter>(*NameAllowlist));
85109467b48Spatrick       for (const auto &Regex : NameRegexFilters)
85209467b48Spatrick         NameFilterer->push_back(
85309467b48Spatrick             std::make_unique<NameRegexCoverageFilter>(Regex));
85409467b48Spatrick       Filters.push_back(std::move(NameFilterer));
85509467b48Spatrick     }
85609467b48Spatrick 
85709467b48Spatrick     if (RegionCoverageLtFilter.getNumOccurrences() ||
85809467b48Spatrick         RegionCoverageGtFilter.getNumOccurrences() ||
85909467b48Spatrick         LineCoverageLtFilter.getNumOccurrences() ||
86009467b48Spatrick         LineCoverageGtFilter.getNumOccurrences()) {
86109467b48Spatrick       auto StatFilterer = std::make_unique<CoverageFilters>();
86209467b48Spatrick       if (RegionCoverageLtFilter.getNumOccurrences())
86309467b48Spatrick         StatFilterer->push_back(std::make_unique<RegionCoverageFilter>(
86409467b48Spatrick             RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
86509467b48Spatrick       if (RegionCoverageGtFilter.getNumOccurrences())
86609467b48Spatrick         StatFilterer->push_back(std::make_unique<RegionCoverageFilter>(
86709467b48Spatrick             RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
86809467b48Spatrick       if (LineCoverageLtFilter.getNumOccurrences())
86909467b48Spatrick         StatFilterer->push_back(std::make_unique<LineCoverageFilter>(
87009467b48Spatrick             LineCoverageFilter::LessThan, LineCoverageLtFilter));
87109467b48Spatrick       if (LineCoverageGtFilter.getNumOccurrences())
87209467b48Spatrick         StatFilterer->push_back(std::make_unique<LineCoverageFilter>(
87309467b48Spatrick             RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
87409467b48Spatrick       Filters.push_back(std::move(StatFilterer));
87509467b48Spatrick     }
87609467b48Spatrick 
87709467b48Spatrick     // Create the ignore filename filters.
87809467b48Spatrick     for (const auto &RE : IgnoreFilenameRegexFilters)
87909467b48Spatrick       IgnoreFilenameFilters.push_back(
88009467b48Spatrick           std::make_unique<NameRegexCoverageFilter>(RE));
88109467b48Spatrick 
88209467b48Spatrick     if (!Arches.empty()) {
88309467b48Spatrick       for (const std::string &Arch : Arches) {
88409467b48Spatrick         if (Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
88509467b48Spatrick           error("Unknown architecture: " + Arch);
88609467b48Spatrick           return 1;
88709467b48Spatrick         }
88809467b48Spatrick         CoverageArches.emplace_back(Arch);
88909467b48Spatrick       }
890*d415bd75Srobert       if (CoverageArches.size() != 1 &&
891*d415bd75Srobert           CoverageArches.size() != ObjectFilenames.size()) {
89209467b48Spatrick         error("Number of architectures doesn't match the number of objects");
89309467b48Spatrick         return 1;
89409467b48Spatrick       }
89509467b48Spatrick     }
89609467b48Spatrick 
89709467b48Spatrick     // IgnoreFilenameFilters are applied even when InputSourceFiles specified.
89809467b48Spatrick     for (const std::string &File : InputSourceFiles)
89909467b48Spatrick       collectPaths(File);
90009467b48Spatrick 
90109467b48Spatrick     if (DebugDumpCollectedPaths) {
90209467b48Spatrick       for (const std::string &SF : SourceFiles)
90309467b48Spatrick         outs() << SF << '\n';
90409467b48Spatrick       ::exit(0);
90509467b48Spatrick     }
90609467b48Spatrick 
90773471bf0Spatrick     ViewOpts.ShowBranchSummary = BranchSummary;
90809467b48Spatrick     ViewOpts.ShowRegionSummary = RegionSummary;
90909467b48Spatrick     ViewOpts.ShowInstantiationSummary = InstantiationSummary;
91009467b48Spatrick     ViewOpts.ExportSummaryOnly = SummaryOnly;
91109467b48Spatrick     ViewOpts.NumThreads = NumThreads;
91273471bf0Spatrick     ViewOpts.CompilationDirectory = CompilationDirectory;
91309467b48Spatrick 
91409467b48Spatrick     return 0;
91509467b48Spatrick   };
91609467b48Spatrick 
91709467b48Spatrick   switch (Cmd) {
91809467b48Spatrick   case Show:
91909467b48Spatrick     return doShow(argc, argv, commandLineParser);
92009467b48Spatrick   case Report:
92109467b48Spatrick     return doReport(argc, argv, commandLineParser);
92209467b48Spatrick   case Export:
92309467b48Spatrick     return doExport(argc, argv, commandLineParser);
92409467b48Spatrick   }
92509467b48Spatrick   return 0;
92609467b48Spatrick }
92709467b48Spatrick 
doShow(int argc,const char ** argv,CommandLineParserType commandLineParser)92809467b48Spatrick int CodeCoverageTool::doShow(int argc, const char **argv,
92909467b48Spatrick                              CommandLineParserType commandLineParser) {
93009467b48Spatrick 
93109467b48Spatrick   cl::OptionCategory ViewCategory("Viewing options");
93209467b48Spatrick 
93309467b48Spatrick   cl::opt<bool> ShowLineExecutionCounts(
93409467b48Spatrick       "show-line-counts", cl::Optional,
93509467b48Spatrick       cl::desc("Show the execution counts for each line"), cl::init(true),
93609467b48Spatrick       cl::cat(ViewCategory));
93709467b48Spatrick 
93809467b48Spatrick   cl::opt<bool> ShowRegions(
93909467b48Spatrick       "show-regions", cl::Optional,
94009467b48Spatrick       cl::desc("Show the execution counts for each region"),
94109467b48Spatrick       cl::cat(ViewCategory));
94209467b48Spatrick 
94373471bf0Spatrick   cl::opt<CoverageViewOptions::BranchOutputType> ShowBranches(
94473471bf0Spatrick       "show-branches", cl::Optional,
94573471bf0Spatrick       cl::desc("Show coverage for branch conditions"), cl::cat(ViewCategory),
94673471bf0Spatrick       cl::values(clEnumValN(CoverageViewOptions::BranchOutputType::Count,
94773471bf0Spatrick                             "count", "Show True/False counts"),
94873471bf0Spatrick                  clEnumValN(CoverageViewOptions::BranchOutputType::Percent,
94973471bf0Spatrick                             "percent", "Show True/False percent")),
95073471bf0Spatrick       cl::init(CoverageViewOptions::BranchOutputType::Off));
95173471bf0Spatrick 
95209467b48Spatrick   cl::opt<bool> ShowBestLineRegionsCounts(
95309467b48Spatrick       "show-line-counts-or-regions", cl::Optional,
95409467b48Spatrick       cl::desc("Show the execution counts for each line, or the execution "
95509467b48Spatrick                "counts for each region on lines that have multiple regions"),
95609467b48Spatrick       cl::cat(ViewCategory));
95709467b48Spatrick 
95809467b48Spatrick   cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
95909467b48Spatrick                                cl::desc("Show expanded source regions"),
96009467b48Spatrick                                cl::cat(ViewCategory));
96109467b48Spatrick 
96209467b48Spatrick   cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
96309467b48Spatrick                                    cl::desc("Show function instantiations"),
96409467b48Spatrick                                    cl::init(true), cl::cat(ViewCategory));
96509467b48Spatrick 
96609467b48Spatrick   cl::opt<std::string> ShowOutputDirectory(
96709467b48Spatrick       "output-dir", cl::init(""),
96809467b48Spatrick       cl::desc("Directory in which coverage information is written out"));
96909467b48Spatrick   cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
97009467b48Spatrick                                  cl::aliasopt(ShowOutputDirectory));
97109467b48Spatrick 
97209467b48Spatrick   cl::opt<uint32_t> TabSize(
97309467b48Spatrick       "tab-size", cl::init(2),
97409467b48Spatrick       cl::desc(
97509467b48Spatrick           "Set tab expansion size for html coverage reports (default = 2)"));
97609467b48Spatrick 
97709467b48Spatrick   cl::opt<std::string> ProjectTitle(
97809467b48Spatrick       "project-title", cl::Optional,
97909467b48Spatrick       cl::desc("Set project title for the coverage report"));
98009467b48Spatrick 
981*d415bd75Srobert   cl::opt<std::string> CovWatermark(
982*d415bd75Srobert       "coverage-watermark", cl::Optional,
983*d415bd75Srobert       cl::desc("<high>,<low> value indicate thresholds for high and low"
984*d415bd75Srobert                "coverage watermark"));
985*d415bd75Srobert 
98609467b48Spatrick   auto Err = commandLineParser(argc, argv);
98709467b48Spatrick   if (Err)
98809467b48Spatrick     return Err;
98909467b48Spatrick 
99009467b48Spatrick   if (ViewOpts.Format == CoverageViewOptions::OutputFormat::Lcov) {
99109467b48Spatrick     error("Lcov format should be used with 'llvm-cov export'.");
99209467b48Spatrick     return 1;
99309467b48Spatrick   }
99409467b48Spatrick 
995*d415bd75Srobert   ViewOpts.HighCovWatermark = 100.0;
996*d415bd75Srobert   ViewOpts.LowCovWatermark = 80.0;
997*d415bd75Srobert   if (!CovWatermark.empty()) {
998*d415bd75Srobert     auto WaterMarkPair = StringRef(CovWatermark).split(',');
999*d415bd75Srobert     if (WaterMarkPair.first.empty() || WaterMarkPair.second.empty()) {
1000*d415bd75Srobert       error("invalid argument '" + CovWatermark +
1001*d415bd75Srobert                 "', must be in format 'high,low'",
1002*d415bd75Srobert             "-coverage-watermark");
1003*d415bd75Srobert       return 1;
1004*d415bd75Srobert     }
1005*d415bd75Srobert 
1006*d415bd75Srobert     char *EndPointer = nullptr;
1007*d415bd75Srobert     ViewOpts.HighCovWatermark =
1008*d415bd75Srobert         strtod(WaterMarkPair.first.begin(), &EndPointer);
1009*d415bd75Srobert     if (EndPointer != WaterMarkPair.first.end()) {
1010*d415bd75Srobert       error("invalid number '" + WaterMarkPair.first +
1011*d415bd75Srobert                 "', invalid value for 'high'",
1012*d415bd75Srobert             "-coverage-watermark");
1013*d415bd75Srobert       return 1;
1014*d415bd75Srobert     }
1015*d415bd75Srobert 
1016*d415bd75Srobert     ViewOpts.LowCovWatermark =
1017*d415bd75Srobert         strtod(WaterMarkPair.second.begin(), &EndPointer);
1018*d415bd75Srobert     if (EndPointer != WaterMarkPair.second.end()) {
1019*d415bd75Srobert       error("invalid number '" + WaterMarkPair.second +
1020*d415bd75Srobert                 "', invalid value for 'low'",
1021*d415bd75Srobert             "-coverage-watermark");
1022*d415bd75Srobert       return 1;
1023*d415bd75Srobert     }
1024*d415bd75Srobert 
1025*d415bd75Srobert     if (ViewOpts.HighCovWatermark > 100 || ViewOpts.LowCovWatermark < 0 ||
1026*d415bd75Srobert         ViewOpts.HighCovWatermark <= ViewOpts.LowCovWatermark) {
1027*d415bd75Srobert       error(
1028*d415bd75Srobert           "invalid number range '" + CovWatermark +
1029*d415bd75Srobert               "', must be both high and low should be between 0-100, and high "
1030*d415bd75Srobert               "> low",
1031*d415bd75Srobert           "-coverage-watermark");
1032*d415bd75Srobert       return 1;
1033*d415bd75Srobert     }
1034*d415bd75Srobert   }
1035*d415bd75Srobert 
103609467b48Spatrick   ViewOpts.ShowLineNumbers = true;
103709467b48Spatrick   ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
103809467b48Spatrick                            !ShowRegions || ShowBestLineRegionsCounts;
103909467b48Spatrick   ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
104009467b48Spatrick   ViewOpts.ShowExpandedRegions = ShowExpansions;
104173471bf0Spatrick   ViewOpts.ShowBranchCounts =
104273471bf0Spatrick       ShowBranches == CoverageViewOptions::BranchOutputType::Count;
104373471bf0Spatrick   ViewOpts.ShowBranchPercents =
104473471bf0Spatrick       ShowBranches == CoverageViewOptions::BranchOutputType::Percent;
104509467b48Spatrick   ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
104609467b48Spatrick   ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
104709467b48Spatrick   ViewOpts.TabSize = TabSize;
104809467b48Spatrick   ViewOpts.ProjectTitle = ProjectTitle;
104909467b48Spatrick 
105009467b48Spatrick   if (ViewOpts.hasOutputDirectory()) {
105109467b48Spatrick     if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) {
105209467b48Spatrick       error("Could not create output directory!", E.message());
105309467b48Spatrick       return 1;
105409467b48Spatrick     }
105509467b48Spatrick   }
105609467b48Spatrick 
105709467b48Spatrick   sys::fs::file_status Status;
1058097a140dSpatrick   if (std::error_code EC = sys::fs::status(PGOFilename, Status)) {
1059*d415bd75Srobert     error("Could not read profile data!" + EC.message(), PGOFilename);
106009467b48Spatrick     return 1;
106109467b48Spatrick   }
106209467b48Spatrick 
106309467b48Spatrick   auto ModifiedTime = Status.getLastModificationTime();
106409467b48Spatrick   std::string ModifiedTimeStr = to_string(ModifiedTime);
106509467b48Spatrick   size_t found = ModifiedTimeStr.rfind(':');
106609467b48Spatrick   ViewOpts.CreatedTimeStr = (found != std::string::npos)
106709467b48Spatrick                                 ? "Created: " + ModifiedTimeStr.substr(0, found)
106809467b48Spatrick                                 : "Created: " + ModifiedTimeStr;
106909467b48Spatrick 
107009467b48Spatrick   auto Coverage = load();
107109467b48Spatrick   if (!Coverage)
107209467b48Spatrick     return 1;
107309467b48Spatrick 
107409467b48Spatrick   auto Printer = CoveragePrinter::create(ViewOpts);
107509467b48Spatrick 
107673471bf0Spatrick   if (SourceFiles.empty() && !HadSourceFiles)
107709467b48Spatrick     // Get the source files from the function coverage mapping.
107809467b48Spatrick     for (StringRef Filename : Coverage->getUniqueSourceFiles()) {
107909467b48Spatrick       if (!IgnoreFilenameFilters.matchesFilename(Filename))
1080097a140dSpatrick         SourceFiles.push_back(std::string(Filename));
108109467b48Spatrick     }
108209467b48Spatrick 
108309467b48Spatrick   // Create an index out of the source files.
108409467b48Spatrick   if (ViewOpts.hasOutputDirectory()) {
108509467b48Spatrick     if (Error E = Printer->createIndexFile(SourceFiles, *Coverage, Filters)) {
108609467b48Spatrick       error("Could not create index file!", toString(std::move(E)));
108709467b48Spatrick       return 1;
108809467b48Spatrick     }
108909467b48Spatrick   }
109009467b48Spatrick 
109109467b48Spatrick   if (!Filters.empty()) {
109209467b48Spatrick     // Build the map of filenames to functions.
109309467b48Spatrick     std::map<llvm::StringRef, std::vector<const FunctionRecord *>>
109409467b48Spatrick         FilenameFunctionMap;
109509467b48Spatrick     for (const auto &SourceFile : SourceFiles)
109609467b48Spatrick       for (const auto &Function : Coverage->getCoveredFunctions(SourceFile))
1097*d415bd75Srobert         if (Filters.matches(*Coverage, Function))
109809467b48Spatrick           FilenameFunctionMap[SourceFile].push_back(&Function);
109909467b48Spatrick 
110009467b48Spatrick     // Only print filter matching functions for each file.
110109467b48Spatrick     for (const auto &FileFunc : FilenameFunctionMap) {
110209467b48Spatrick       StringRef File = FileFunc.first;
110309467b48Spatrick       const auto &Functions = FileFunc.second;
110409467b48Spatrick 
110509467b48Spatrick       auto OSOrErr = Printer->createViewFile(File, /*InToplevel=*/false);
110609467b48Spatrick       if (Error E = OSOrErr.takeError()) {
110709467b48Spatrick         error("Could not create view file!", toString(std::move(E)));
110809467b48Spatrick         return 1;
110909467b48Spatrick       }
111009467b48Spatrick       auto OS = std::move(OSOrErr.get());
111109467b48Spatrick 
111209467b48Spatrick       bool ShowTitle = ViewOpts.hasOutputDirectory();
111309467b48Spatrick       for (const auto *Function : Functions) {
111409467b48Spatrick         auto FunctionView = createFunctionView(*Function, *Coverage);
111509467b48Spatrick         if (!FunctionView) {
111609467b48Spatrick           warning("Could not read coverage for '" + Function->Name + "'.");
111709467b48Spatrick           continue;
111809467b48Spatrick         }
111909467b48Spatrick         FunctionView->print(*OS.get(), /*WholeFile=*/false,
112009467b48Spatrick                             /*ShowSourceName=*/true, ShowTitle);
112109467b48Spatrick         ShowTitle = false;
112209467b48Spatrick       }
112309467b48Spatrick 
112409467b48Spatrick       Printer->closeViewFile(std::move(OS));
112509467b48Spatrick     }
112609467b48Spatrick     return 0;
112709467b48Spatrick   }
112809467b48Spatrick 
112909467b48Spatrick   // Show files
113009467b48Spatrick   bool ShowFilenames =
113109467b48Spatrick       (SourceFiles.size() != 1) || ViewOpts.hasOutputDirectory() ||
113209467b48Spatrick       (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML);
113309467b48Spatrick 
1134097a140dSpatrick   ThreadPoolStrategy S = hardware_concurrency(ViewOpts.NumThreads);
1135097a140dSpatrick   if (ViewOpts.NumThreads == 0) {
1136097a140dSpatrick     // If NumThreads is not specified, create one thread for each input, up to
1137097a140dSpatrick     // the number of hardware cores.
1138097a140dSpatrick     S = heavyweight_hardware_concurrency(SourceFiles.size());
1139097a140dSpatrick     S.Limit = true;
1140097a140dSpatrick   }
114109467b48Spatrick 
1142097a140dSpatrick   if (!ViewOpts.hasOutputDirectory() || S.ThreadsRequested == 1) {
114309467b48Spatrick     for (const std::string &SourceFile : SourceFiles)
114409467b48Spatrick       writeSourceFileView(SourceFile, Coverage.get(), Printer.get(),
114509467b48Spatrick                           ShowFilenames);
114609467b48Spatrick   } else {
114709467b48Spatrick     // In -output-dir mode, it's safe to use multiple threads to print files.
1148097a140dSpatrick     ThreadPool Pool(S);
114909467b48Spatrick     for (const std::string &SourceFile : SourceFiles)
115009467b48Spatrick       Pool.async(&CodeCoverageTool::writeSourceFileView, this, SourceFile,
115109467b48Spatrick                  Coverage.get(), Printer.get(), ShowFilenames);
115209467b48Spatrick     Pool.wait();
115309467b48Spatrick   }
115409467b48Spatrick 
115509467b48Spatrick   return 0;
115609467b48Spatrick }
115709467b48Spatrick 
doReport(int argc,const char ** argv,CommandLineParserType commandLineParser)115809467b48Spatrick int CodeCoverageTool::doReport(int argc, const char **argv,
115909467b48Spatrick                                CommandLineParserType commandLineParser) {
116009467b48Spatrick   cl::opt<bool> ShowFunctionSummaries(
116109467b48Spatrick       "show-functions", cl::Optional, cl::init(false),
116209467b48Spatrick       cl::desc("Show coverage summaries for each function"));
116309467b48Spatrick 
116409467b48Spatrick   auto Err = commandLineParser(argc, argv);
116509467b48Spatrick   if (Err)
116609467b48Spatrick     return Err;
116709467b48Spatrick 
116809467b48Spatrick   if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) {
116909467b48Spatrick     error("HTML output for summary reports is not yet supported.");
117009467b48Spatrick     return 1;
117109467b48Spatrick   } else if (ViewOpts.Format == CoverageViewOptions::OutputFormat::Lcov) {
117209467b48Spatrick     error("Lcov format should be used with 'llvm-cov export'.");
117309467b48Spatrick     return 1;
117409467b48Spatrick   }
117509467b48Spatrick 
1176*d415bd75Srobert   sys::fs::file_status Status;
1177*d415bd75Srobert   if (std::error_code EC = sys::fs::status(PGOFilename, Status)) {
1178*d415bd75Srobert     error("Could not read profile data!" + EC.message(), PGOFilename);
1179*d415bd75Srobert     return 1;
1180*d415bd75Srobert   }
1181*d415bd75Srobert 
118209467b48Spatrick   auto Coverage = load();
118309467b48Spatrick   if (!Coverage)
118409467b48Spatrick     return 1;
118509467b48Spatrick 
1186*d415bd75Srobert   CoverageReport Report(ViewOpts, *Coverage);
118709467b48Spatrick   if (!ShowFunctionSummaries) {
118809467b48Spatrick     if (SourceFiles.empty())
118909467b48Spatrick       Report.renderFileReports(llvm::outs(), IgnoreFilenameFilters);
119009467b48Spatrick     else
119109467b48Spatrick       Report.renderFileReports(llvm::outs(), SourceFiles);
119209467b48Spatrick   } else {
119309467b48Spatrick     if (SourceFiles.empty()) {
119409467b48Spatrick       error("Source files must be specified when -show-functions=true is "
119509467b48Spatrick             "specified");
119609467b48Spatrick       return 1;
119709467b48Spatrick     }
119809467b48Spatrick 
119909467b48Spatrick     Report.renderFunctionReports(SourceFiles, DC, llvm::outs());
120009467b48Spatrick   }
120109467b48Spatrick   return 0;
120209467b48Spatrick }
120309467b48Spatrick 
doExport(int argc,const char ** argv,CommandLineParserType commandLineParser)120409467b48Spatrick int CodeCoverageTool::doExport(int argc, const char **argv,
120509467b48Spatrick                                CommandLineParserType commandLineParser) {
120609467b48Spatrick 
120709467b48Spatrick   cl::OptionCategory ExportCategory("Exporting options");
120809467b48Spatrick 
120909467b48Spatrick   cl::opt<bool> SkipExpansions("skip-expansions", cl::Optional,
121009467b48Spatrick                                cl::desc("Don't export expanded source regions"),
121109467b48Spatrick                                cl::cat(ExportCategory));
121209467b48Spatrick 
121309467b48Spatrick   cl::opt<bool> SkipFunctions("skip-functions", cl::Optional,
121409467b48Spatrick                               cl::desc("Don't export per-function data"),
121509467b48Spatrick                               cl::cat(ExportCategory));
121609467b48Spatrick 
1217*d415bd75Srobert   cl::opt<bool> SkipBranches("skip-branches", cl::Optional,
1218*d415bd75Srobert                               cl::desc("Don't export branch data (LCOV)"),
1219*d415bd75Srobert                               cl::cat(ExportCategory));
1220*d415bd75Srobert 
122109467b48Spatrick   auto Err = commandLineParser(argc, argv);
122209467b48Spatrick   if (Err)
122309467b48Spatrick     return Err;
122409467b48Spatrick 
122509467b48Spatrick   ViewOpts.SkipExpansions = SkipExpansions;
122609467b48Spatrick   ViewOpts.SkipFunctions = SkipFunctions;
1227*d415bd75Srobert   ViewOpts.SkipBranches = SkipBranches;
122809467b48Spatrick 
122909467b48Spatrick   if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text &&
123009467b48Spatrick       ViewOpts.Format != CoverageViewOptions::OutputFormat::Lcov) {
123109467b48Spatrick     error("Coverage data can only be exported as textual JSON or an "
123209467b48Spatrick           "lcov tracefile.");
123309467b48Spatrick     return 1;
123409467b48Spatrick   }
123509467b48Spatrick 
1236*d415bd75Srobert   sys::fs::file_status Status;
1237*d415bd75Srobert   if (std::error_code EC = sys::fs::status(PGOFilename, Status)) {
1238*d415bd75Srobert     error("Could not read profile data!" + EC.message(), PGOFilename);
1239*d415bd75Srobert     return 1;
1240*d415bd75Srobert   }
1241*d415bd75Srobert 
124209467b48Spatrick   auto Coverage = load();
124309467b48Spatrick   if (!Coverage) {
124409467b48Spatrick     error("Could not load coverage information");
124509467b48Spatrick     return 1;
124609467b48Spatrick   }
124709467b48Spatrick 
124809467b48Spatrick   std::unique_ptr<CoverageExporter> Exporter;
124909467b48Spatrick 
125009467b48Spatrick   switch (ViewOpts.Format) {
125109467b48Spatrick   case CoverageViewOptions::OutputFormat::Text:
1252*d415bd75Srobert     Exporter =
1253*d415bd75Srobert         std::make_unique<CoverageExporterJson>(*Coverage, ViewOpts, outs());
125409467b48Spatrick     break;
125509467b48Spatrick   case CoverageViewOptions::OutputFormat::HTML:
125609467b48Spatrick     // Unreachable because we should have gracefully terminated with an error
125709467b48Spatrick     // above.
125809467b48Spatrick     llvm_unreachable("Export in HTML is not supported!");
125909467b48Spatrick   case CoverageViewOptions::OutputFormat::Lcov:
1260*d415bd75Srobert     Exporter =
1261*d415bd75Srobert         std::make_unique<CoverageExporterLcov>(*Coverage, ViewOpts, outs());
126209467b48Spatrick     break;
126309467b48Spatrick   }
126409467b48Spatrick 
126509467b48Spatrick   if (SourceFiles.empty())
126609467b48Spatrick     Exporter->renderRoot(IgnoreFilenameFilters);
126709467b48Spatrick   else
126809467b48Spatrick     Exporter->renderRoot(SourceFiles);
126909467b48Spatrick 
127009467b48Spatrick   return 0;
127109467b48Spatrick }
127209467b48Spatrick 
showMain(int argc,const char * argv[])127309467b48Spatrick int showMain(int argc, const char *argv[]) {
127409467b48Spatrick   CodeCoverageTool Tool;
127509467b48Spatrick   return Tool.run(CodeCoverageTool::Show, argc, argv);
127609467b48Spatrick }
127709467b48Spatrick 
reportMain(int argc,const char * argv[])127809467b48Spatrick int reportMain(int argc, const char *argv[]) {
127909467b48Spatrick   CodeCoverageTool Tool;
128009467b48Spatrick   return Tool.run(CodeCoverageTool::Report, argc, argv);
128109467b48Spatrick }
128209467b48Spatrick 
exportMain(int argc,const char * argv[])128309467b48Spatrick int exportMain(int argc, const char *argv[]) {
128409467b48Spatrick   CodeCoverageTool Tool;
128509467b48Spatrick   return Tool.run(CodeCoverageTool::Export, argc, argv);
128609467b48Spatrick }
1287