forked from OSchip/llvm-project
[llvm-cov] Implement -ignore-filename-regex= option for excluding source files.
Summary: The option is helpful for large projects where it's not feasible to specify sources which user would like to see in the report. Instead, it allows to black-list specific sources via regular expressions (e.g. now it's possible to skip all files that have "test" in its name). This also partially fixes https://bugs.llvm.org/show_bug.cgi?id=34277 Reviewers: vsk, morehouse, liaoyuke Reviewed By: vsk Subscribers: kcc, mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D43907 llvm-svn: 329581
This commit is contained in:
parent
ea9773ac69
commit
4220f89107
|
@ -246,6 +246,10 @@ OPTIONS
|
|||
|
||||
Show code coverage only for functions that match the given regular expression.
|
||||
|
||||
.. option:: -ignore-filename-regex=<PATTERN>
|
||||
|
||||
Skip source code files with file paths that match the given regular expression.
|
||||
|
||||
.. option:: -format=<FORMAT>
|
||||
|
||||
Use the specified output format. The supported formats are: "text", "html".
|
||||
|
@ -351,6 +355,10 @@ OPTIONS
|
|||
|
||||
Show statistics for all function instantiations. Defaults to false.
|
||||
|
||||
.. option:: -ignore-filename-regex=<PATTERN>
|
||||
|
||||
Skip source code files with file paths that match the given regular expression.
|
||||
|
||||
.. program:: llvm-cov export
|
||||
|
||||
.. _llvm-cov-export:
|
||||
|
@ -390,3 +398,7 @@ OPTIONS
|
|||
will not export coverage information for smaller units such as individual
|
||||
functions or regions. The result will be the same as produced by :program:
|
||||
`llvm-cov report` command, but presented in JSON format rather than text.
|
||||
|
||||
.. option:: -ignore-filename-regex=<PATTERN>
|
||||
|
||||
Skip source code files with file paths that match the given regular expression.
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
########################
|
||||
# Test "report" command.
|
||||
########################
|
||||
# Ignore all header files.
|
||||
RUN: llvm-cov report -instr-profile %S/Inputs/sources_specified/main.profdata \
|
||||
RUN: -path-equivalence=/tmp,%S/Inputs -ignore-filename-regex='.*\.h$' \
|
||||
RUN: %S/Inputs/sources_specified/main.covmapping \
|
||||
RUN: | FileCheck -check-prefix=REPORT_IGNORE_HEADERS %s
|
||||
|
||||
REPORT_IGNORE_HEADERS-NOT: {{.*}}dec.h{{.*}}
|
||||
REPORT_IGNORE_HEADERS-NOT: {{.*}}inc.h{{.*}}
|
||||
REPORT_IGNORE_HEADERS-NOT: {{.*}}abs.h{{.*}}
|
||||
REPORT_IGNORE_HEADERS: {{^}}TOTAL 1{{.*}}100.00%{{$}}
|
||||
|
||||
# Ignore all files from "extra" directory.
|
||||
RUN: llvm-cov report -instr-profile %S/Inputs/sources_specified/main.profdata \
|
||||
RUN: -path-equivalence=/tmp,%S/Inputs -ignore-filename-regex='.*extra[/\\].*' \
|
||||
RUN: %S/Inputs/sources_specified/main.covmapping \
|
||||
RUN: | FileCheck -check-prefix=REPORT_IGNORE_DIR %s
|
||||
|
||||
REPORT_IGNORE_DIR-NOT: {{.*}}extra{{[/\\]}}dec.h{{.*}}
|
||||
REPORT_IGNORE_DIR-NOT: {{.*}}extra{{[/\\]}}inc.h{{.*}}
|
||||
REPORT_IGNORE_DIR: {{.*}}abs.h{{.*}}
|
||||
REPORT_IGNORE_DIR: {{.*}}main.cc{{.*}}
|
||||
REPORT_IGNORE_DIR: {{^}}TOTAL 5{{.*}}100.00%{{$}}
|
||||
|
||||
# Ignore all files from "extra" directory even when SOURCES specified.
|
||||
RUN: llvm-cov report -instr-profile %S/Inputs/sources_specified/main.profdata \
|
||||
RUN: -path-equivalence=/tmp,%S/Inputs -ignore-filename-regex='.*extra[/\\].*' \
|
||||
RUN: %S/Inputs/sources_specified/main.covmapping \
|
||||
RUN: %S/Inputs/sources_specified/extra %S/Inputs/sources_specified/abs.h \
|
||||
RUN: | FileCheck -check-prefix=REPORT_IGNORE_DIR_WITH_SOURCES %s
|
||||
|
||||
REPORT_IGNORE_DIR_WITH_SOURCES-NOT: {{.*}}extra{{[/\\]}}dec.h{{.*}}
|
||||
REPORT_IGNORE_DIR_WITH_SOURCES-NOT: {{.*}}extra{{[/\\]}}inc.h{{.*}}
|
||||
REPORT_IGNORE_DIR_WITH_SOURCES-NOT: {{.*}}main.cc{{.*}}
|
||||
REPORT_IGNORE_DIR_WITH_SOURCES: {{.*}}abs.h{{.*}}
|
||||
REPORT_IGNORE_DIR_WITH_SOURCES: {{^}}TOTAL 4{{.*}}100.00%{{$}}
|
||||
|
||||
########################
|
||||
# Test "show" command.
|
||||
########################
|
||||
# Ignore all ".cc" files.
|
||||
RUN: llvm-cov show -instr-profile %S/Inputs/sources_specified/main.profdata \
|
||||
RUN: -path-equivalence=/tmp,%S/Inputs -ignore-filename-regex='.*\.cc$' \
|
||||
RUN: %S/Inputs/sources_specified/main.covmapping \
|
||||
RUN: | FileCheck -check-prefix=SHOW_IGNORE_CC %s
|
||||
|
||||
# Order of files may differ, check that there are 3 files and not abs.h.
|
||||
SHOW_IGNORE_CC-NOT: {{.*}}main.cc{{.*}}
|
||||
SHOW_IGNORE_CC: {{.*}}sources_specified{{.*}}
|
||||
SHOW_IGNORE_CC: {{.*}}sources_specified{{.*}}
|
||||
SHOW_IGNORE_CC: {{.*}}sources_specified{{.*}}
|
||||
|
||||
########################
|
||||
# Test "export" command.
|
||||
########################
|
||||
# Use a temp .json file as output in a single line. Ignore headers that have
|
||||
# name in a format of 3 symbols followed by ".h".
|
||||
RUN: llvm-cov export -instr-profile %S/Inputs/sources_specified/main.profdata \
|
||||
RUN: -path-equivalence=/tmp,%S/Inputs -ignore-filename-regex='.*...\.h$' \
|
||||
RUN: %S/Inputs/sources_specified/main.covmapping \
|
||||
RUN: > %t.export.json
|
||||
|
||||
RUN: FileCheck -check-prefix=NO-EXPORT_IGNORE_3_SYMBOLS_H %s < %t.export.json
|
||||
RUN: FileCheck -check-prefix=EXPORT_IGNORE_3_SYMBOLS_H %s < %t.export.json
|
||||
|
||||
NO-EXPORT_IGNORE_3_SYMBOLS_H-NOT: {{"filename":"(/|\\\\)tmp(/|\\\\)sources_specified(/|\\\\)abs.h"}}
|
||||
NO-EXPORT_IGNORE_3_SYMBOLS_H-NOT: {{"filename":"(/|\\\\)tmp(/|\\\\)sources_specified(/|\\\\)inc.h"}}
|
||||
NO-EXPORT_IGNORE_3_SYMBOLS_H-NOT: {{"filename":"(/|\\\\)tmp(/|\\\\)sources_specified(/|\\\\)dec.h"}}
|
||||
EXPORT_IGNORE_3_SYMBOLS_H: {{"filename":"(/|\\\\)tmp(/|\\\\)sources_specified(/|\\\\)main.cc"}}
|
|
@ -126,6 +126,7 @@ private:
|
|||
std::vector<StringRef> ObjectFilenames;
|
||||
CoverageViewOptions ViewOpts;
|
||||
CoverageFiltersMatchAll Filters;
|
||||
CoverageFilters IgnoreFilenameFilters;
|
||||
|
||||
/// The path to the indexed profile.
|
||||
std::string PGOFilename;
|
||||
|
@ -189,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) {
|
||||
|
@ -597,6 +599,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 "
|
||||
|
@ -714,6 +722,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() ||
|
||||
|
@ -734,6 +743,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) {
|
||||
|
@ -748,6 +762,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);
|
||||
|
||||
|
@ -862,8 +877,10 @@ int CodeCoverageTool::doShow(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()) {
|
||||
|
@ -962,7 +979,7 @@ int CodeCoverageTool::doReport(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 {
|
||||
|
@ -998,7 +1015,7 @@ int CodeCoverageTool::doExport(int argc, const char **argv,
|
|||
auto Exporter = CoverageExporterJson(*Coverage.get(), ViewOpts, outs());
|
||||
|
||||
if (SourceFiles.empty())
|
||||
Exporter.renderRoot();
|
||||
Exporter.renderRoot(IgnoreFilenameFilters);
|
||||
else
|
||||
Exporter.renderRoot(SourceFiles);
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#ifndef LLVM_COV_COVERAGEEXPORTER_H
|
||||
#define LLVM_COV_COVERAGEEXPORTER_H
|
||||
|
||||
#include "CoverageFilters.h"
|
||||
#include "CoverageSummaryInfo.h"
|
||||
#include "CoverageViewOptions.h"
|
||||
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
|
||||
|
@ -40,7 +41,7 @@ public:
|
|||
virtual ~CoverageExporter(){};
|
||||
|
||||
/// \brief Render the CoverageMapping object.
|
||||
virtual void renderRoot() = 0;
|
||||
virtual void renderRoot(const CoverageFilters &IgnoreFilenameFilters) = 0;
|
||||
|
||||
/// \brief Render the CoverageMapping object for specified source files.
|
||||
virtual void renderRoot(const std::vector<std::string> &SourceFiles) = 0;
|
||||
|
|
|
@ -117,10 +117,13 @@ void CoverageExporterJson::emitArrayEnd() {
|
|||
OS << "]";
|
||||
}
|
||||
|
||||
void CoverageExporterJson::renderRoot() {
|
||||
void CoverageExporterJson::renderRoot(
|
||||
const CoverageFilters &IgnoreFilenameFilters) {
|
||||
std::vector<std::string> SourceFiles;
|
||||
for (StringRef SF : Coverage.getUniqueSourceFiles())
|
||||
SourceFiles.emplace_back(SF);
|
||||
for (StringRef SF : Coverage.getUniqueSourceFiles()) {
|
||||
if (!IgnoreFilenameFilters.matchesFilename(SF))
|
||||
SourceFiles.emplace_back(SF);
|
||||
}
|
||||
renderRoot(SourceFiles);
|
||||
}
|
||||
|
||||
|
@ -218,11 +221,11 @@ void CoverageExporterJson::renderFiles(
|
|||
|
||||
void CoverageExporterJson::renderFile(const std::string &Filename,
|
||||
const FileCoverageSummary &FileReport) {
|
||||
// Start File.
|
||||
// Start File.
|
||||
emitDictStart();
|
||||
|
||||
emitDictElement("filename", Filename);
|
||||
|
||||
|
||||
if (!Options.ExportSummaryOnly) {
|
||||
// Calculate and render detailed coverage information for given file.
|
||||
auto FileCoverage = Coverage.getCoverageForFile(Filename);
|
||||
|
|
|
@ -101,7 +101,7 @@ public:
|
|||
const CoverageViewOptions &Options, raw_ostream &OS);
|
||||
|
||||
/// \brief Render the CoverageMapping object.
|
||||
void renderRoot() override;
|
||||
void renderRoot(const CoverageFilters &IgnoreFilenameFilters) override;
|
||||
|
||||
/// \brief Render the CoverageMapping object for specified source files.
|
||||
void renderRoot(const std::vector<std::string> &SourceFiles) override;
|
||||
|
|
|
@ -30,6 +30,10 @@ bool NameRegexCoverageFilter::matches(
|
|||
return llvm::Regex(Regex).match(Function.Name);
|
||||
}
|
||||
|
||||
bool NameRegexCoverageFilter::matchesFilename(StringRef Filename) const {
|
||||
return llvm::Regex(Regex).match(Filename);
|
||||
}
|
||||
|
||||
bool NameWhitelistCoverageFilter::matches(
|
||||
const coverage::CoverageMapping &,
|
||||
const coverage::FunctionRecord &Function) const {
|
||||
|
@ -63,6 +67,14 @@ bool CoverageFilters::matches(const coverage::CoverageMapping &CM,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool CoverageFilters::matchesFilename(StringRef Filename) const {
|
||||
for (const auto &Filter : Filters) {
|
||||
if (Filter->matchesFilename(Filename))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CoverageFiltersMatchAll::matches(
|
||||
const coverage::CoverageMapping &CM,
|
||||
const coverage::FunctionRecord &Function) const {
|
||||
|
|
|
@ -32,6 +32,11 @@ public:
|
|||
const coverage::FunctionRecord &Function) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Return true if the filename passes the requirements of this filter.
|
||||
virtual bool matchesFilename(StringRef Filename) const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Matches functions that contain a specific string in their name.
|
||||
|
@ -54,6 +59,8 @@ public:
|
|||
|
||||
bool matches(const coverage::CoverageMapping &CM,
|
||||
const coverage::FunctionRecord &Function) const override;
|
||||
|
||||
bool matchesFilename(StringRef Filename) const override;
|
||||
};
|
||||
|
||||
/// \brief Matches functions whose name appears in a SpecialCaseList in the
|
||||
|
@ -133,6 +140,8 @@ public:
|
|||
|
||||
bool matches(const coverage::CoverageMapping &CM,
|
||||
const coverage::FunctionRecord &Function) const override;
|
||||
|
||||
bool matchesFilename(StringRef Filename) const override;
|
||||
};
|
||||
|
||||
/// \brief A collection of filters.
|
||||
|
|
|
@ -379,10 +379,14 @@ std::vector<FileCoverageSummary> CoverageReport::prepareFileReports(
|
|||
return FileReports;
|
||||
}
|
||||
|
||||
void CoverageReport::renderFileReports(raw_ostream &OS) const {
|
||||
void CoverageReport::renderFileReports(
|
||||
raw_ostream &OS, const CoverageFilters &IgnoreFilenameFilters) const {
|
||||
std::vector<std::string> UniqueSourceFiles;
|
||||
for (StringRef SF : Coverage.getUniqueSourceFiles())
|
||||
UniqueSourceFiles.emplace_back(SF.str());
|
||||
for (StringRef SF : Coverage.getUniqueSourceFiles()) {
|
||||
// Apply ignore source files filters.
|
||||
if (!IgnoreFilenameFilters.matchesFilename(SF))
|
||||
UniqueSourceFiles.emplace_back(SF.str());
|
||||
}
|
||||
renderFileReports(OS, UniqueSourceFiles);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,8 @@ public:
|
|||
const CoverageFilter *Filters);
|
||||
|
||||
/// Render file reports for every unique file in the coverage mapping.
|
||||
void renderFileReports(raw_ostream &OS) const;
|
||||
void renderFileReports(raw_ostream &OS,
|
||||
const CoverageFilters &IgnoreFilenameFilters) const;
|
||||
|
||||
/// Render file reports for the files specified in \p Files.
|
||||
void renderFileReports(raw_ostream &OS, ArrayRef<std::string> Files) const;
|
||||
|
|
Loading…
Reference in New Issue