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