diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
commit | eb11fae6d08f479c0799db45860a98af528fa6e7 (patch) | |
tree | 44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /tools/llvm-cov/CodeCoverage.cpp | |
parent | b8a2042aa938069e862750553db0e4d82d25822c (diff) |
Notes
Diffstat (limited to 'tools/llvm-cov/CodeCoverage.cpp')
-rw-r--r-- | tools/llvm-cov/CodeCoverage.cpp | 137 |
1 files changed, 83 insertions, 54 deletions
diff --git a/tools/llvm-cov/CodeCoverage.cpp b/tools/llvm-cov/CodeCoverage.cpp index c5ea50bff273..e93b63d388e0 100644 --- a/tools/llvm-cov/CodeCoverage.cpp +++ b/tools/llvm-cov/CodeCoverage.cpp @@ -13,6 +13,7 @@ // //===----------------------------------------------------------------------===// +#include "CoverageExporterJson.h" #include "CoverageFilters.h" #include "CoverageReport.h" #include "CoverageSummaryInfo.h" @@ -32,8 +33,8 @@ #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/ScopedPrinter.h" -#include "llvm/Support/Threading.h" #include "llvm/Support/ThreadPool.h" +#include "llvm/Support/Threading.h" #include "llvm/Support/ToolOutputFile.h" #include <functional> @@ -48,83 +49,84 @@ void exportCoverageDataToJson(const coverage::CoverageMapping &CoverageMapping, raw_ostream &OS); namespace { -/// \brief The implementation of the coverage tool. +/// The implementation of the coverage tool. class CodeCoverageTool { public: enum Command { - /// \brief The show command. + /// The show command. Show, - /// \brief The report command. + /// The report command. Report, - /// \brief The export command. + /// The export command. Export }; int run(Command Cmd, int argc, const char **argv); private: - /// \brief Print the error message to the error output stream. + /// Print the error message to the error output stream. void error(const Twine &Message, StringRef Whence = ""); - /// \brief Print the warning message to the error output stream. + /// Print the warning message to the error output stream. void warning(const Twine &Message, StringRef Whence = ""); - /// \brief Convert \p Path into an absolute path and append it to the list + /// Convert \p Path into an absolute path and append it to the list /// of collected paths. void addCollectedPath(const std::string &Path); - /// \brief If \p Path is a regular file, collect the path. If it's a + /// If \p Path is a regular file, collect the path. If it's a /// directory, recursively collect all of the paths within the directory. void collectPaths(const std::string &Path); - /// \brief Return a memory buffer for the given source file. + /// Return a memory buffer for the given source file. ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile); - /// \brief Create source views for the expansions of the view. + /// Create source views for the expansions of the view. void attachExpansionSubViews(SourceCoverageView &View, ArrayRef<ExpansionRecord> Expansions, const CoverageMapping &Coverage); - /// \brief Create the source view of a particular function. + /// Create the source view of a particular function. std::unique_ptr<SourceCoverageView> createFunctionView(const FunctionRecord &Function, const CoverageMapping &Coverage); - /// \brief Create the main source view of a particular source file. + /// Create the main source view of a particular source file. std::unique_ptr<SourceCoverageView> createSourceFileView(StringRef SourceFile, const CoverageMapping &Coverage); - /// \brief Load the coverage mapping data. Return nullptr if an error occurred. + /// Load the coverage mapping data. Return nullptr if an error occurred. std::unique_ptr<CoverageMapping> load(); - /// \brief Create a mapping from files in the Coverage data to local copies + /// Create a mapping from files in the Coverage data to local copies /// (path-equivalence). void remapPathNames(const CoverageMapping &Coverage); - /// \brief Remove input source files which aren't mapped by \p Coverage. + /// Remove input source files which aren't mapped by \p Coverage. void removeUnmappedInputs(const CoverageMapping &Coverage); - /// \brief If a demangler is available, demangle all symbol names. + /// If a demangler is available, demangle all symbol names. void demangleSymbols(const CoverageMapping &Coverage); - /// \brief Write out a source file view to the filesystem. + /// Write out a source file view to the filesystem. void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage, CoveragePrinter *Printer, bool ShowFilenames); typedef llvm::function_ref<int(int, const char **)> CommandLineParserType; - int show(int argc, const char **argv, - CommandLineParserType commandLineParser); - - int report(int argc, const char **argv, + int doShow(int argc, const char **argv, CommandLineParserType commandLineParser); - int export_(int argc, const char **argv, - CommandLineParserType commandLineParser); + int doReport(int argc, const char **argv, + CommandLineParserType commandLineParser); + + int doExport(int argc, const char **argv, + CommandLineParserType commandLineParser); std::vector<StringRef> ObjectFilenames; CoverageViewOptions ViewOpts; CoverageFiltersMatchAll Filters; + CoverageFilters IgnoreFilenameFilters; /// The path to the indexed profile. std::string PGOFilename; @@ -188,7 +190,8 @@ void CodeCoverageTool::addCollectedPath(const std::string &Path) { return; } sys::path::remove_dots(EffectivePath, /*remove_dot_dots=*/true); - SourceFiles.emplace_back(EffectivePath.str()); + if (!IgnoreFilenameFilters.matchesFilename(EffectivePath)) + SourceFiles.emplace_back(EffectivePath.str()); } void CodeCoverageTool::collectPaths(const std::string &Path) { @@ -198,7 +201,7 @@ void CodeCoverageTool::collectPaths(const std::string &Path) { if (PathRemapping) addCollectedPath(Path); else - error("Missing source file", Path); + warning("Source file doesn't exist, proceeded by ignoring it.", Path); return; } @@ -210,12 +213,16 @@ void CodeCoverageTool::collectPaths(const std::string &Path) { if (llvm::sys::fs::is_directory(Status)) { std::error_code EC; for (llvm::sys::fs::recursive_directory_iterator F(Path, EC), E; - F != E && !EC; F.increment(EC)) { + F != E; F.increment(EC)) { + + if (EC) { + warning(EC.message(), F->path()); + continue; + } + if (llvm::sys::fs::is_regular_file(F->path())) addCollectedPath(F->path()); } - if (EC) - warning(EC.message(), Path); } } @@ -471,14 +478,13 @@ void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) { OutputTOF.os().close(); // Invoke the demangler. - std::vector<const char *> ArgsV; - for (const std::string &Arg : ViewOpts.DemanglerOpts) - ArgsV.push_back(Arg.c_str()); - ArgsV.push_back(nullptr); + std::vector<StringRef> ArgsV; + for (StringRef Arg : ViewOpts.DemanglerOpts) + ArgsV.push_back(Arg); Optional<StringRef> Redirects[] = {InputPath.str(), OutputPath.str(), {""}}; std::string ErrMsg; - int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV.data(), - /*env=*/nullptr, Redirects, /*secondsToWait=*/0, + int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV, + /*env=*/None, Redirects, /*secondsToWait=*/0, /*memoryLimit=*/0, &ErrMsg); if (RC) { error(ErrMsg, ViewOpts.DemanglerOpts[0]); @@ -592,6 +598,12 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { "regular expression"), cl::ZeroOrMore, cl::cat(FilteringCategory)); + cl::list<std::string> IgnoreFilenameRegexFilters( + "ignore-filename-regex", cl::Optional, + cl::desc("Skip source code files with file paths that match the given " + "regular expression"), + cl::ZeroOrMore, cl::cat(FilteringCategory)); + cl::opt<double> RegionCoverageLtFilter( "region-coverage-lt", cl::Optional, cl::desc("Show code coverage only for functions with region coverage " @@ -636,6 +648,12 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { "summary-only", cl::Optional, cl::desc("Export only summary information for each source file")); + cl::opt<unsigned> NumThreads( + "num-threads", cl::init(0), + cl::desc("Number of merge threads to use (default: autodetect)")); + cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"), + cl::aliasopt(NumThreads)); + auto commandLineParser = [&, this](int argc, const char **argv) -> int { cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); ViewOpts.Debug = DebugDump; @@ -703,6 +721,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { llvm::make_unique<NameRegexCoverageFilter>(Regex)); Filters.push_back(std::move(NameFilterer)); } + if (RegionCoverageLtFilter.getNumOccurrences() || RegionCoverageGtFilter.getNumOccurrences() || LineCoverageLtFilter.getNumOccurrences() || @@ -723,6 +742,11 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { Filters.push_back(std::move(StatFilterer)); } + // Create the ignore filename filters. + for (const auto &RE : IgnoreFilenameRegexFilters) + IgnoreFilenameFilters.push_back( + llvm::make_unique<NameRegexCoverageFilter>(RE)); + if (!Arches.empty()) { for (const std::string &Arch : Arches) { if (Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) { @@ -737,6 +761,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { } } + // IgnoreFilenameFilters are applied even when InputSourceFiles specified. for (const std::string &File : InputSourceFiles) collectPaths(File); @@ -749,23 +774,24 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { ViewOpts.ShowRegionSummary = RegionSummary; ViewOpts.ShowInstantiationSummary = InstantiationSummary; ViewOpts.ExportSummaryOnly = SummaryOnly; + ViewOpts.NumThreads = NumThreads; return 0; }; switch (Cmd) { case Show: - return show(argc, argv, commandLineParser); + return doShow(argc, argv, commandLineParser); case Report: - return report(argc, argv, commandLineParser); + return doReport(argc, argv, commandLineParser); case Export: - return export_(argc, argv, commandLineParser); + return doExport(argc, argv, commandLineParser); } return 0; } -int CodeCoverageTool::show(int argc, const char **argv, - CommandLineParserType commandLineParser) { +int CodeCoverageTool::doShow(int argc, const char **argv, + CommandLineParserType commandLineParser) { cl::OptionCategory ViewCategory("Viewing options"); @@ -808,12 +834,6 @@ int CodeCoverageTool::show(int argc, const char **argv, "project-title", cl::Optional, cl::desc("Set project title for the coverage report")); - cl::opt<unsigned> NumThreads( - "num-threads", cl::init(0), - cl::desc("Number of merge threads to use (default: autodetect)")); - cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"), - cl::aliasopt(NumThreads)); - auto Err = commandLineParser(argc, argv); if (Err) return Err; @@ -856,8 +876,10 @@ int CodeCoverageTool::show(int argc, const char **argv, if (SourceFiles.empty()) // Get the source files from the function coverage mapping. - for (StringRef Filename : Coverage->getUniqueSourceFiles()) - SourceFiles.push_back(Filename); + for (StringRef Filename : Coverage->getUniqueSourceFiles()) { + if (!IgnoreFilenameFilters.matchesFilename(Filename)) + SourceFiles.push_back(Filename); + } // Create an index out of the source files. if (ViewOpts.hasOutputDirectory()) { @@ -910,6 +932,8 @@ int CodeCoverageTool::show(int argc, const char **argv, (SourceFiles.size() != 1) || ViewOpts.hasOutputDirectory() || (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML); + auto NumThreads = ViewOpts.NumThreads; + // If NumThreads is not specified, auto-detect a good default. if (NumThreads == 0) NumThreads = @@ -932,8 +956,8 @@ int CodeCoverageTool::show(int argc, const char **argv, return 0; } -int CodeCoverageTool::report(int argc, const char **argv, - CommandLineParserType commandLineParser) { +int CodeCoverageTool::doReport(int argc, const char **argv, + CommandLineParserType commandLineParser) { cl::opt<bool> ShowFunctionSummaries( "show-functions", cl::Optional, cl::init(false), cl::desc("Show coverage summaries for each function")); @@ -954,7 +978,7 @@ int CodeCoverageTool::report(int argc, const char **argv, CoverageReport Report(ViewOpts, *Coverage.get()); if (!ShowFunctionSummaries) { if (SourceFiles.empty()) - Report.renderFileReports(llvm::outs()); + Report.renderFileReports(llvm::outs(), IgnoreFilenameFilters); else Report.renderFileReports(llvm::outs(), SourceFiles); } else { @@ -969,8 +993,8 @@ int CodeCoverageTool::report(int argc, const char **argv, return 0; } -int CodeCoverageTool::export_(int argc, const char **argv, - CommandLineParserType commandLineParser) { +int CodeCoverageTool::doExport(int argc, const char **argv, + CommandLineParserType commandLineParser) { auto Err = commandLineParser(argc, argv); if (Err) @@ -987,7 +1011,12 @@ int CodeCoverageTool::export_(int argc, const char **argv, return 1; } - exportCoverageDataToJson(*Coverage.get(), ViewOpts, outs()); + auto Exporter = CoverageExporterJson(*Coverage.get(), ViewOpts, outs()); + + if (SourceFiles.empty()) + Exporter.renderRoot(IgnoreFilenameFilters); + else + Exporter.renderRoot(SourceFiles); return 0; } |