forked from OSchip/llvm-project
[llvm-cov] Add option to whitelist filenames
Add the `-whitelist-filename-regex` option to restrict coverage reporting to file paths that match a whitelist regex. Patch by Michael Daniels! rdar://56720320
This commit is contained in:
parent
3b982b11f4
commit
bfed824b57
|
@ -259,6 +259,10 @@ OPTIONS
|
||||||
|
|
||||||
Skip source code files with file paths that match the given regular expression.
|
Skip source code files with file paths that match the given regular expression.
|
||||||
|
|
||||||
|
.. option:: -whitelist-filename-regex=<PATTERN>
|
||||||
|
|
||||||
|
Show code coverage only for files that match the given regular expression.
|
||||||
|
|
||||||
.. option:: -format=<FORMAT>
|
.. option:: -format=<FORMAT>
|
||||||
|
|
||||||
Use the specified output format. The supported formats are: "text", "html".
|
Use the specified output format. The supported formats are: "text", "html".
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
########################
|
||||||
|
# Test "report" command.
|
||||||
|
########################
|
||||||
|
# Only source files
|
||||||
|
RUN: llvm-cov report -instr-profile %S/Inputs/sources_specified/main.profdata \
|
||||||
|
RUN: -path-equivalence=/tmp,%S/Inputs -whitelist-filename-regex='.*\.cc$' \
|
||||||
|
RUN: %S/Inputs/sources_specified/main.covmapping \
|
||||||
|
RUN: | FileCheck -check-prefix=REPORT_WHITELIST_SOURCE %s
|
||||||
|
|
||||||
|
REPORT_WHITELIST_SOURCE-NOT: {{.*}}dec.h{{.*}}
|
||||||
|
REPORT_WHITELIST_SOURCE-NOT: {{.*}}inc.h{{.*}}
|
||||||
|
REPORT_WHITELIST_SOURCE-NOT: {{.*}}abs.h{{.*}}
|
||||||
|
REPORT_WHITELIST_SOURCE: {{.*}}main.cc{{.*}}
|
||||||
|
REPORT_WHITELIST_SOURCE: {{^}}TOTAL 1{{.*}}100.00%{{$}}
|
||||||
|
|
||||||
|
# Whitelist all files from "extra" directory.
|
||||||
|
RUN: llvm-cov report -instr-profile %S/Inputs/sources_specified/main.profdata \
|
||||||
|
RUN: -path-equivalence=/tmp,%S/Inputs -whitelist-filename-regex='.*extra[/\\].*' \
|
||||||
|
RUN: %S/Inputs/sources_specified/main.covmapping \
|
||||||
|
RUN: | FileCheck -check-prefix=REPORT_WHITELIST_DIR %s
|
||||||
|
|
||||||
|
REPORT_WHITELIST_DIR: {{.*}}dec.h{{.*}}
|
||||||
|
REPORT_WHITELIST_DIR: {{.*}}inc.h{{.*}}
|
||||||
|
REPORT_WHITELIST_DIR-NOT: {{.*}}abs.h{{.*}}
|
||||||
|
REPORT_WHITELIST_DIR-NOT: {{.*}}main.cc{{.*}}
|
||||||
|
REPORT_WHITELIST_DIR: {{^}}TOTAL 2{{.*}}50.00%{{$}}
|
||||||
|
|
||||||
|
# Whitelist ignored files
|
||||||
|
RUN: llvm-cov report -instr-profile %S/Inputs/sources_specified/main.profdata \
|
||||||
|
RUN: -path-equivalence=/tmp,%S/Inputs \
|
||||||
|
RUN: -ignore-filename-regex='.*' -whitelist-filename-regex='.*' \
|
||||||
|
RUN: %S/Inputs/sources_specified/main.covmapping \
|
||||||
|
RUN: | FileCheck -check-prefix=REPORT_WHITELIST_IGNORED %s
|
||||||
|
|
||||||
|
REPORT_WHITELIST_IGNORED-NOT: {{.*}}dec.h{{.*}}
|
||||||
|
REPORT_WHITELIST_IGNORED-NOT: {{.*}}inc.h{{.*}}
|
||||||
|
REPORT_WHITELIST_IGNORED-NOT: {{.*}}abs.h{{.*}}
|
||||||
|
REPORT_WHITELIST_IGNORED-NOT: {{.*}}main.cc{{.*}}
|
||||||
|
REPORT_WHITELIST_IGNORED-NOT: {{^}}TOTAL 0{{.*}}0.00%{{$}}
|
||||||
|
|
||||||
|
# Whitelist 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 -whitelist-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_WHITELIST_DIR_WITH_SOURCES %s
|
||||||
|
|
||||||
|
REPORT_WHITELIST_DIR_WITH_SOURCES: {{.*}}dec.h{{.*}}
|
||||||
|
REPORT_WHITELIST_DIR_WITH_SOURCES: {{.*}}inc.h{{.*}}
|
||||||
|
REPORT_WHITELIST_DIR_WITH_SOURCES-NOT: {{.*}}abs.h{{.*}}
|
||||||
|
REPORT_WHITELIST_DIR_WITH_SOURCES-NOT: {{.*}}main.cc{{.*}}
|
||||||
|
REPORT_WHITELIST_DIR_WITH_SOURCES: {{^}}TOTAL 2{{.*}}50.00%{{$}}
|
||||||
|
|
||||||
|
########################
|
||||||
|
# Test "show" command.
|
||||||
|
########################
|
||||||
|
# Whitelist a couple files
|
||||||
|
RUN: llvm-cov show -instr-profile %S/Inputs/sources_specified/main.profdata \
|
||||||
|
RUN: -path-equivalence=/tmp,%S/Inputs \
|
||||||
|
RUN: -whitelist-filename-regex='.*\.cc$' -whitelist-filename-regex='.*abs\.h$' \
|
||||||
|
RUN: %S/Inputs/sources_specified/main.covmapping \
|
||||||
|
RUN: | FileCheck -check-prefix=SHOW_WHITELIST_CC %s
|
||||||
|
|
||||||
|
# Order of files may differ, check that there are 3 files and not abs.h.
|
||||||
|
SHOW_IGNORE_CC-NOT: {{.*}}main.cc{{.*}}
|
||||||
|
|
||||||
|
SHOW_WHITELIST_CC-NOT: {{.*}}dec.h{{.*}}
|
||||||
|
SHOW_WHITELIST_CC-NOT: {{.*}}inc.h{{.*}}
|
||||||
|
SHOW_WHITELIST_CC: {{.*}}sources_specified{{.*}}
|
||||||
|
SHOW_WHITELIST_CC: {{.*}}sources_specified{{.*}}
|
||||||
|
|
||||||
|
########################
|
||||||
|
# Test "export" command.
|
||||||
|
########################
|
||||||
|
# Use a temp .json file as output in a single line. Whitelist headers that have
|
||||||
|
# an 'a' follow by 2 chars followed by '.h'.
|
||||||
|
RUN: llvm-cov export -instr-profile %S/Inputs/sources_specified/main.profdata \
|
||||||
|
RUN: -path-equivalence=/tmp,%S/Inputs -whitelist-filename-regex='.*a..\.h$' \
|
||||||
|
RUN: %S/Inputs/sources_specified/main.covmapping \
|
||||||
|
RUN: > %t.export.json
|
||||||
|
|
||||||
|
RUN: FileCheck -check-prefix=NO-EXPORT_WHITELIST_3_SYMBOLS_H %s < %t.export.json
|
||||||
|
RUN: FileCheck -check-prefix=EXPORT_WHITELIST_3_SYMBOLS_H %s < %t.export.json
|
||||||
|
|
||||||
|
NO-EXPORT_WHITELIST_3_SYMBOLS_H-NOT: {{"filename":"(/|\\\\)tmp(/|\\\\)sources_specified(/|\\\\)inc.h"}}
|
||||||
|
NO-EXPORT_WHITELIST_3_SYMBOLS_H-NOT: {{"filename":"(/|\\\\)tmp(/|\\\\)sources_specified(/|\\\\)dec.h"}}
|
||||||
|
NO-EXPORT_WHITELIST_3_SYMBOLS_H-NOT: {{"filename":"(/|\\\\)tmp(/|\\\\)sources_specified(/|\\\\)main.cc"}}
|
||||||
|
EXPORT_WHITELIST_3_SYMBOLS_H: {{"filename":"(/|\\\\)tmp(/|\\\\)sources_specified(/|\\\\)abs.h"}}
|
|
@ -126,7 +126,7 @@ private:
|
||||||
std::vector<StringRef> ObjectFilenames;
|
std::vector<StringRef> ObjectFilenames;
|
||||||
CoverageViewOptions ViewOpts;
|
CoverageViewOptions ViewOpts;
|
||||||
CoverageFiltersMatchAll Filters;
|
CoverageFiltersMatchAll Filters;
|
||||||
CoverageFilters IgnoreFilenameFilters;
|
FilenameCoverageFilters FilenameFilters;
|
||||||
|
|
||||||
/// The path to the indexed profile.
|
/// The path to the indexed profile.
|
||||||
std::string PGOFilename;
|
std::string PGOFilename;
|
||||||
|
@ -190,7 +190,7 @@ void CodeCoverageTool::addCollectedPath(const std::string &Path) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sys::path::remove_dots(EffectivePath, /*remove_dot_dots=*/true);
|
sys::path::remove_dots(EffectivePath, /*remove_dot_dots=*/true);
|
||||||
if (!IgnoreFilenameFilters.matchesFilename(EffectivePath))
|
if (FilenameFilters.matchesFilename(EffectivePath))
|
||||||
SourceFiles.emplace_back(EffectivePath.str());
|
SourceFiles.emplace_back(EffectivePath.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,6 +595,12 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
|
||||||
"regular expression"),
|
"regular expression"),
|
||||||
cl::ZeroOrMore, cl::cat(FilteringCategory));
|
cl::ZeroOrMore, cl::cat(FilteringCategory));
|
||||||
|
|
||||||
|
cl::list<std::string> WhitelistFilenameRegexFilters(
|
||||||
|
"whitelist-filename-regex", cl::Optional,
|
||||||
|
cl::desc("Show code coverage only for file paths that match the given "
|
||||||
|
"regular expression"),
|
||||||
|
cl::ZeroOrMore, cl::cat(FilteringCategory));
|
||||||
|
|
||||||
cl::list<std::string> IgnoreFilenameRegexFilters(
|
cl::list<std::string> IgnoreFilenameRegexFilters(
|
||||||
"ignore-filename-regex", cl::Optional,
|
"ignore-filename-regex", cl::Optional,
|
||||||
cl::desc("Skip source code files with file paths that match the given "
|
cl::desc("Skip source code files with file paths that match the given "
|
||||||
|
@ -744,10 +750,11 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
|
||||||
Filters.push_back(std::move(StatFilterer));
|
Filters.push_back(std::move(StatFilterer));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the ignore filename filters.
|
// Create the filename filters.
|
||||||
for (const auto &RE : IgnoreFilenameRegexFilters)
|
for (const auto &RE : IgnoreFilenameRegexFilters)
|
||||||
IgnoreFilenameFilters.push_back(
|
FilenameFilters.blacklist(std::make_unique<NameRegexCoverageFilter>(RE));
|
||||||
std::make_unique<NameRegexCoverageFilter>(RE));
|
for (const auto &RE : WhitelistFilenameRegexFilters)
|
||||||
|
FilenameFilters.whitelist(std::make_unique<NameRegexCoverageFilter>(RE));
|
||||||
|
|
||||||
if (!Arches.empty()) {
|
if (!Arches.empty()) {
|
||||||
for (const std::string &Arch : Arches) {
|
for (const std::string &Arch : Arches) {
|
||||||
|
@ -763,7 +770,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IgnoreFilenameFilters are applied even when InputSourceFiles specified.
|
// FilenameFilters are applied even when InputSourceFiles specified.
|
||||||
for (const std::string &File : InputSourceFiles)
|
for (const std::string &File : InputSourceFiles)
|
||||||
collectPaths(File);
|
collectPaths(File);
|
||||||
|
|
||||||
|
@ -884,7 +891,7 @@ int CodeCoverageTool::doShow(int argc, const char **argv,
|
||||||
if (SourceFiles.empty())
|
if (SourceFiles.empty())
|
||||||
// Get the source files from the function coverage mapping.
|
// Get the source files from the function coverage mapping.
|
||||||
for (StringRef Filename : Coverage->getUniqueSourceFiles()) {
|
for (StringRef Filename : Coverage->getUniqueSourceFiles()) {
|
||||||
if (!IgnoreFilenameFilters.matchesFilename(Filename))
|
if (FilenameFilters.matchesFilename(Filename))
|
||||||
SourceFiles.push_back(Filename);
|
SourceFiles.push_back(Filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -988,7 +995,7 @@ int CodeCoverageTool::doReport(int argc, const char **argv,
|
||||||
CoverageReport Report(ViewOpts, *Coverage.get());
|
CoverageReport Report(ViewOpts, *Coverage.get());
|
||||||
if (!ShowFunctionSummaries) {
|
if (!ShowFunctionSummaries) {
|
||||||
if (SourceFiles.empty())
|
if (SourceFiles.empty())
|
||||||
Report.renderFileReports(llvm::outs(), IgnoreFilenameFilters);
|
Report.renderFileReports(llvm::outs(), FilenameFilters);
|
||||||
else
|
else
|
||||||
Report.renderFileReports(llvm::outs(), SourceFiles);
|
Report.renderFileReports(llvm::outs(), SourceFiles);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1054,7 +1061,7 @@ int CodeCoverageTool::doExport(int argc, const char **argv,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SourceFiles.empty())
|
if (SourceFiles.empty())
|
||||||
Exporter->renderRoot(IgnoreFilenameFilters);
|
Exporter->renderRoot(FilenameFilters);
|
||||||
else
|
else
|
||||||
Exporter->renderRoot(SourceFiles);
|
Exporter->renderRoot(SourceFiles);
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ public:
|
||||||
virtual ~CoverageExporter(){};
|
virtual ~CoverageExporter(){};
|
||||||
|
|
||||||
/// Render the CoverageMapping object.
|
/// Render the CoverageMapping object.
|
||||||
virtual void renderRoot(const CoverageFilters &IgnoreFilters) = 0;
|
virtual void renderRoot(const FilenameCoverageFilters &FilenameFilters) = 0;
|
||||||
|
|
||||||
/// Render the CoverageMapping object for specified source files.
|
/// Render the CoverageMapping object for specified source files.
|
||||||
virtual void renderRoot(ArrayRef<std::string> SourceFiles) = 0;
|
virtual void renderRoot(ArrayRef<std::string> SourceFiles) = 0;
|
||||||
|
|
|
@ -190,10 +190,11 @@ json::Array renderFunctions(
|
||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
void CoverageExporterJson::renderRoot(const CoverageFilters &IgnoreFilters) {
|
void CoverageExporterJson::renderRoot(
|
||||||
|
const FilenameCoverageFilters &FilenameFilters) {
|
||||||
std::vector<std::string> SourceFiles;
|
std::vector<std::string> SourceFiles;
|
||||||
for (StringRef SF : Coverage.getUniqueSourceFiles()) {
|
for (StringRef SF : Coverage.getUniqueSourceFiles()) {
|
||||||
if (!IgnoreFilters.matchesFilename(SF))
|
if (FilenameFilters.matchesFilename(SF))
|
||||||
SourceFiles.emplace_back(SF);
|
SourceFiles.emplace_back(SF);
|
||||||
}
|
}
|
||||||
renderRoot(SourceFiles);
|
renderRoot(SourceFiles);
|
||||||
|
|
|
@ -24,7 +24,7 @@ public:
|
||||||
: CoverageExporter(CoverageMapping, Options, OS) {}
|
: CoverageExporter(CoverageMapping, Options, OS) {}
|
||||||
|
|
||||||
/// Render the CoverageMapping object.
|
/// Render the CoverageMapping object.
|
||||||
void renderRoot(const CoverageFilters &IgnoreFilters) override;
|
void renderRoot(const FilenameCoverageFilters &FilenameFilters) override;
|
||||||
|
|
||||||
/// Render the CoverageMapping object for specified source files.
|
/// Render the CoverageMapping object for specified source files.
|
||||||
void renderRoot(ArrayRef<std::string> SourceFiles) override;
|
void renderRoot(ArrayRef<std::string> SourceFiles) override;
|
||||||
|
|
|
@ -106,10 +106,11 @@ void renderFiles(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
|
||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
void CoverageExporterLcov::renderRoot(const CoverageFilters &IgnoreFilters) {
|
void CoverageExporterLcov::renderRoot(
|
||||||
|
const FilenameCoverageFilters &FilenameFilters) {
|
||||||
std::vector<std::string> SourceFiles;
|
std::vector<std::string> SourceFiles;
|
||||||
for (StringRef SF : Coverage.getUniqueSourceFiles()) {
|
for (StringRef SF : Coverage.getUniqueSourceFiles()) {
|
||||||
if (!IgnoreFilters.matchesFilename(SF))
|
if (FilenameFilters.matchesFilename(SF))
|
||||||
SourceFiles.emplace_back(SF);
|
SourceFiles.emplace_back(SF);
|
||||||
}
|
}
|
||||||
renderRoot(SourceFiles);
|
renderRoot(SourceFiles);
|
||||||
|
|
|
@ -24,7 +24,7 @@ public:
|
||||||
: CoverageExporter(CoverageMapping, Options, OS) {}
|
: CoverageExporter(CoverageMapping, Options, OS) {}
|
||||||
|
|
||||||
/// Render the CoverageMapping object.
|
/// Render the CoverageMapping object.
|
||||||
void renderRoot(const CoverageFilters &IgnoreFilters) override;
|
void renderRoot(const FilenameCoverageFilters &FilenameFilters) override;
|
||||||
|
|
||||||
/// Render the CoverageMapping object for specified source files.
|
/// Render the CoverageMapping object for specified source files.
|
||||||
void renderRoot(ArrayRef<std::string> SourceFiles) override;
|
void renderRoot(ArrayRef<std::string> SourceFiles) override;
|
||||||
|
|
|
@ -83,3 +83,20 @@ bool CoverageFiltersMatchAll::matches(
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FilenameCoverageFilters::matchesFilename(StringRef Filename) const {
|
||||||
|
if (!Whitelist.empty() && !Whitelist.matchesFilename(Filename)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !Blacklist.matchesFilename(Filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilenameCoverageFilters::whitelist(
|
||||||
|
std::unique_ptr<CoverageFilter> Filter) {
|
||||||
|
Whitelist.push_back(std::move(Filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilenameCoverageFilters::blacklist(
|
||||||
|
std::unique_ptr<CoverageFilter> Filter) {
|
||||||
|
Blacklist.push_back(std::move(Filter));
|
||||||
|
}
|
||||||
|
|
|
@ -152,6 +152,22 @@ public:
|
||||||
const coverage::FunctionRecord &Function) const override;
|
const coverage::FunctionRecord &Function) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A collection of filters.
|
||||||
|
/// Matches filenames that are whitelisted and not blacklisted.
|
||||||
|
class FilenameCoverageFilters : public CoverageFilter {
|
||||||
|
protected:
|
||||||
|
CoverageFilters Whitelist;
|
||||||
|
CoverageFilters Blacklist;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void whitelist(std::unique_ptr<CoverageFilter> Filter);
|
||||||
|
void blacklist(std::unique_ptr<CoverageFilter> Filter);
|
||||||
|
|
||||||
|
bool matchesFilename(StringRef Filename) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace llvm
|
} // namespace llvm
|
||||||
|
|
||||||
#endif // LLVM_COV_COVERAGEFILTERS_H
|
#endif // LLVM_COV_COVERAGEFILTERS_H
|
||||||
|
|
|
@ -379,11 +379,11 @@ std::vector<FileCoverageSummary> CoverageReport::prepareFileReports(
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoverageReport::renderFileReports(
|
void CoverageReport::renderFileReports(
|
||||||
raw_ostream &OS, const CoverageFilters &IgnoreFilenameFilters) const {
|
raw_ostream &OS, const FilenameCoverageFilters &FilenameFilters) const {
|
||||||
std::vector<std::string> UniqueSourceFiles;
|
std::vector<std::string> UniqueSourceFiles;
|
||||||
for (StringRef SF : Coverage.getUniqueSourceFiles()) {
|
for (StringRef SF : Coverage.getUniqueSourceFiles()) {
|
||||||
// Apply ignore source files filters.
|
// Apply source files filters.
|
||||||
if (!IgnoreFilenameFilters.matchesFilename(SF))
|
if (FilenameFilters.matchesFilename(SF))
|
||||||
UniqueSourceFiles.emplace_back(SF.str());
|
UniqueSourceFiles.emplace_back(SF.str());
|
||||||
}
|
}
|
||||||
renderFileReports(OS, UniqueSourceFiles);
|
renderFileReports(OS, UniqueSourceFiles);
|
||||||
|
|
|
@ -53,7 +53,7 @@ public:
|
||||||
|
|
||||||
/// Render file reports for every unique file in the coverage mapping.
|
/// Render file reports for every unique file in the coverage mapping.
|
||||||
void renderFileReports(raw_ostream &OS,
|
void renderFileReports(raw_ostream &OS,
|
||||||
const CoverageFilters &IgnoreFilenameFilters) const;
|
const FilenameCoverageFilters &FilenameFilters) const;
|
||||||
|
|
||||||
/// Render file reports for the files specified in \p Files.
|
/// Render file reports for the files specified in \p Files.
|
||||||
void renderFileReports(raw_ostream &OS, ArrayRef<std::string> Files) const;
|
void renderFileReports(raw_ostream &OS, ArrayRef<std::string> Files) const;
|
||||||
|
|
Loading…
Reference in New Issue