xref: /netbsd-src/external/apache2/llvm/dist/llvm/tools/llvm-cov/CodeCoverage.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
17330f729Sjoerg //===- CodeCoverage.cpp - Coverage tool based on profiling instrumentation-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // The 'CodeCoverageTool' class implements a command line tool to analyze and
107330f729Sjoerg // report coverage information using the profiling instrumentation and code
117330f729Sjoerg // coverage mapping.
127330f729Sjoerg //
137330f729Sjoerg //===----------------------------------------------------------------------===//
147330f729Sjoerg 
157330f729Sjoerg #include "CoverageExporterJson.h"
167330f729Sjoerg #include "CoverageExporterLcov.h"
177330f729Sjoerg #include "CoverageFilters.h"
187330f729Sjoerg #include "CoverageReport.h"
197330f729Sjoerg #include "CoverageSummaryInfo.h"
207330f729Sjoerg #include "CoverageViewOptions.h"
217330f729Sjoerg #include "RenderingSupport.h"
227330f729Sjoerg #include "SourceCoverageView.h"
237330f729Sjoerg #include "llvm/ADT/SmallString.h"
247330f729Sjoerg #include "llvm/ADT/StringRef.h"
257330f729Sjoerg #include "llvm/ADT/Triple.h"
267330f729Sjoerg #include "llvm/ProfileData/Coverage/CoverageMapping.h"
277330f729Sjoerg #include "llvm/ProfileData/InstrProfReader.h"
287330f729Sjoerg #include "llvm/Support/CommandLine.h"
297330f729Sjoerg #include "llvm/Support/FileSystem.h"
307330f729Sjoerg #include "llvm/Support/Format.h"
317330f729Sjoerg #include "llvm/Support/MemoryBuffer.h"
327330f729Sjoerg #include "llvm/Support/Path.h"
337330f729Sjoerg #include "llvm/Support/Process.h"
347330f729Sjoerg #include "llvm/Support/Program.h"
357330f729Sjoerg #include "llvm/Support/ScopedPrinter.h"
36*82d56013Sjoerg #include "llvm/Support/SpecialCaseList.h"
377330f729Sjoerg #include "llvm/Support/ThreadPool.h"
387330f729Sjoerg #include "llvm/Support/Threading.h"
397330f729Sjoerg #include "llvm/Support/ToolOutputFile.h"
40*82d56013Sjoerg #include "llvm/Support/VirtualFileSystem.h"
417330f729Sjoerg 
427330f729Sjoerg #include <functional>
437330f729Sjoerg #include <map>
447330f729Sjoerg #include <system_error>
457330f729Sjoerg 
467330f729Sjoerg using namespace llvm;
477330f729Sjoerg using namespace coverage;
487330f729Sjoerg 
497330f729Sjoerg void exportCoverageDataToJson(const coverage::CoverageMapping &CoverageMapping,
507330f729Sjoerg                               const CoverageViewOptions &Options,
517330f729Sjoerg                               raw_ostream &OS);
527330f729Sjoerg 
537330f729Sjoerg namespace {
547330f729Sjoerg /// The implementation of the coverage tool.
557330f729Sjoerg class CodeCoverageTool {
567330f729Sjoerg public:
577330f729Sjoerg   enum Command {
587330f729Sjoerg     /// The show command.
597330f729Sjoerg     Show,
607330f729Sjoerg     /// The report command.
617330f729Sjoerg     Report,
627330f729Sjoerg     /// The export command.
637330f729Sjoerg     Export
647330f729Sjoerg   };
657330f729Sjoerg 
667330f729Sjoerg   int run(Command Cmd, int argc, const char **argv);
677330f729Sjoerg 
687330f729Sjoerg private:
697330f729Sjoerg   /// Print the error message to the error output stream.
707330f729Sjoerg   void error(const Twine &Message, StringRef Whence = "");
717330f729Sjoerg 
727330f729Sjoerg   /// Print the warning message to the error output stream.
737330f729Sjoerg   void warning(const Twine &Message, StringRef Whence = "");
747330f729Sjoerg 
757330f729Sjoerg   /// Convert \p Path into an absolute path and append it to the list
767330f729Sjoerg   /// of collected paths.
777330f729Sjoerg   void addCollectedPath(const std::string &Path);
787330f729Sjoerg 
797330f729Sjoerg   /// If \p Path is a regular file, collect the path. If it's a
807330f729Sjoerg   /// directory, recursively collect all of the paths within the directory.
817330f729Sjoerg   void collectPaths(const std::string &Path);
827330f729Sjoerg 
83*82d56013Sjoerg   /// Check if the two given files are the same file.
84*82d56013Sjoerg   bool isEquivalentFile(StringRef FilePath1, StringRef FilePath2);
85*82d56013Sjoerg 
86*82d56013Sjoerg   /// Retrieve a file status with a cache.
87*82d56013Sjoerg   Optional<sys::fs::file_status> getFileStatus(StringRef FilePath);
88*82d56013Sjoerg 
897330f729Sjoerg   /// Return a memory buffer for the given source file.
907330f729Sjoerg   ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
917330f729Sjoerg 
927330f729Sjoerg   /// Create source views for the expansions of the view.
937330f729Sjoerg   void attachExpansionSubViews(SourceCoverageView &View,
947330f729Sjoerg                                ArrayRef<ExpansionRecord> Expansions,
957330f729Sjoerg                                const CoverageMapping &Coverage);
967330f729Sjoerg 
97*82d56013Sjoerg   /// Create source views for the branches of the view.
98*82d56013Sjoerg   void attachBranchSubViews(SourceCoverageView &View, StringRef SourceName,
99*82d56013Sjoerg                             ArrayRef<CountedRegion> Branches,
100*82d56013Sjoerg                             const MemoryBuffer &File,
101*82d56013Sjoerg                             CoverageData &CoverageInfo);
102*82d56013Sjoerg 
1037330f729Sjoerg   /// Create the source view of a particular function.
1047330f729Sjoerg   std::unique_ptr<SourceCoverageView>
1057330f729Sjoerg   createFunctionView(const FunctionRecord &Function,
1067330f729Sjoerg                      const CoverageMapping &Coverage);
1077330f729Sjoerg 
1087330f729Sjoerg   /// Create the main source view of a particular source file.
1097330f729Sjoerg   std::unique_ptr<SourceCoverageView>
1107330f729Sjoerg   createSourceFileView(StringRef SourceFile, const CoverageMapping &Coverage);
1117330f729Sjoerg 
1127330f729Sjoerg   /// Load the coverage mapping data. Return nullptr if an error occurred.
1137330f729Sjoerg   std::unique_ptr<CoverageMapping> load();
1147330f729Sjoerg 
1157330f729Sjoerg   /// Create a mapping from files in the Coverage data to local copies
1167330f729Sjoerg   /// (path-equivalence).
1177330f729Sjoerg   void remapPathNames(const CoverageMapping &Coverage);
1187330f729Sjoerg 
1197330f729Sjoerg   /// Remove input source files which aren't mapped by \p Coverage.
1207330f729Sjoerg   void removeUnmappedInputs(const CoverageMapping &Coverage);
1217330f729Sjoerg 
1227330f729Sjoerg   /// If a demangler is available, demangle all symbol names.
1237330f729Sjoerg   void demangleSymbols(const CoverageMapping &Coverage);
1247330f729Sjoerg 
1257330f729Sjoerg   /// Write out a source file view to the filesystem.
1267330f729Sjoerg   void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage,
1277330f729Sjoerg                            CoveragePrinter *Printer, bool ShowFilenames);
1287330f729Sjoerg 
1297330f729Sjoerg   typedef llvm::function_ref<int(int, const char **)> CommandLineParserType;
1307330f729Sjoerg 
1317330f729Sjoerg   int doShow(int argc, const char **argv,
1327330f729Sjoerg              CommandLineParserType commandLineParser);
1337330f729Sjoerg 
1347330f729Sjoerg   int doReport(int argc, const char **argv,
1357330f729Sjoerg                CommandLineParserType commandLineParser);
1367330f729Sjoerg 
1377330f729Sjoerg   int doExport(int argc, const char **argv,
1387330f729Sjoerg                CommandLineParserType commandLineParser);
1397330f729Sjoerg 
1407330f729Sjoerg   std::vector<StringRef> ObjectFilenames;
1417330f729Sjoerg   CoverageViewOptions ViewOpts;
1427330f729Sjoerg   CoverageFiltersMatchAll Filters;
1437330f729Sjoerg   CoverageFilters IgnoreFilenameFilters;
1447330f729Sjoerg 
145*82d56013Sjoerg   /// True if InputSourceFiles are provided.
146*82d56013Sjoerg   bool HadSourceFiles = false;
147*82d56013Sjoerg 
1487330f729Sjoerg   /// The path to the indexed profile.
1497330f729Sjoerg   std::string PGOFilename;
1507330f729Sjoerg 
1517330f729Sjoerg   /// A list of input source files.
1527330f729Sjoerg   std::vector<std::string> SourceFiles;
1537330f729Sjoerg 
1547330f729Sjoerg   /// In -path-equivalence mode, this maps the absolute paths from the coverage
1557330f729Sjoerg   /// mapping data to the input source files.
1567330f729Sjoerg   StringMap<std::string> RemappedFilenames;
1577330f729Sjoerg 
1587330f729Sjoerg   /// The coverage data path to be remapped from, and the source path to be
1597330f729Sjoerg   /// remapped to, when using -path-equivalence.
1607330f729Sjoerg   Optional<std::pair<std::string, std::string>> PathRemapping;
1617330f729Sjoerg 
162*82d56013Sjoerg   /// File status cache used when finding the same file.
163*82d56013Sjoerg   StringMap<Optional<sys::fs::file_status>> FileStatusCache;
164*82d56013Sjoerg 
1657330f729Sjoerg   /// The architecture the coverage mapping data targets.
1667330f729Sjoerg   std::vector<StringRef> CoverageArches;
1677330f729Sjoerg 
1687330f729Sjoerg   /// A cache for demangled symbols.
1697330f729Sjoerg   DemangleCache DC;
1707330f729Sjoerg 
1717330f729Sjoerg   /// A lock which guards printing to stderr.
1727330f729Sjoerg   std::mutex ErrsLock;
1737330f729Sjoerg 
1747330f729Sjoerg   /// A container for input source file buffers.
1757330f729Sjoerg   std::mutex LoadedSourceFilesLock;
1767330f729Sjoerg   std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
1777330f729Sjoerg       LoadedSourceFiles;
1787330f729Sjoerg 
1797330f729Sjoerg   /// Whitelist from -name-whitelist to be used for filtering.
1807330f729Sjoerg   std::unique_ptr<SpecialCaseList> NameWhitelist;
1817330f729Sjoerg };
1827330f729Sjoerg }
1837330f729Sjoerg 
getErrorString(const Twine & Message,StringRef Whence,bool Warning)1847330f729Sjoerg static std::string getErrorString(const Twine &Message, StringRef Whence,
1857330f729Sjoerg                                   bool Warning) {
1867330f729Sjoerg   std::string Str = (Warning ? "warning" : "error");
1877330f729Sjoerg   Str += ": ";
1887330f729Sjoerg   if (!Whence.empty())
1897330f729Sjoerg     Str += Whence.str() + ": ";
1907330f729Sjoerg   Str += Message.str() + "\n";
1917330f729Sjoerg   return Str;
1927330f729Sjoerg }
1937330f729Sjoerg 
error(const Twine & Message,StringRef Whence)1947330f729Sjoerg void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
1957330f729Sjoerg   std::unique_lock<std::mutex> Guard{ErrsLock};
1967330f729Sjoerg   ViewOpts.colored_ostream(errs(), raw_ostream::RED)
1977330f729Sjoerg       << getErrorString(Message, Whence, false);
1987330f729Sjoerg }
1997330f729Sjoerg 
warning(const Twine & Message,StringRef Whence)2007330f729Sjoerg void CodeCoverageTool::warning(const Twine &Message, StringRef Whence) {
2017330f729Sjoerg   std::unique_lock<std::mutex> Guard{ErrsLock};
2027330f729Sjoerg   ViewOpts.colored_ostream(errs(), raw_ostream::RED)
2037330f729Sjoerg       << getErrorString(Message, Whence, true);
2047330f729Sjoerg }
2057330f729Sjoerg 
addCollectedPath(const std::string & Path)2067330f729Sjoerg void CodeCoverageTool::addCollectedPath(const std::string &Path) {
2077330f729Sjoerg   SmallString<128> EffectivePath(Path);
2087330f729Sjoerg   if (std::error_code EC = sys::fs::make_absolute(EffectivePath)) {
2097330f729Sjoerg     error(EC.message(), Path);
2107330f729Sjoerg     return;
2117330f729Sjoerg   }
2127330f729Sjoerg   sys::path::remove_dots(EffectivePath, /*remove_dot_dots=*/true);
2137330f729Sjoerg   if (!IgnoreFilenameFilters.matchesFilename(EffectivePath))
2147330f729Sjoerg     SourceFiles.emplace_back(EffectivePath.str());
215*82d56013Sjoerg   HadSourceFiles = !SourceFiles.empty();
2167330f729Sjoerg }
2177330f729Sjoerg 
collectPaths(const std::string & Path)2187330f729Sjoerg void CodeCoverageTool::collectPaths(const std::string &Path) {
2197330f729Sjoerg   llvm::sys::fs::file_status Status;
2207330f729Sjoerg   llvm::sys::fs::status(Path, Status);
2217330f729Sjoerg   if (!llvm::sys::fs::exists(Status)) {
2227330f729Sjoerg     if (PathRemapping)
2237330f729Sjoerg       addCollectedPath(Path);
2247330f729Sjoerg     else
2257330f729Sjoerg       warning("Source file doesn't exist, proceeded by ignoring it.", Path);
2267330f729Sjoerg     return;
2277330f729Sjoerg   }
2287330f729Sjoerg 
2297330f729Sjoerg   if (llvm::sys::fs::is_regular_file(Status)) {
2307330f729Sjoerg     addCollectedPath(Path);
2317330f729Sjoerg     return;
2327330f729Sjoerg   }
2337330f729Sjoerg 
2347330f729Sjoerg   if (llvm::sys::fs::is_directory(Status)) {
2357330f729Sjoerg     std::error_code EC;
2367330f729Sjoerg     for (llvm::sys::fs::recursive_directory_iterator F(Path, EC), E;
2377330f729Sjoerg          F != E; F.increment(EC)) {
2387330f729Sjoerg 
2397330f729Sjoerg       auto Status = F->status();
2407330f729Sjoerg       if (!Status) {
2417330f729Sjoerg         warning(Status.getError().message(), F->path());
2427330f729Sjoerg         continue;
2437330f729Sjoerg       }
2447330f729Sjoerg 
2457330f729Sjoerg       if (Status->type() == llvm::sys::fs::file_type::regular_file)
2467330f729Sjoerg         addCollectedPath(F->path());
2477330f729Sjoerg     }
2487330f729Sjoerg   }
2497330f729Sjoerg }
2507330f729Sjoerg 
251*82d56013Sjoerg Optional<sys::fs::file_status>
getFileStatus(StringRef FilePath)252*82d56013Sjoerg CodeCoverageTool::getFileStatus(StringRef FilePath) {
253*82d56013Sjoerg   auto It = FileStatusCache.try_emplace(FilePath);
254*82d56013Sjoerg   auto &CachedStatus = It.first->getValue();
255*82d56013Sjoerg   if (!It.second)
256*82d56013Sjoerg     return CachedStatus;
257*82d56013Sjoerg 
258*82d56013Sjoerg   sys::fs::file_status Status;
259*82d56013Sjoerg   if (!sys::fs::status(FilePath, Status))
260*82d56013Sjoerg     CachedStatus = Status;
261*82d56013Sjoerg   return CachedStatus;
262*82d56013Sjoerg }
263*82d56013Sjoerg 
isEquivalentFile(StringRef FilePath1,StringRef FilePath2)264*82d56013Sjoerg bool CodeCoverageTool::isEquivalentFile(StringRef FilePath1,
265*82d56013Sjoerg                                         StringRef FilePath2) {
266*82d56013Sjoerg   auto Status1 = getFileStatus(FilePath1);
267*82d56013Sjoerg   auto Status2 = getFileStatus(FilePath2);
268*82d56013Sjoerg   return Status1.hasValue() && Status2.hasValue() &&
269*82d56013Sjoerg          sys::fs::equivalent(Status1.getValue(), Status2.getValue());
270*82d56013Sjoerg }
271*82d56013Sjoerg 
2727330f729Sjoerg ErrorOr<const MemoryBuffer &>
getSourceFile(StringRef SourceFile)2737330f729Sjoerg CodeCoverageTool::getSourceFile(StringRef SourceFile) {
2747330f729Sjoerg   // If we've remapped filenames, look up the real location for this file.
2757330f729Sjoerg   std::unique_lock<std::mutex> Guard{LoadedSourceFilesLock};
2767330f729Sjoerg   if (!RemappedFilenames.empty()) {
2777330f729Sjoerg     auto Loc = RemappedFilenames.find(SourceFile);
2787330f729Sjoerg     if (Loc != RemappedFilenames.end())
2797330f729Sjoerg       SourceFile = Loc->second;
2807330f729Sjoerg   }
2817330f729Sjoerg   for (const auto &Files : LoadedSourceFiles)
282*82d56013Sjoerg     if (isEquivalentFile(SourceFile, Files.first))
2837330f729Sjoerg       return *Files.second;
2847330f729Sjoerg   auto Buffer = MemoryBuffer::getFile(SourceFile);
2857330f729Sjoerg   if (auto EC = Buffer.getError()) {
2867330f729Sjoerg     error(EC.message(), SourceFile);
2877330f729Sjoerg     return EC;
2887330f729Sjoerg   }
289*82d56013Sjoerg   LoadedSourceFiles.emplace_back(std::string(SourceFile),
290*82d56013Sjoerg                                  std::move(Buffer.get()));
2917330f729Sjoerg   return *LoadedSourceFiles.back().second;
2927330f729Sjoerg }
2937330f729Sjoerg 
attachExpansionSubViews(SourceCoverageView & View,ArrayRef<ExpansionRecord> Expansions,const CoverageMapping & Coverage)2947330f729Sjoerg void CodeCoverageTool::attachExpansionSubViews(
2957330f729Sjoerg     SourceCoverageView &View, ArrayRef<ExpansionRecord> Expansions,
2967330f729Sjoerg     const CoverageMapping &Coverage) {
2977330f729Sjoerg   if (!ViewOpts.ShowExpandedRegions)
2987330f729Sjoerg     return;
2997330f729Sjoerg   for (const auto &Expansion : Expansions) {
3007330f729Sjoerg     auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
3017330f729Sjoerg     if (ExpansionCoverage.empty())
3027330f729Sjoerg       continue;
3037330f729Sjoerg     auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
3047330f729Sjoerg     if (!SourceBuffer)
3057330f729Sjoerg       continue;
3067330f729Sjoerg 
307*82d56013Sjoerg     auto SubViewBranches = ExpansionCoverage.getBranches();
3087330f729Sjoerg     auto SubViewExpansions = ExpansionCoverage.getExpansions();
3097330f729Sjoerg     auto SubView =
3107330f729Sjoerg         SourceCoverageView::create(Expansion.Function.Name, SourceBuffer.get(),
3117330f729Sjoerg                                    ViewOpts, std::move(ExpansionCoverage));
3127330f729Sjoerg     attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
313*82d56013Sjoerg     attachBranchSubViews(*SubView, Expansion.Function.Name, SubViewBranches,
314*82d56013Sjoerg                          SourceBuffer.get(), ExpansionCoverage);
3157330f729Sjoerg     View.addExpansion(Expansion.Region, std::move(SubView));
3167330f729Sjoerg   }
3177330f729Sjoerg }
3187330f729Sjoerg 
attachBranchSubViews(SourceCoverageView & View,StringRef SourceName,ArrayRef<CountedRegion> Branches,const MemoryBuffer & File,CoverageData & CoverageInfo)319*82d56013Sjoerg void CodeCoverageTool::attachBranchSubViews(SourceCoverageView &View,
320*82d56013Sjoerg                                             StringRef SourceName,
321*82d56013Sjoerg                                             ArrayRef<CountedRegion> Branches,
322*82d56013Sjoerg                                             const MemoryBuffer &File,
323*82d56013Sjoerg                                             CoverageData &CoverageInfo) {
324*82d56013Sjoerg   if (!ViewOpts.ShowBranchCounts && !ViewOpts.ShowBranchPercents)
325*82d56013Sjoerg     return;
326*82d56013Sjoerg 
327*82d56013Sjoerg   const auto *NextBranch = Branches.begin();
328*82d56013Sjoerg   const auto *EndBranch = Branches.end();
329*82d56013Sjoerg 
330*82d56013Sjoerg   // Group branches that have the same line number into the same subview.
331*82d56013Sjoerg   while (NextBranch != EndBranch) {
332*82d56013Sjoerg     std::vector<CountedRegion> ViewBranches;
333*82d56013Sjoerg     unsigned CurrentLine = NextBranch->LineStart;
334*82d56013Sjoerg 
335*82d56013Sjoerg     while (NextBranch != EndBranch && CurrentLine == NextBranch->LineStart)
336*82d56013Sjoerg       ViewBranches.push_back(*NextBranch++);
337*82d56013Sjoerg 
338*82d56013Sjoerg     if (!ViewBranches.empty()) {
339*82d56013Sjoerg       auto SubView = SourceCoverageView::create(SourceName, File, ViewOpts,
340*82d56013Sjoerg                                                 std::move(CoverageInfo));
341*82d56013Sjoerg       View.addBranch(CurrentLine, ViewBranches, std::move(SubView));
342*82d56013Sjoerg     }
343*82d56013Sjoerg   }
344*82d56013Sjoerg }
345*82d56013Sjoerg 
3467330f729Sjoerg std::unique_ptr<SourceCoverageView>
createFunctionView(const FunctionRecord & Function,const CoverageMapping & Coverage)3477330f729Sjoerg CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
3487330f729Sjoerg                                      const CoverageMapping &Coverage) {
3497330f729Sjoerg   auto FunctionCoverage = Coverage.getCoverageForFunction(Function);
3507330f729Sjoerg   if (FunctionCoverage.empty())
3517330f729Sjoerg     return nullptr;
3527330f729Sjoerg   auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename());
3537330f729Sjoerg   if (!SourceBuffer)
3547330f729Sjoerg     return nullptr;
3557330f729Sjoerg 
356*82d56013Sjoerg   auto Branches = FunctionCoverage.getBranches();
3577330f729Sjoerg   auto Expansions = FunctionCoverage.getExpansions();
3587330f729Sjoerg   auto View = SourceCoverageView::create(DC.demangle(Function.Name),
3597330f729Sjoerg                                          SourceBuffer.get(), ViewOpts,
3607330f729Sjoerg                                          std::move(FunctionCoverage));
3617330f729Sjoerg   attachExpansionSubViews(*View, Expansions, Coverage);
362*82d56013Sjoerg   attachBranchSubViews(*View, DC.demangle(Function.Name), Branches,
363*82d56013Sjoerg                        SourceBuffer.get(), FunctionCoverage);
3647330f729Sjoerg 
3657330f729Sjoerg   return View;
3667330f729Sjoerg }
3677330f729Sjoerg 
3687330f729Sjoerg std::unique_ptr<SourceCoverageView>
createSourceFileView(StringRef SourceFile,const CoverageMapping & Coverage)3697330f729Sjoerg CodeCoverageTool::createSourceFileView(StringRef SourceFile,
3707330f729Sjoerg                                        const CoverageMapping &Coverage) {
3717330f729Sjoerg   auto SourceBuffer = getSourceFile(SourceFile);
3727330f729Sjoerg   if (!SourceBuffer)
3737330f729Sjoerg     return nullptr;
3747330f729Sjoerg   auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
3757330f729Sjoerg   if (FileCoverage.empty())
3767330f729Sjoerg     return nullptr;
3777330f729Sjoerg 
378*82d56013Sjoerg   auto Branches = FileCoverage.getBranches();
3797330f729Sjoerg   auto Expansions = FileCoverage.getExpansions();
3807330f729Sjoerg   auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
3817330f729Sjoerg                                          ViewOpts, std::move(FileCoverage));
3827330f729Sjoerg   attachExpansionSubViews(*View, Expansions, Coverage);
383*82d56013Sjoerg   attachBranchSubViews(*View, SourceFile, Branches, SourceBuffer.get(),
384*82d56013Sjoerg                        FileCoverage);
3857330f729Sjoerg   if (!ViewOpts.ShowFunctionInstantiations)
3867330f729Sjoerg     return View;
3877330f729Sjoerg 
3887330f729Sjoerg   for (const auto &Group : Coverage.getInstantiationGroups(SourceFile)) {
3897330f729Sjoerg     // Skip functions which have a single instantiation.
3907330f729Sjoerg     if (Group.size() < 2)
3917330f729Sjoerg       continue;
3927330f729Sjoerg 
3937330f729Sjoerg     for (const FunctionRecord *Function : Group.getInstantiations()) {
3947330f729Sjoerg       std::unique_ptr<SourceCoverageView> SubView{nullptr};
3957330f729Sjoerg 
3967330f729Sjoerg       StringRef Funcname = DC.demangle(Function->Name);
3977330f729Sjoerg 
3987330f729Sjoerg       if (Function->ExecutionCount > 0) {
3997330f729Sjoerg         auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
4007330f729Sjoerg         auto SubViewExpansions = SubViewCoverage.getExpansions();
401*82d56013Sjoerg         auto SubViewBranches = SubViewCoverage.getBranches();
4027330f729Sjoerg         SubView = SourceCoverageView::create(
4037330f729Sjoerg             Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
4047330f729Sjoerg         attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
405*82d56013Sjoerg         attachBranchSubViews(*SubView, SourceFile, SubViewBranches,
406*82d56013Sjoerg                              SourceBuffer.get(), SubViewCoverage);
4077330f729Sjoerg       }
4087330f729Sjoerg 
4097330f729Sjoerg       unsigned FileID = Function->CountedRegions.front().FileID;
4107330f729Sjoerg       unsigned Line = 0;
4117330f729Sjoerg       for (const auto &CR : Function->CountedRegions)
4127330f729Sjoerg         if (CR.FileID == FileID)
4137330f729Sjoerg           Line = std::max(CR.LineEnd, Line);
4147330f729Sjoerg       View->addInstantiation(Funcname, Line, std::move(SubView));
4157330f729Sjoerg     }
4167330f729Sjoerg   }
4177330f729Sjoerg   return View;
4187330f729Sjoerg }
4197330f729Sjoerg 
modifiedTimeGT(StringRef LHS,StringRef RHS)4207330f729Sjoerg static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
4217330f729Sjoerg   sys::fs::file_status Status;
4227330f729Sjoerg   if (sys::fs::status(LHS, Status))
4237330f729Sjoerg     return false;
4247330f729Sjoerg   auto LHSTime = Status.getLastModificationTime();
4257330f729Sjoerg   if (sys::fs::status(RHS, Status))
4267330f729Sjoerg     return false;
4277330f729Sjoerg   auto RHSTime = Status.getLastModificationTime();
4287330f729Sjoerg   return LHSTime > RHSTime;
4297330f729Sjoerg }
4307330f729Sjoerg 
load()4317330f729Sjoerg std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
4327330f729Sjoerg   for (StringRef ObjectFilename : ObjectFilenames)
4337330f729Sjoerg     if (modifiedTimeGT(ObjectFilename, PGOFilename))
4347330f729Sjoerg       warning("profile data may be out of date - object is newer",
4357330f729Sjoerg               ObjectFilename);
4367330f729Sjoerg   auto CoverageOrErr =
437*82d56013Sjoerg       CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches,
438*82d56013Sjoerg                             ViewOpts.CompilationDirectory);
4397330f729Sjoerg   if (Error E = CoverageOrErr.takeError()) {
4407330f729Sjoerg     error("Failed to load coverage: " + toString(std::move(E)),
4417330f729Sjoerg           join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "));
4427330f729Sjoerg     return nullptr;
4437330f729Sjoerg   }
4447330f729Sjoerg   auto Coverage = std::move(CoverageOrErr.get());
4457330f729Sjoerg   unsigned Mismatched = Coverage->getMismatchedCount();
4467330f729Sjoerg   if (Mismatched) {
4477330f729Sjoerg     warning(Twine(Mismatched) + " functions have mismatched data");
4487330f729Sjoerg 
4497330f729Sjoerg     if (ViewOpts.Debug) {
4507330f729Sjoerg       for (const auto &HashMismatch : Coverage->getHashMismatches())
4517330f729Sjoerg         errs() << "hash-mismatch: "
4527330f729Sjoerg                << "No profile record found for '" << HashMismatch.first << "'"
4537330f729Sjoerg                << " with hash = 0x" << Twine::utohexstr(HashMismatch.second)
4547330f729Sjoerg                << '\n';
4557330f729Sjoerg     }
4567330f729Sjoerg   }
4577330f729Sjoerg 
4587330f729Sjoerg   remapPathNames(*Coverage);
4597330f729Sjoerg 
4607330f729Sjoerg   if (!SourceFiles.empty())
4617330f729Sjoerg     removeUnmappedInputs(*Coverage);
4627330f729Sjoerg 
4637330f729Sjoerg   demangleSymbols(*Coverage);
4647330f729Sjoerg 
4657330f729Sjoerg   return Coverage;
4667330f729Sjoerg }
4677330f729Sjoerg 
remapPathNames(const CoverageMapping & Coverage)4687330f729Sjoerg void CodeCoverageTool::remapPathNames(const CoverageMapping &Coverage) {
4697330f729Sjoerg   if (!PathRemapping)
4707330f729Sjoerg     return;
4717330f729Sjoerg 
4727330f729Sjoerg   // Convert remapping paths to native paths with trailing seperators.
4737330f729Sjoerg   auto nativeWithTrailing = [](StringRef Path) -> std::string {
4747330f729Sjoerg     if (Path.empty())
4757330f729Sjoerg       return "";
4767330f729Sjoerg     SmallString<128> NativePath;
4777330f729Sjoerg     sys::path::native(Path, NativePath);
478*82d56013Sjoerg     sys::path::remove_dots(NativePath, true);
479*82d56013Sjoerg     if (!NativePath.empty() && !sys::path::is_separator(NativePath.back()))
4807330f729Sjoerg       NativePath += sys::path::get_separator();
4817330f729Sjoerg     return NativePath.c_str();
4827330f729Sjoerg   };
4837330f729Sjoerg   std::string RemapFrom = nativeWithTrailing(PathRemapping->first);
4847330f729Sjoerg   std::string RemapTo = nativeWithTrailing(PathRemapping->second);
4857330f729Sjoerg 
4867330f729Sjoerg   // Create a mapping from coverage data file paths to local paths.
4877330f729Sjoerg   for (StringRef Filename : Coverage.getUniqueSourceFiles()) {
4887330f729Sjoerg     SmallString<128> NativeFilename;
4897330f729Sjoerg     sys::path::native(Filename, NativeFilename);
490*82d56013Sjoerg     sys::path::remove_dots(NativeFilename, true);
4917330f729Sjoerg     if (NativeFilename.startswith(RemapFrom)) {
4927330f729Sjoerg       RemappedFilenames[Filename] =
4937330f729Sjoerg           RemapTo + NativeFilename.substr(RemapFrom.size()).str();
4947330f729Sjoerg     }
4957330f729Sjoerg   }
4967330f729Sjoerg 
4977330f729Sjoerg   // Convert input files from local paths to coverage data file paths.
4987330f729Sjoerg   StringMap<std::string> InvRemappedFilenames;
4997330f729Sjoerg   for (const auto &RemappedFilename : RemappedFilenames)
500*82d56013Sjoerg     InvRemappedFilenames[RemappedFilename.getValue()] =
501*82d56013Sjoerg         std::string(RemappedFilename.getKey());
5027330f729Sjoerg 
5037330f729Sjoerg   for (std::string &Filename : SourceFiles) {
5047330f729Sjoerg     SmallString<128> NativeFilename;
5057330f729Sjoerg     sys::path::native(Filename, NativeFilename);
5067330f729Sjoerg     auto CovFileName = InvRemappedFilenames.find(NativeFilename);
5077330f729Sjoerg     if (CovFileName != InvRemappedFilenames.end())
5087330f729Sjoerg       Filename = CovFileName->second;
5097330f729Sjoerg   }
5107330f729Sjoerg }
5117330f729Sjoerg 
removeUnmappedInputs(const CoverageMapping & Coverage)5127330f729Sjoerg void CodeCoverageTool::removeUnmappedInputs(const CoverageMapping &Coverage) {
5137330f729Sjoerg   std::vector<StringRef> CoveredFiles = Coverage.getUniqueSourceFiles();
5147330f729Sjoerg 
5157330f729Sjoerg   // The user may have specified source files which aren't in the coverage
5167330f729Sjoerg   // mapping. Filter these files away.
517*82d56013Sjoerg   llvm::erase_if(SourceFiles, [&](const std::string &SF) {
518*82d56013Sjoerg     return !std::binary_search(CoveredFiles.begin(), CoveredFiles.end(), SF);
5197330f729Sjoerg   });
5207330f729Sjoerg }
5217330f729Sjoerg 
demangleSymbols(const CoverageMapping & Coverage)5227330f729Sjoerg void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) {
5237330f729Sjoerg   if (!ViewOpts.hasDemangler())
5247330f729Sjoerg     return;
5257330f729Sjoerg 
5267330f729Sjoerg   // Pass function names to the demangler in a temporary file.
5277330f729Sjoerg   int InputFD;
5287330f729Sjoerg   SmallString<256> InputPath;
5297330f729Sjoerg   std::error_code EC =
5307330f729Sjoerg       sys::fs::createTemporaryFile("demangle-in", "list", InputFD, InputPath);
5317330f729Sjoerg   if (EC) {
5327330f729Sjoerg     error(InputPath, EC.message());
5337330f729Sjoerg     return;
5347330f729Sjoerg   }
5357330f729Sjoerg   ToolOutputFile InputTOF{InputPath, InputFD};
5367330f729Sjoerg 
5377330f729Sjoerg   unsigned NumSymbols = 0;
5387330f729Sjoerg   for (const auto &Function : Coverage.getCoveredFunctions()) {
5397330f729Sjoerg     InputTOF.os() << Function.Name << '\n';
5407330f729Sjoerg     ++NumSymbols;
5417330f729Sjoerg   }
5427330f729Sjoerg   InputTOF.os().close();
5437330f729Sjoerg 
5447330f729Sjoerg   // Use another temporary file to store the demangler's output.
5457330f729Sjoerg   int OutputFD;
5467330f729Sjoerg   SmallString<256> OutputPath;
5477330f729Sjoerg   EC = sys::fs::createTemporaryFile("demangle-out", "list", OutputFD,
5487330f729Sjoerg                                     OutputPath);
5497330f729Sjoerg   if (EC) {
5507330f729Sjoerg     error(OutputPath, EC.message());
5517330f729Sjoerg     return;
5527330f729Sjoerg   }
5537330f729Sjoerg   ToolOutputFile OutputTOF{OutputPath, OutputFD};
5547330f729Sjoerg   OutputTOF.os().close();
5557330f729Sjoerg 
5567330f729Sjoerg   // Invoke the demangler.
5577330f729Sjoerg   std::vector<StringRef> ArgsV;
5587330f729Sjoerg   for (StringRef Arg : ViewOpts.DemanglerOpts)
5597330f729Sjoerg     ArgsV.push_back(Arg);
5607330f729Sjoerg   Optional<StringRef> Redirects[] = {InputPath.str(), OutputPath.str(), {""}};
5617330f729Sjoerg   std::string ErrMsg;
5627330f729Sjoerg   int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV,
5637330f729Sjoerg                                /*env=*/None, Redirects, /*secondsToWait=*/0,
5647330f729Sjoerg                                /*memoryLimit=*/0, &ErrMsg);
5657330f729Sjoerg   if (RC) {
5667330f729Sjoerg     error(ErrMsg, ViewOpts.DemanglerOpts[0]);
5677330f729Sjoerg     return;
5687330f729Sjoerg   }
5697330f729Sjoerg 
5707330f729Sjoerg   // Parse the demangler's output.
5717330f729Sjoerg   auto BufOrError = MemoryBuffer::getFile(OutputPath);
5727330f729Sjoerg   if (!BufOrError) {
5737330f729Sjoerg     error(OutputPath, BufOrError.getError().message());
5747330f729Sjoerg     return;
5757330f729Sjoerg   }
5767330f729Sjoerg 
5777330f729Sjoerg   std::unique_ptr<MemoryBuffer> DemanglerBuf = std::move(*BufOrError);
5787330f729Sjoerg 
5797330f729Sjoerg   SmallVector<StringRef, 8> Symbols;
5807330f729Sjoerg   StringRef DemanglerData = DemanglerBuf->getBuffer();
5817330f729Sjoerg   DemanglerData.split(Symbols, '\n', /*MaxSplit=*/NumSymbols,
5827330f729Sjoerg                       /*KeepEmpty=*/false);
5837330f729Sjoerg   if (Symbols.size() != NumSymbols) {
5847330f729Sjoerg     error("Demangler did not provide expected number of symbols");
5857330f729Sjoerg     return;
5867330f729Sjoerg   }
5877330f729Sjoerg 
5887330f729Sjoerg   // Cache the demangled names.
5897330f729Sjoerg   unsigned I = 0;
5907330f729Sjoerg   for (const auto &Function : Coverage.getCoveredFunctions())
5917330f729Sjoerg     // On Windows, lines in the demangler's output file end with "\r\n".
5927330f729Sjoerg     // Splitting by '\n' keeps '\r's, so cut them now.
593*82d56013Sjoerg     DC.DemangledNames[Function.Name] = std::string(Symbols[I++].rtrim());
5947330f729Sjoerg }
5957330f729Sjoerg 
writeSourceFileView(StringRef SourceFile,CoverageMapping * Coverage,CoveragePrinter * Printer,bool ShowFilenames)5967330f729Sjoerg void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
5977330f729Sjoerg                                            CoverageMapping *Coverage,
5987330f729Sjoerg                                            CoveragePrinter *Printer,
5997330f729Sjoerg                                            bool ShowFilenames) {
6007330f729Sjoerg   auto View = createSourceFileView(SourceFile, *Coverage);
6017330f729Sjoerg   if (!View) {
6027330f729Sjoerg     warning("The file '" + SourceFile + "' isn't covered.");
6037330f729Sjoerg     return;
6047330f729Sjoerg   }
6057330f729Sjoerg 
6067330f729Sjoerg   auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false);
6077330f729Sjoerg   if (Error E = OSOrErr.takeError()) {
6087330f729Sjoerg     error("Could not create view file!", toString(std::move(E)));
6097330f729Sjoerg     return;
6107330f729Sjoerg   }
6117330f729Sjoerg   auto OS = std::move(OSOrErr.get());
6127330f729Sjoerg 
6137330f729Sjoerg   View->print(*OS.get(), /*Wholefile=*/true,
6147330f729Sjoerg               /*ShowSourceName=*/ShowFilenames,
6157330f729Sjoerg               /*ShowTitle=*/ViewOpts.hasOutputDirectory());
6167330f729Sjoerg   Printer->closeViewFile(std::move(OS));
6177330f729Sjoerg }
6187330f729Sjoerg 
run(Command Cmd,int argc,const char ** argv)6197330f729Sjoerg int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
6207330f729Sjoerg   cl::opt<std::string> CovFilename(
6217330f729Sjoerg       cl::Positional, cl::desc("Covered executable or object file."));
6227330f729Sjoerg 
6237330f729Sjoerg   cl::list<std::string> CovFilenames(
624*82d56013Sjoerg       "object", cl::desc("Coverage executable or object file"), cl::ZeroOrMore);
625*82d56013Sjoerg 
626*82d56013Sjoerg   cl::opt<bool> DebugDumpCollectedObjects(
627*82d56013Sjoerg       "dump-collected-objects", cl::Optional, cl::Hidden,
628*82d56013Sjoerg       cl::desc("Show the collected coverage object files"));
6297330f729Sjoerg 
6307330f729Sjoerg   cl::list<std::string> InputSourceFiles(
6317330f729Sjoerg       cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
6327330f729Sjoerg 
6337330f729Sjoerg   cl::opt<bool> DebugDumpCollectedPaths(
6347330f729Sjoerg       "dump-collected-paths", cl::Optional, cl::Hidden,
6357330f729Sjoerg       cl::desc("Show the collected paths to source files"));
6367330f729Sjoerg 
6377330f729Sjoerg   cl::opt<std::string, true> PGOFilename(
6387330f729Sjoerg       "instr-profile", cl::Required, cl::location(this->PGOFilename),
6397330f729Sjoerg       cl::desc(
6407330f729Sjoerg           "File with the profile data obtained after an instrumented run"));
6417330f729Sjoerg 
6427330f729Sjoerg   cl::list<std::string> Arches(
6437330f729Sjoerg       "arch", cl::desc("architectures of the coverage mapping binaries"));
6447330f729Sjoerg 
6457330f729Sjoerg   cl::opt<bool> DebugDump("dump", cl::Optional,
6467330f729Sjoerg                           cl::desc("Show internal debug dump"));
6477330f729Sjoerg 
6487330f729Sjoerg   cl::opt<CoverageViewOptions::OutputFormat> Format(
6497330f729Sjoerg       "format", cl::desc("Output format for line-based coverage reports"),
6507330f729Sjoerg       cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text, "text",
6517330f729Sjoerg                             "Text output"),
6527330f729Sjoerg                  clEnumValN(CoverageViewOptions::OutputFormat::HTML, "html",
6537330f729Sjoerg                             "HTML output"),
6547330f729Sjoerg                  clEnumValN(CoverageViewOptions::OutputFormat::Lcov, "lcov",
6557330f729Sjoerg                             "lcov tracefile output")),
6567330f729Sjoerg       cl::init(CoverageViewOptions::OutputFormat::Text));
6577330f729Sjoerg 
6587330f729Sjoerg   cl::opt<std::string> PathRemap(
6597330f729Sjoerg       "path-equivalence", cl::Optional,
6607330f729Sjoerg       cl::desc("<from>,<to> Map coverage data paths to local source file "
6617330f729Sjoerg                "paths"));
6627330f729Sjoerg 
6637330f729Sjoerg   cl::OptionCategory FilteringCategory("Function filtering options");
6647330f729Sjoerg 
6657330f729Sjoerg   cl::list<std::string> NameFilters(
6667330f729Sjoerg       "name", cl::Optional,
6677330f729Sjoerg       cl::desc("Show code coverage only for functions with the given name"),
6687330f729Sjoerg       cl::ZeroOrMore, cl::cat(FilteringCategory));
6697330f729Sjoerg 
6707330f729Sjoerg   cl::list<std::string> NameFilterFiles(
6717330f729Sjoerg       "name-whitelist", cl::Optional,
6727330f729Sjoerg       cl::desc("Show code coverage only for functions listed in the given "
6737330f729Sjoerg                "file"),
6747330f729Sjoerg       cl::ZeroOrMore, cl::cat(FilteringCategory));
6757330f729Sjoerg 
6767330f729Sjoerg   cl::list<std::string> NameRegexFilters(
6777330f729Sjoerg       "name-regex", cl::Optional,
6787330f729Sjoerg       cl::desc("Show code coverage only for functions that match the given "
6797330f729Sjoerg                "regular expression"),
6807330f729Sjoerg       cl::ZeroOrMore, cl::cat(FilteringCategory));
6817330f729Sjoerg 
6827330f729Sjoerg   cl::list<std::string> IgnoreFilenameRegexFilters(
6837330f729Sjoerg       "ignore-filename-regex", cl::Optional,
6847330f729Sjoerg       cl::desc("Skip source code files with file paths that match the given "
6857330f729Sjoerg                "regular expression"),
6867330f729Sjoerg       cl::ZeroOrMore, cl::cat(FilteringCategory));
6877330f729Sjoerg 
6887330f729Sjoerg   cl::opt<double> RegionCoverageLtFilter(
6897330f729Sjoerg       "region-coverage-lt", cl::Optional,
6907330f729Sjoerg       cl::desc("Show code coverage only for functions with region coverage "
6917330f729Sjoerg                "less than the given threshold"),
6927330f729Sjoerg       cl::cat(FilteringCategory));
6937330f729Sjoerg 
6947330f729Sjoerg   cl::opt<double> RegionCoverageGtFilter(
6957330f729Sjoerg       "region-coverage-gt", cl::Optional,
6967330f729Sjoerg       cl::desc("Show code coverage only for functions with region coverage "
6977330f729Sjoerg                "greater than the given threshold"),
6987330f729Sjoerg       cl::cat(FilteringCategory));
6997330f729Sjoerg 
7007330f729Sjoerg   cl::opt<double> LineCoverageLtFilter(
7017330f729Sjoerg       "line-coverage-lt", cl::Optional,
7027330f729Sjoerg       cl::desc("Show code coverage only for functions with line coverage less "
7037330f729Sjoerg                "than the given threshold"),
7047330f729Sjoerg       cl::cat(FilteringCategory));
7057330f729Sjoerg 
7067330f729Sjoerg   cl::opt<double> LineCoverageGtFilter(
7077330f729Sjoerg       "line-coverage-gt", cl::Optional,
7087330f729Sjoerg       cl::desc("Show code coverage only for functions with line coverage "
7097330f729Sjoerg                "greater than the given threshold"),
7107330f729Sjoerg       cl::cat(FilteringCategory));
7117330f729Sjoerg 
7127330f729Sjoerg   cl::opt<cl::boolOrDefault> UseColor(
7137330f729Sjoerg       "use-color", cl::desc("Emit colored output (default=autodetect)"),
7147330f729Sjoerg       cl::init(cl::BOU_UNSET));
7157330f729Sjoerg 
7167330f729Sjoerg   cl::list<std::string> DemanglerOpts(
7177330f729Sjoerg       "Xdemangler", cl::desc("<demangler-path>|<demangler-option>"));
7187330f729Sjoerg 
7197330f729Sjoerg   cl::opt<bool> RegionSummary(
7207330f729Sjoerg       "show-region-summary", cl::Optional,
7217330f729Sjoerg       cl::desc("Show region statistics in summary table"),
7227330f729Sjoerg       cl::init(true));
7237330f729Sjoerg 
724*82d56013Sjoerg   cl::opt<bool> BranchSummary(
725*82d56013Sjoerg       "show-branch-summary", cl::Optional,
726*82d56013Sjoerg       cl::desc("Show branch condition statistics in summary table"),
727*82d56013Sjoerg       cl::init(true));
728*82d56013Sjoerg 
7297330f729Sjoerg   cl::opt<bool> InstantiationSummary(
7307330f729Sjoerg       "show-instantiation-summary", cl::Optional,
7317330f729Sjoerg       cl::desc("Show instantiation statistics in summary table"));
7327330f729Sjoerg 
7337330f729Sjoerg   cl::opt<bool> SummaryOnly(
7347330f729Sjoerg       "summary-only", cl::Optional,
7357330f729Sjoerg       cl::desc("Export only summary information for each source file"));
7367330f729Sjoerg 
7377330f729Sjoerg   cl::opt<unsigned> NumThreads(
7387330f729Sjoerg       "num-threads", cl::init(0),
7397330f729Sjoerg       cl::desc("Number of merge threads to use (default: autodetect)"));
7407330f729Sjoerg   cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"),
7417330f729Sjoerg                         cl::aliasopt(NumThreads));
7427330f729Sjoerg 
743*82d56013Sjoerg   cl::opt<std::string> CompilationDirectory(
744*82d56013Sjoerg       "compilation-dir", cl::init(""),
745*82d56013Sjoerg       cl::desc("Directory used as a base for relative coverage mapping paths"));
746*82d56013Sjoerg 
7477330f729Sjoerg   auto commandLineParser = [&, this](int argc, const char **argv) -> int {
7487330f729Sjoerg     cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
7497330f729Sjoerg     ViewOpts.Debug = DebugDump;
7507330f729Sjoerg 
7517330f729Sjoerg     if (!CovFilename.empty())
7527330f729Sjoerg       ObjectFilenames.emplace_back(CovFilename);
7537330f729Sjoerg     for (const std::string &Filename : CovFilenames)
7547330f729Sjoerg       ObjectFilenames.emplace_back(Filename);
7557330f729Sjoerg     if (ObjectFilenames.empty()) {
7567330f729Sjoerg       errs() << "No filenames specified!\n";
7577330f729Sjoerg       ::exit(1);
7587330f729Sjoerg     }
7597330f729Sjoerg 
760*82d56013Sjoerg     if (DebugDumpCollectedObjects) {
761*82d56013Sjoerg       for (StringRef OF : ObjectFilenames)
762*82d56013Sjoerg         outs() << OF << '\n';
763*82d56013Sjoerg       ::exit(0);
764*82d56013Sjoerg     }
765*82d56013Sjoerg 
7667330f729Sjoerg     ViewOpts.Format = Format;
7677330f729Sjoerg     switch (ViewOpts.Format) {
7687330f729Sjoerg     case CoverageViewOptions::OutputFormat::Text:
7697330f729Sjoerg       ViewOpts.Colors = UseColor == cl::BOU_UNSET
7707330f729Sjoerg                             ? sys::Process::StandardOutHasColors()
7717330f729Sjoerg                             : UseColor == cl::BOU_TRUE;
7727330f729Sjoerg       break;
7737330f729Sjoerg     case CoverageViewOptions::OutputFormat::HTML:
7747330f729Sjoerg       if (UseColor == cl::BOU_FALSE)
7757330f729Sjoerg         errs() << "Color output cannot be disabled when generating html.\n";
7767330f729Sjoerg       ViewOpts.Colors = true;
7777330f729Sjoerg       break;
7787330f729Sjoerg     case CoverageViewOptions::OutputFormat::Lcov:
7797330f729Sjoerg       if (UseColor == cl::BOU_TRUE)
7807330f729Sjoerg         errs() << "Color output cannot be enabled when generating lcov.\n";
7817330f729Sjoerg       ViewOpts.Colors = false;
7827330f729Sjoerg       break;
7837330f729Sjoerg     }
7847330f729Sjoerg 
7857330f729Sjoerg     // If path-equivalence was given and is a comma seperated pair then set
7867330f729Sjoerg     // PathRemapping.
7877330f729Sjoerg     auto EquivPair = StringRef(PathRemap).split(',');
7887330f729Sjoerg     if (!(EquivPair.first.empty() && EquivPair.second.empty()))
789*82d56013Sjoerg       PathRemapping = {std::string(EquivPair.first),
790*82d56013Sjoerg                        std::string(EquivPair.second)};
7917330f729Sjoerg 
7927330f729Sjoerg     // If a demangler is supplied, check if it exists and register it.
7937330f729Sjoerg     if (!DemanglerOpts.empty()) {
7947330f729Sjoerg       auto DemanglerPathOrErr = sys::findProgramByName(DemanglerOpts[0]);
7957330f729Sjoerg       if (!DemanglerPathOrErr) {
7967330f729Sjoerg         error("Could not find the demangler!",
7977330f729Sjoerg               DemanglerPathOrErr.getError().message());
7987330f729Sjoerg         return 1;
7997330f729Sjoerg       }
8007330f729Sjoerg       DemanglerOpts[0] = *DemanglerPathOrErr;
8017330f729Sjoerg       ViewOpts.DemanglerOpts.swap(DemanglerOpts);
8027330f729Sjoerg     }
8037330f729Sjoerg 
8047330f729Sjoerg     // Read in -name-whitelist files.
8057330f729Sjoerg     if (!NameFilterFiles.empty()) {
8067330f729Sjoerg       std::string SpecialCaseListErr;
807*82d56013Sjoerg       NameWhitelist = SpecialCaseList::create(
808*82d56013Sjoerg           NameFilterFiles, *vfs::getRealFileSystem(), SpecialCaseListErr);
8097330f729Sjoerg       if (!NameWhitelist)
8107330f729Sjoerg         error(SpecialCaseListErr);
8117330f729Sjoerg     }
8127330f729Sjoerg 
8137330f729Sjoerg     // Create the function filters
8147330f729Sjoerg     if (!NameFilters.empty() || NameWhitelist || !NameRegexFilters.empty()) {
8157330f729Sjoerg       auto NameFilterer = std::make_unique<CoverageFilters>();
8167330f729Sjoerg       for (const auto &Name : NameFilters)
8177330f729Sjoerg         NameFilterer->push_back(std::make_unique<NameCoverageFilter>(Name));
8187330f729Sjoerg       if (NameWhitelist)
8197330f729Sjoerg         NameFilterer->push_back(
8207330f729Sjoerg             std::make_unique<NameWhitelistCoverageFilter>(*NameWhitelist));
8217330f729Sjoerg       for (const auto &Regex : NameRegexFilters)
8227330f729Sjoerg         NameFilterer->push_back(
8237330f729Sjoerg             std::make_unique<NameRegexCoverageFilter>(Regex));
8247330f729Sjoerg       Filters.push_back(std::move(NameFilterer));
8257330f729Sjoerg     }
8267330f729Sjoerg 
8277330f729Sjoerg     if (RegionCoverageLtFilter.getNumOccurrences() ||
8287330f729Sjoerg         RegionCoverageGtFilter.getNumOccurrences() ||
8297330f729Sjoerg         LineCoverageLtFilter.getNumOccurrences() ||
8307330f729Sjoerg         LineCoverageGtFilter.getNumOccurrences()) {
8317330f729Sjoerg       auto StatFilterer = std::make_unique<CoverageFilters>();
8327330f729Sjoerg       if (RegionCoverageLtFilter.getNumOccurrences())
8337330f729Sjoerg         StatFilterer->push_back(std::make_unique<RegionCoverageFilter>(
8347330f729Sjoerg             RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
8357330f729Sjoerg       if (RegionCoverageGtFilter.getNumOccurrences())
8367330f729Sjoerg         StatFilterer->push_back(std::make_unique<RegionCoverageFilter>(
8377330f729Sjoerg             RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
8387330f729Sjoerg       if (LineCoverageLtFilter.getNumOccurrences())
8397330f729Sjoerg         StatFilterer->push_back(std::make_unique<LineCoverageFilter>(
8407330f729Sjoerg             LineCoverageFilter::LessThan, LineCoverageLtFilter));
8417330f729Sjoerg       if (LineCoverageGtFilter.getNumOccurrences())
8427330f729Sjoerg         StatFilterer->push_back(std::make_unique<LineCoverageFilter>(
8437330f729Sjoerg             RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
8447330f729Sjoerg       Filters.push_back(std::move(StatFilterer));
8457330f729Sjoerg     }
8467330f729Sjoerg 
8477330f729Sjoerg     // Create the ignore filename filters.
8487330f729Sjoerg     for (const auto &RE : IgnoreFilenameRegexFilters)
8497330f729Sjoerg       IgnoreFilenameFilters.push_back(
8507330f729Sjoerg           std::make_unique<NameRegexCoverageFilter>(RE));
8517330f729Sjoerg 
8527330f729Sjoerg     if (!Arches.empty()) {
8537330f729Sjoerg       for (const std::string &Arch : Arches) {
8547330f729Sjoerg         if (Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
8557330f729Sjoerg           error("Unknown architecture: " + Arch);
8567330f729Sjoerg           return 1;
8577330f729Sjoerg         }
8587330f729Sjoerg         CoverageArches.emplace_back(Arch);
8597330f729Sjoerg       }
8607330f729Sjoerg       if (CoverageArches.size() != ObjectFilenames.size()) {
8617330f729Sjoerg         error("Number of architectures doesn't match the number of objects");
8627330f729Sjoerg         return 1;
8637330f729Sjoerg       }
8647330f729Sjoerg     }
8657330f729Sjoerg 
8667330f729Sjoerg     // IgnoreFilenameFilters are applied even when InputSourceFiles specified.
8677330f729Sjoerg     for (const std::string &File : InputSourceFiles)
8687330f729Sjoerg       collectPaths(File);
8697330f729Sjoerg 
8707330f729Sjoerg     if (DebugDumpCollectedPaths) {
8717330f729Sjoerg       for (const std::string &SF : SourceFiles)
8727330f729Sjoerg         outs() << SF << '\n';
8737330f729Sjoerg       ::exit(0);
8747330f729Sjoerg     }
8757330f729Sjoerg 
876*82d56013Sjoerg     ViewOpts.ShowBranchSummary = BranchSummary;
8777330f729Sjoerg     ViewOpts.ShowRegionSummary = RegionSummary;
8787330f729Sjoerg     ViewOpts.ShowInstantiationSummary = InstantiationSummary;
8797330f729Sjoerg     ViewOpts.ExportSummaryOnly = SummaryOnly;
8807330f729Sjoerg     ViewOpts.NumThreads = NumThreads;
881*82d56013Sjoerg     ViewOpts.CompilationDirectory = CompilationDirectory;
8827330f729Sjoerg 
8837330f729Sjoerg     return 0;
8847330f729Sjoerg   };
8857330f729Sjoerg 
8867330f729Sjoerg   switch (Cmd) {
8877330f729Sjoerg   case Show:
8887330f729Sjoerg     return doShow(argc, argv, commandLineParser);
8897330f729Sjoerg   case Report:
8907330f729Sjoerg     return doReport(argc, argv, commandLineParser);
8917330f729Sjoerg   case Export:
8927330f729Sjoerg     return doExport(argc, argv, commandLineParser);
8937330f729Sjoerg   }
8947330f729Sjoerg   return 0;
8957330f729Sjoerg }
8967330f729Sjoerg 
doShow(int argc,const char ** argv,CommandLineParserType commandLineParser)8977330f729Sjoerg int CodeCoverageTool::doShow(int argc, const char **argv,
8987330f729Sjoerg                              CommandLineParserType commandLineParser) {
8997330f729Sjoerg 
9007330f729Sjoerg   cl::OptionCategory ViewCategory("Viewing options");
9017330f729Sjoerg 
9027330f729Sjoerg   cl::opt<bool> ShowLineExecutionCounts(
9037330f729Sjoerg       "show-line-counts", cl::Optional,
9047330f729Sjoerg       cl::desc("Show the execution counts for each line"), cl::init(true),
9057330f729Sjoerg       cl::cat(ViewCategory));
9067330f729Sjoerg 
9077330f729Sjoerg   cl::opt<bool> ShowRegions(
9087330f729Sjoerg       "show-regions", cl::Optional,
9097330f729Sjoerg       cl::desc("Show the execution counts for each region"),
9107330f729Sjoerg       cl::cat(ViewCategory));
9117330f729Sjoerg 
912*82d56013Sjoerg   cl::opt<CoverageViewOptions::BranchOutputType> ShowBranches(
913*82d56013Sjoerg       "show-branches", cl::Optional,
914*82d56013Sjoerg       cl::desc("Show coverage for branch conditions"), cl::cat(ViewCategory),
915*82d56013Sjoerg       cl::values(clEnumValN(CoverageViewOptions::BranchOutputType::Count,
916*82d56013Sjoerg                             "count", "Show True/False counts"),
917*82d56013Sjoerg                  clEnumValN(CoverageViewOptions::BranchOutputType::Percent,
918*82d56013Sjoerg                             "percent", "Show True/False percent")),
919*82d56013Sjoerg       cl::init(CoverageViewOptions::BranchOutputType::Off));
920*82d56013Sjoerg 
9217330f729Sjoerg   cl::opt<bool> ShowBestLineRegionsCounts(
9227330f729Sjoerg       "show-line-counts-or-regions", cl::Optional,
9237330f729Sjoerg       cl::desc("Show the execution counts for each line, or the execution "
9247330f729Sjoerg                "counts for each region on lines that have multiple regions"),
9257330f729Sjoerg       cl::cat(ViewCategory));
9267330f729Sjoerg 
9277330f729Sjoerg   cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
9287330f729Sjoerg                                cl::desc("Show expanded source regions"),
9297330f729Sjoerg                                cl::cat(ViewCategory));
9307330f729Sjoerg 
9317330f729Sjoerg   cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
9327330f729Sjoerg                                    cl::desc("Show function instantiations"),
9337330f729Sjoerg                                    cl::init(true), cl::cat(ViewCategory));
9347330f729Sjoerg 
9357330f729Sjoerg   cl::opt<std::string> ShowOutputDirectory(
9367330f729Sjoerg       "output-dir", cl::init(""),
9377330f729Sjoerg       cl::desc("Directory in which coverage information is written out"));
9387330f729Sjoerg   cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
9397330f729Sjoerg                                  cl::aliasopt(ShowOutputDirectory));
9407330f729Sjoerg 
9417330f729Sjoerg   cl::opt<uint32_t> TabSize(
9427330f729Sjoerg       "tab-size", cl::init(2),
9437330f729Sjoerg       cl::desc(
9447330f729Sjoerg           "Set tab expansion size for html coverage reports (default = 2)"));
9457330f729Sjoerg 
9467330f729Sjoerg   cl::opt<std::string> ProjectTitle(
9477330f729Sjoerg       "project-title", cl::Optional,
9487330f729Sjoerg       cl::desc("Set project title for the coverage report"));
9497330f729Sjoerg 
9507330f729Sjoerg   auto Err = commandLineParser(argc, argv);
9517330f729Sjoerg   if (Err)
9527330f729Sjoerg     return Err;
9537330f729Sjoerg 
9547330f729Sjoerg   if (ViewOpts.Format == CoverageViewOptions::OutputFormat::Lcov) {
9557330f729Sjoerg     error("Lcov format should be used with 'llvm-cov export'.");
9567330f729Sjoerg     return 1;
9577330f729Sjoerg   }
9587330f729Sjoerg 
9597330f729Sjoerg   ViewOpts.ShowLineNumbers = true;
9607330f729Sjoerg   ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
9617330f729Sjoerg                            !ShowRegions || ShowBestLineRegionsCounts;
9627330f729Sjoerg   ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
9637330f729Sjoerg   ViewOpts.ShowExpandedRegions = ShowExpansions;
964*82d56013Sjoerg   ViewOpts.ShowBranchCounts =
965*82d56013Sjoerg       ShowBranches == CoverageViewOptions::BranchOutputType::Count;
966*82d56013Sjoerg   ViewOpts.ShowBranchPercents =
967*82d56013Sjoerg       ShowBranches == CoverageViewOptions::BranchOutputType::Percent;
9687330f729Sjoerg   ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
9697330f729Sjoerg   ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
9707330f729Sjoerg   ViewOpts.TabSize = TabSize;
9717330f729Sjoerg   ViewOpts.ProjectTitle = ProjectTitle;
9727330f729Sjoerg 
9737330f729Sjoerg   if (ViewOpts.hasOutputDirectory()) {
9747330f729Sjoerg     if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) {
9757330f729Sjoerg       error("Could not create output directory!", E.message());
9767330f729Sjoerg       return 1;
9777330f729Sjoerg     }
9787330f729Sjoerg   }
9797330f729Sjoerg 
9807330f729Sjoerg   sys::fs::file_status Status;
981*82d56013Sjoerg   if (std::error_code EC = sys::fs::status(PGOFilename, Status)) {
982*82d56013Sjoerg     error("Could not read profile data!", EC.message());
9837330f729Sjoerg     return 1;
9847330f729Sjoerg   }
9857330f729Sjoerg 
9867330f729Sjoerg   auto ModifiedTime = Status.getLastModificationTime();
9877330f729Sjoerg   std::string ModifiedTimeStr = to_string(ModifiedTime);
9887330f729Sjoerg   size_t found = ModifiedTimeStr.rfind(':');
9897330f729Sjoerg   ViewOpts.CreatedTimeStr = (found != std::string::npos)
9907330f729Sjoerg                                 ? "Created: " + ModifiedTimeStr.substr(0, found)
9917330f729Sjoerg                                 : "Created: " + ModifiedTimeStr;
9927330f729Sjoerg 
9937330f729Sjoerg   auto Coverage = load();
9947330f729Sjoerg   if (!Coverage)
9957330f729Sjoerg     return 1;
9967330f729Sjoerg 
9977330f729Sjoerg   auto Printer = CoveragePrinter::create(ViewOpts);
9987330f729Sjoerg 
999*82d56013Sjoerg   if (SourceFiles.empty() && !HadSourceFiles)
10007330f729Sjoerg     // Get the source files from the function coverage mapping.
10017330f729Sjoerg     for (StringRef Filename : Coverage->getUniqueSourceFiles()) {
10027330f729Sjoerg       if (!IgnoreFilenameFilters.matchesFilename(Filename))
1003*82d56013Sjoerg         SourceFiles.push_back(std::string(Filename));
10047330f729Sjoerg     }
10057330f729Sjoerg 
10067330f729Sjoerg   // Create an index out of the source files.
10077330f729Sjoerg   if (ViewOpts.hasOutputDirectory()) {
10087330f729Sjoerg     if (Error E = Printer->createIndexFile(SourceFiles, *Coverage, Filters)) {
10097330f729Sjoerg       error("Could not create index file!", toString(std::move(E)));
10107330f729Sjoerg       return 1;
10117330f729Sjoerg     }
10127330f729Sjoerg   }
10137330f729Sjoerg 
10147330f729Sjoerg   if (!Filters.empty()) {
10157330f729Sjoerg     // Build the map of filenames to functions.
10167330f729Sjoerg     std::map<llvm::StringRef, std::vector<const FunctionRecord *>>
10177330f729Sjoerg         FilenameFunctionMap;
10187330f729Sjoerg     for (const auto &SourceFile : SourceFiles)
10197330f729Sjoerg       for (const auto &Function : Coverage->getCoveredFunctions(SourceFile))
10207330f729Sjoerg         if (Filters.matches(*Coverage.get(), Function))
10217330f729Sjoerg           FilenameFunctionMap[SourceFile].push_back(&Function);
10227330f729Sjoerg 
10237330f729Sjoerg     // Only print filter matching functions for each file.
10247330f729Sjoerg     for (const auto &FileFunc : FilenameFunctionMap) {
10257330f729Sjoerg       StringRef File = FileFunc.first;
10267330f729Sjoerg       const auto &Functions = FileFunc.second;
10277330f729Sjoerg 
10287330f729Sjoerg       auto OSOrErr = Printer->createViewFile(File, /*InToplevel=*/false);
10297330f729Sjoerg       if (Error E = OSOrErr.takeError()) {
10307330f729Sjoerg         error("Could not create view file!", toString(std::move(E)));
10317330f729Sjoerg         return 1;
10327330f729Sjoerg       }
10337330f729Sjoerg       auto OS = std::move(OSOrErr.get());
10347330f729Sjoerg 
10357330f729Sjoerg       bool ShowTitle = ViewOpts.hasOutputDirectory();
10367330f729Sjoerg       for (const auto *Function : Functions) {
10377330f729Sjoerg         auto FunctionView = createFunctionView(*Function, *Coverage);
10387330f729Sjoerg         if (!FunctionView) {
10397330f729Sjoerg           warning("Could not read coverage for '" + Function->Name + "'.");
10407330f729Sjoerg           continue;
10417330f729Sjoerg         }
10427330f729Sjoerg         FunctionView->print(*OS.get(), /*WholeFile=*/false,
10437330f729Sjoerg                             /*ShowSourceName=*/true, ShowTitle);
10447330f729Sjoerg         ShowTitle = false;
10457330f729Sjoerg       }
10467330f729Sjoerg 
10477330f729Sjoerg       Printer->closeViewFile(std::move(OS));
10487330f729Sjoerg     }
10497330f729Sjoerg     return 0;
10507330f729Sjoerg   }
10517330f729Sjoerg 
10527330f729Sjoerg   // Show files
10537330f729Sjoerg   bool ShowFilenames =
10547330f729Sjoerg       (SourceFiles.size() != 1) || ViewOpts.hasOutputDirectory() ||
10557330f729Sjoerg       (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML);
10567330f729Sjoerg 
1057*82d56013Sjoerg   ThreadPoolStrategy S = hardware_concurrency(ViewOpts.NumThreads);
1058*82d56013Sjoerg   if (ViewOpts.NumThreads == 0) {
1059*82d56013Sjoerg     // If NumThreads is not specified, create one thread for each input, up to
1060*82d56013Sjoerg     // the number of hardware cores.
1061*82d56013Sjoerg     S = heavyweight_hardware_concurrency(SourceFiles.size());
1062*82d56013Sjoerg     S.Limit = true;
1063*82d56013Sjoerg   }
10647330f729Sjoerg 
1065*82d56013Sjoerg   if (!ViewOpts.hasOutputDirectory() || S.ThreadsRequested == 1) {
10667330f729Sjoerg     for (const std::string &SourceFile : SourceFiles)
10677330f729Sjoerg       writeSourceFileView(SourceFile, Coverage.get(), Printer.get(),
10687330f729Sjoerg                           ShowFilenames);
10697330f729Sjoerg   } else {
10707330f729Sjoerg     // In -output-dir mode, it's safe to use multiple threads to print files.
1071*82d56013Sjoerg     ThreadPool Pool(S);
10727330f729Sjoerg     for (const std::string &SourceFile : SourceFiles)
10737330f729Sjoerg       Pool.async(&CodeCoverageTool::writeSourceFileView, this, SourceFile,
10747330f729Sjoerg                  Coverage.get(), Printer.get(), ShowFilenames);
10757330f729Sjoerg     Pool.wait();
10767330f729Sjoerg   }
10777330f729Sjoerg 
10787330f729Sjoerg   return 0;
10797330f729Sjoerg }
10807330f729Sjoerg 
doReport(int argc,const char ** argv,CommandLineParserType commandLineParser)10817330f729Sjoerg int CodeCoverageTool::doReport(int argc, const char **argv,
10827330f729Sjoerg                                CommandLineParserType commandLineParser) {
10837330f729Sjoerg   cl::opt<bool> ShowFunctionSummaries(
10847330f729Sjoerg       "show-functions", cl::Optional, cl::init(false),
10857330f729Sjoerg       cl::desc("Show coverage summaries for each function"));
10867330f729Sjoerg 
10877330f729Sjoerg   auto Err = commandLineParser(argc, argv);
10887330f729Sjoerg   if (Err)
10897330f729Sjoerg     return Err;
10907330f729Sjoerg 
10917330f729Sjoerg   if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) {
10927330f729Sjoerg     error("HTML output for summary reports is not yet supported.");
10937330f729Sjoerg     return 1;
10947330f729Sjoerg   } else if (ViewOpts.Format == CoverageViewOptions::OutputFormat::Lcov) {
10957330f729Sjoerg     error("Lcov format should be used with 'llvm-cov export'.");
10967330f729Sjoerg     return 1;
10977330f729Sjoerg   }
10987330f729Sjoerg 
10997330f729Sjoerg   auto Coverage = load();
11007330f729Sjoerg   if (!Coverage)
11017330f729Sjoerg     return 1;
11027330f729Sjoerg 
11037330f729Sjoerg   CoverageReport Report(ViewOpts, *Coverage.get());
11047330f729Sjoerg   if (!ShowFunctionSummaries) {
11057330f729Sjoerg     if (SourceFiles.empty())
11067330f729Sjoerg       Report.renderFileReports(llvm::outs(), IgnoreFilenameFilters);
11077330f729Sjoerg     else
11087330f729Sjoerg       Report.renderFileReports(llvm::outs(), SourceFiles);
11097330f729Sjoerg   } else {
11107330f729Sjoerg     if (SourceFiles.empty()) {
11117330f729Sjoerg       error("Source files must be specified when -show-functions=true is "
11127330f729Sjoerg             "specified");
11137330f729Sjoerg       return 1;
11147330f729Sjoerg     }
11157330f729Sjoerg 
11167330f729Sjoerg     Report.renderFunctionReports(SourceFiles, DC, llvm::outs());
11177330f729Sjoerg   }
11187330f729Sjoerg   return 0;
11197330f729Sjoerg }
11207330f729Sjoerg 
doExport(int argc,const char ** argv,CommandLineParserType commandLineParser)11217330f729Sjoerg int CodeCoverageTool::doExport(int argc, const char **argv,
11227330f729Sjoerg                                CommandLineParserType commandLineParser) {
11237330f729Sjoerg 
11247330f729Sjoerg   cl::OptionCategory ExportCategory("Exporting options");
11257330f729Sjoerg 
11267330f729Sjoerg   cl::opt<bool> SkipExpansions("skip-expansions", cl::Optional,
11277330f729Sjoerg                                cl::desc("Don't export expanded source regions"),
11287330f729Sjoerg                                cl::cat(ExportCategory));
11297330f729Sjoerg 
11307330f729Sjoerg   cl::opt<bool> SkipFunctions("skip-functions", cl::Optional,
11317330f729Sjoerg                               cl::desc("Don't export per-function data"),
11327330f729Sjoerg                               cl::cat(ExportCategory));
11337330f729Sjoerg 
11347330f729Sjoerg   auto Err = commandLineParser(argc, argv);
11357330f729Sjoerg   if (Err)
11367330f729Sjoerg     return Err;
11377330f729Sjoerg 
11387330f729Sjoerg   ViewOpts.SkipExpansions = SkipExpansions;
11397330f729Sjoerg   ViewOpts.SkipFunctions = SkipFunctions;
11407330f729Sjoerg 
11417330f729Sjoerg   if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text &&
11427330f729Sjoerg       ViewOpts.Format != CoverageViewOptions::OutputFormat::Lcov) {
11437330f729Sjoerg     error("Coverage data can only be exported as textual JSON or an "
11447330f729Sjoerg           "lcov tracefile.");
11457330f729Sjoerg     return 1;
11467330f729Sjoerg   }
11477330f729Sjoerg 
11487330f729Sjoerg   auto Coverage = load();
11497330f729Sjoerg   if (!Coverage) {
11507330f729Sjoerg     error("Could not load coverage information");
11517330f729Sjoerg     return 1;
11527330f729Sjoerg   }
11537330f729Sjoerg 
11547330f729Sjoerg   std::unique_ptr<CoverageExporter> Exporter;
11557330f729Sjoerg 
11567330f729Sjoerg   switch (ViewOpts.Format) {
11577330f729Sjoerg   case CoverageViewOptions::OutputFormat::Text:
11587330f729Sjoerg     Exporter = std::make_unique<CoverageExporterJson>(*Coverage.get(),
11597330f729Sjoerg                                                        ViewOpts, outs());
11607330f729Sjoerg     break;
11617330f729Sjoerg   case CoverageViewOptions::OutputFormat::HTML:
11627330f729Sjoerg     // Unreachable because we should have gracefully terminated with an error
11637330f729Sjoerg     // above.
11647330f729Sjoerg     llvm_unreachable("Export in HTML is not supported!");
11657330f729Sjoerg   case CoverageViewOptions::OutputFormat::Lcov:
11667330f729Sjoerg     Exporter = std::make_unique<CoverageExporterLcov>(*Coverage.get(),
11677330f729Sjoerg                                                        ViewOpts, outs());
11687330f729Sjoerg     break;
11697330f729Sjoerg   }
11707330f729Sjoerg 
11717330f729Sjoerg   if (SourceFiles.empty())
11727330f729Sjoerg     Exporter->renderRoot(IgnoreFilenameFilters);
11737330f729Sjoerg   else
11747330f729Sjoerg     Exporter->renderRoot(SourceFiles);
11757330f729Sjoerg 
11767330f729Sjoerg   return 0;
11777330f729Sjoerg }
11787330f729Sjoerg 
showMain(int argc,const char * argv[])11797330f729Sjoerg int showMain(int argc, const char *argv[]) {
11807330f729Sjoerg   CodeCoverageTool Tool;
11817330f729Sjoerg   return Tool.run(CodeCoverageTool::Show, argc, argv);
11827330f729Sjoerg }
11837330f729Sjoerg 
reportMain(int argc,const char * argv[])11847330f729Sjoerg int reportMain(int argc, const char *argv[]) {
11857330f729Sjoerg   CodeCoverageTool Tool;
11867330f729Sjoerg   return Tool.run(CodeCoverageTool::Report, argc, argv);
11877330f729Sjoerg }
11887330f729Sjoerg 
exportMain(int argc,const char * argv[])11897330f729Sjoerg int exportMain(int argc, const char *argv[]) {
11907330f729Sjoerg   CodeCoverageTool Tool;
11917330f729Sjoerg   return Tool.run(CodeCoverageTool::Export, argc, argv);
11927330f729Sjoerg }
1193