Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions llvm/docs/CommandGuide/llvm-cov.rst
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,10 @@ OPTIONS

Skip source code files with file paths that match the given regular expression.

.. option:: -include-filename-regex=<PATTERN>

Only include 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".
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/tools/llvm-cov/ignore-filename-regex.test
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ 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.
# Order of files may differ, check that there are 3 files and not main.cc.
SHOW_IGNORE_CC-NOT: {{.*}}main.cc{{.*}}
SHOW_IGNORE_CC: {{.*}}sources_specified{{.*}}
SHOW_IGNORE_CC: {{.*}}sources_specified{{.*}}
Expand Down
40 changes: 40 additions & 0 deletions llvm/test/tools/llvm-cov/include-and-exlude-filename-regex.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
########################
# Test "report" command.
########################
# Include files with a "a" in their name and exclude header files.
RUN: llvm-cov report -instr-profile %S/Inputs/sources_specified/main.profdata \
RUN: -path-equivalence=/tmp,%S/Inputs \
RUN: -include-filename-regex='.*a.*' -ignore-filename-regex='.*\.h$' \
RUN: %S/Inputs/sources_specified/main.covmapping --show-branch-summary=false \
RUN: | FileCheck -check-prefix=REPORT_SOURCE_WITH_A %s

REPORT_SOURCE_WITH_A-NOT: {{.*}}dec.h{{.*}}
REPORT_SOURCE_WITH_A-NOT: {{.*}}inc.h{{.*}}
REPORT_SOURCE_WITH_A-NOT: {{.*}}abs.h{{.*}}
REPORT_SOURCE_WITH_A: {{^}}TOTAL 1{{.*}}100.00%{{$}}

# Only include files from "extra" directory and ignore files starting with "d".
RUN: llvm-cov report -instr-profile %S/Inputs/sources_specified/main.profdata \
RUN: -path-equivalence=/tmp,%S/Inputs \
RUN: -include-filename-regex='.*extra[/\\].*' -ignore-filename-regex='.[/\\]d.*' \
RUN: %S/Inputs/sources_specified/main.covmapping --show-branch-summary=false \
RUN: | FileCheck -check-prefix=REPORT_INCLUDE_DIR_WITHOUT_D %s

REPORT_INCLUDE_DIR_WITHOUT_D-NOT: {{.*}}extra{{[/\\]}}dec.h{{.*}}
REPORT_INCLUDE_DIR_WITHOUT_D: {{.*}}extra{{[/\\]}}inc.h{{.*}}
REPORT_INCLUDE_DIR_WITHOUT_D-NOT: {{.*}}abs.h{{.*}}
REPORT_INCLUDE_DIR_WITHOUT_D-NOT: {{.*}}main.cc{{.*}}
REPORT_INCLUDE_DIR_WITHOUT_D: {{^}}TOTAL 1{{.*}}100.00%{{$}}

# Same test as above but the arguments are passed in a different order.
RUN: llvm-cov report -instr-profile %S/Inputs/sources_specified/main.profdata \
RUN: -path-equivalence=/tmp,%S/Inputs \
RUN: -ignore-filename-regex='.[/\\]d.*' -include-filename-regex='.*extra[/\\].*' \
RUN: %S/Inputs/sources_specified/main.covmapping --show-branch-summary=false \
RUN: | FileCheck -check-prefix=REPORT_INCLUDE_DIR_WITHOUT_D_REVERSED %s

REPORT_INCLUDE_DIR_WITHOUT_D_REVERSED-NOT: {{.*}}extra{{[/\\]}}dec.h{{.*}}
REPORT_INCLUDE_DIR_WITHOUT_D_REVERSED: {{.*}}extra{{[/\\]}}inc.h{{.*}}
REPORT_INCLUDE_DIR_WITHOUT_D_REVERSED-NOT: {{.*}}abs.h{{.*}}
REPORT_INCLUDE_DIR_WITHOUT_D_REVERSED-NOT: {{.*}}main.cc{{.*}}
REPORT_INCLUDE_DIR_WITHOUT_D_REVERSED: {{^}}TOTAL 1{{.*}}100.00%{{$}}
59 changes: 59 additions & 0 deletions llvm/test/tools/llvm-cov/include-filename-regex.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
########################
# Test "report" command.
########################
# Include only source files.
RUN: llvm-cov report -instr-profile %S/Inputs/sources_specified/main.profdata \
RUN: -path-equivalence=/tmp,%S/Inputs -include-filename-regex='.*\.cc$' \
RUN: %S/Inputs/sources_specified/main.covmapping --show-branch-summary=false \
RUN: | FileCheck -check-prefix=REPORT_INCLUDE_SOURCE %s

REPORT_INCLUDE_SOURCE-NOT: {{.*}}dec.h{{.*}}
REPORT_INCLUDE_SOURCE-NOT: {{.*}}inc.h{{.*}}
REPORT_INCLUDE_SOURCE-NOT: {{.*}}abs.h{{.*}}
REPORT_INCLUDE_SOURCE: {{^}}TOTAL 1{{.*}}100.00%{{$}}

# Only include files from "extra" directory.
RUN: llvm-cov report -instr-profile %S/Inputs/sources_specified/main.profdata \
RUN: -path-equivalence=/tmp,%S/Inputs -include-filename-regex='.*extra[/\\].*' \
RUN: %S/Inputs/sources_specified/main.covmapping --show-branch-summary=false \
RUN: | FileCheck -check-prefix=REPORT_INCLUDE_DIR %s

# llvm-cov uses extra as the base directory.
REPORT_INCLUDE_DIR: {{.*}}dec.h{{.*}}
REPORT_INCLUDE_DIR: {{.*}}inc.h{{.*}}
REPORT_INCLUDE_DIR-NOT: {{.*}}abs.h{{.*}}
REPORT_INCLUDE_DIR-NOT: {{.*}}main.cc{{.*}}
REPORT_INCLUDE_DIR: {{^}}TOTAL 2{{.*}}50.00%{{$}}

########################
# Test "show" command.
########################
# Include only header files.
RUN: llvm-cov show -instr-profile %S/Inputs/sources_specified/main.profdata \
RUN: -path-equivalence=/tmp,%S/Inputs -include-filename-regex='.*\.h$' \
RUN: %S/Inputs/sources_specified/main.covmapping \
RUN: | FileCheck -check-prefix=SHOW_INCLUDE_HEADERS %s

# Order of files may differ, check that there are 3 files and not main.cc.
SHOW_INCLUDE_HEADERS-NOT: {{.*}}main.cc{{.*}}
SHOW_INCLUDE_HEADERS: {{.*}}sources_specified{{.*}}
SHOW_INCLUDE_HEADERS: {{.*}}sources_specified{{.*}}
SHOW_INCLUDE_HEADERS: {{.*}}sources_specified{{.*}}

########################
# Test "export" command.
########################
# Use a temp .json file as output in a single line. Only include 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 -include-filename-regex='.*...\.h$' \
RUN: %S/Inputs/sources_specified/main.covmapping \
RUN: > %t.export.json

RUN: FileCheck -check-prefix=NO-EXPORT_INCLUDE_3_SYMBOLS_H %s < %t.export.json
RUN: FileCheck -check-prefix=EXPORT_INCLUDE_3_SYMBOLS_H %s < %t.export.json

NO-EXPORT_INCLUDE_3_SYMBOLS_H: {{"filename":"(/|\\\\)tmp(/|\\\\)sources_specified(/|\\\\)abs.h"}}
NO-EXPORT_INCLUDE_3_SYMBOLS_H: {{"filename":"(/|\\\\)tmp(/|\\\\)sources_specified(/|\\\\)extra(/|\\\\)dec.h"}}
NO-EXPORT_INCLUDE_3_SYMBOLS_H: {{"filename":"(/|\\\\)tmp(/|\\\\)sources_specified(/|\\\\)extra(/|\\\\)inc.h"}}
EXPORT_INCLUDE_3_SYMBOLS_H-NOT: {{"filename":"(/|\\\\)tmp(/|\\\\)sources_specified(/|\\\\)main.cc"}}
25 changes: 17 additions & 8 deletions llvm/tools/llvm-cov/CodeCoverage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ class CodeCoverageTool {
std::vector<StringRef> ObjectFilenames;
CoverageViewOptions ViewOpts;
CoverageFiltersMatchAll Filters;
CoverageFilters IgnoreFilenameFilters;
CoverageFilters FilenameFilters;

/// True if InputSourceFiles are provided.
bool HadSourceFiles = false;
Expand Down Expand Up @@ -222,7 +222,7 @@ void CodeCoverageTool::addCollectedPath(const std::string &Path) {
return;
}
sys::path::remove_dots(EffectivePath, /*remove_dot_dot=*/true);
if (!IgnoreFilenameFilters.matchesFilename(EffectivePath))
if (!FilenameFilters.matchesFilename(EffectivePath))
SourceFiles.emplace_back(EffectivePath.str());
HadSourceFiles = !SourceFiles.empty();
}
Expand Down Expand Up @@ -734,6 +734,12 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
"regular expression"),
cl::cat(FilteringCategory));

cl::list<std::string> IncludeFilenameRegexFilters(
"include-filename-regex", cl::Optional,
cl::desc("Only include source code files with file paths that match the "
"given regular expression"),
cl::cat(FilteringCategory));

cl::opt<double> RegionCoverageLtFilter(
"region-coverage-lt", cl::Optional,
cl::desc("Show code coverage only for functions with region coverage "
Expand Down Expand Up @@ -935,8 +941,11 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {

// Create the ignore filename filters.
for (const auto &RE : IgnoreFilenameRegexFilters)
IgnoreFilenameFilters.push_back(
std::make_unique<NameRegexCoverageFilter>(RE));
FilenameFilters.push_back(std::make_unique<NameRegexCoverageFilter>(RE));

for (const auto &RE : IncludeFilenameRegexFilters)
FilenameFilters.push_back(std::make_unique<NameRegexCoverageFilter>(
RE, NameRegexCoverageFilter::FilterType::Include));

if (!Arches.empty()) {
for (const std::string &Arch : Arches) {
Expand All @@ -953,7 +962,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)
collectPaths(File);

Expand Down Expand Up @@ -1164,7 +1173,7 @@ int CodeCoverageTool::doShow(int argc, const char **argv,
if (SourceFiles.empty() && !HadSourceFiles)
// Get the source files from the function coverage mapping.
for (StringRef Filename : Coverage->getUniqueSourceFiles()) {
if (!IgnoreFilenameFilters.matchesFilename(Filename))
if (!FilenameFilters.matchesFilename(Filename))
SourceFiles.push_back(std::string(Filename));
}

Expand Down Expand Up @@ -1276,7 +1285,7 @@ int CodeCoverageTool::doReport(int argc, const char **argv,
CoverageReport Report(ViewOpts, *Coverage);
if (!ShowFunctionSummaries) {
if (SourceFiles.empty())
Report.renderFileReports(llvm::outs(), IgnoreFilenameFilters);
Report.renderFileReports(llvm::outs(), FilenameFilters);
else
Report.renderFileReports(llvm::outs(), SourceFiles);
} else {
Expand Down Expand Up @@ -1360,7 +1369,7 @@ int CodeCoverageTool::doExport(int argc, const char **argv,
}

if (SourceFiles.empty())
Exporter->renderRoot(IgnoreFilenameFilters);
Exporter->renderRoot(FilenameFilters);
else
Exporter->renderRoot(SourceFiles);

Expand Down
3 changes: 2 additions & 1 deletion llvm/tools/llvm-cov/CoverageFilters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ bool NameRegexCoverageFilter::matches(
}

bool NameRegexCoverageFilter::matchesFilename(StringRef Filename) const {
return llvm::Regex(Regex).match(Filename);
bool regex_match = llvm::Regex(Regex).match(Filename);
return Type == FilterType::Exclude ? regex_match : !regex_match;
}

bool NameAllowlistCoverageFilter::matches(
Expand Down
12 changes: 11 additions & 1 deletion llvm/tools/llvm-cov/CoverageFilters.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,20 @@ class NameCoverageFilter : public CoverageFilter {

/// Matches functions whose name matches a certain regular expression.
class NameRegexCoverageFilter : public CoverageFilter {
public:
enum class FilterType {
Include,
Exclude,
};

private:
StringRef Regex;
FilterType Type;

public:
NameRegexCoverageFilter(StringRef Regex) : Regex(Regex) {}
NameRegexCoverageFilter(StringRef Regex,
FilterType Type = FilterType::Exclude)
: Regex(Regex), Type(Type) {}

bool matches(const coverage::CoverageMapping &CM,
const coverage::FunctionRecord &Function) const override;
Expand Down