Skip to content

Commit bfb0a50

Browse files
committed
Improved support for Python, Perl, Java.
Signed-off-by: Henry Cox <[email protected]>
1 parent 1171b66 commit bfb0a50

File tree

10 files changed

+219
-75
lines changed

10 files changed

+219
-75
lines changed

CONTRIBUTING

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,23 +104,20 @@ accompanied by tests for those features. Lack of tests may substantially
104104
delay review and/or acceptance of your contribution.
105105

106106
It is recommended to check code coverage of your contribution.
107-
The lcov project currently uses Devel::Cover to measure perl code coverage.
108-
To generate a report:
107+
The lcov project currently uses Devel::Cover to measure perl code coverage,
108+
then 'perl2lcov' and 'py2lcov' and lcov to generate a coverage report:
109109

110110
$ make COVERAGE=1 test
111111

112-
and then check coverage at ./tests/cover_db/coverage.html
112+
and then check coverage by pointing your browser to
113+
./tests/lcov_coveragee/index.html
114+
113115
Note that certain version combinations of gcc, perl, and Devel::Cover
114116
will crash during test execution. To work around the issue, some tests
115117
ignore these errors if passed the "--keep-going" flag:
116118

117119
$ make COVERAGE=1 TESTCASE_ARGS=--keep-going test
118120

119-
It is more than a little ironic that the lcov project does not use lcov
120-
to check its own coverage. Similarly, it is disappointing that it does
121-
not use differential coverage on new contributions. (If this statement
122-
makes you think of a small project that you want to tackle: excellent.)
123-
124121
Pull requests which add tests for existing features or which enhance
125122
existing tests are actively encouraged.
126123
The lcov maintainers are painfully aware that the code coverage of the

bin/genhtml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ use lcovutil qw (set_tool_name define_errors parse_ignore_errors
110110
info $verbose init_verbose_flag debug $debug $devnull
111111
parseOptions
112112
strip_directories
113-
set_rtl_extensions set_c_extensions
114113
parse_cov_filters summarize_cov_filters
115114
$FILTER_BRANCH_NO_COND $FILTER_LINE_CLOSE_BRACE @cov_filter
116115
rate get_overall_line $default_precision check_precision

bin/lcov

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ use lcovutil qw ($tool_name $tool_dir $lcov_version $lcov_url
8383
create_temp_dir temp_cleanup
8484
summarize_cov_filters
8585
$FILTER_BRANCH_NO_COND $FILTER_LINE_CLOSE_BRACE @cov_filter
86-
set_rtl_extensions set_c_extensions
8786
8887
@exclude_file_patterns @include_file_patterns %excluded_files
8988
warn_file_patterns summarize_messages

lib/lcovutil.pm

Lines changed: 67 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ our @EXPORT_OK = qw($tool_name $tool_dir $lcov_version $lcov_url
6161
parse_cov_filters summarize_cov_filters
6262
disable_cov_filters reenable_cov_filters is_filter_enabled
6363
filterStringsAndComments simplifyCode balancedParens
64-
set_rtl_extensions set_c_extensions
64+
set_extensions
6565
$source_filter_lookahead $source_filter_bitwise_are_conditional
6666
$exclude_exception_branch
6767
$derive_function_end_line $derive_function_end_line_all_files
@@ -189,8 +189,6 @@ our $excessive_count_threshold; # default not set: don't check
189189

190190
our $br_coverage = 0; # If set, generate branch coverage statistics
191191
our $func_coverage = 1; # If set, generate function coverage statistics
192-
our $rtlExtensions;
193-
our $cExtensions;
194192

195193
# for external file filtering
196194
our @internal_dirs;
@@ -300,9 +298,12 @@ our $trivial_function_threshold = 5;
300298
our @omit_line_patterns;
301299
our @exclude_function_patterns;
302300

303-
our $rtl_file_extensions = 'v|vh|sv|vhdl?';
304-
our $c_file_extensions = 'c|h|i||C|H|I|icc|cpp|cc|cxx|hh|hpp|hxx';
305-
our $java_file_extensions = 'java';
301+
our %languageExtensions = ('c' => 'c|h|i||C|H|I|icc|cpp|cc|cxx|hh|hpp|hxx',
302+
'rtl' => 'v|vh|sv|vhdl?',
303+
'perl' => 'pl|pm',
304+
'python' => 'py',
305+
'java' => 'java');
306+
306307
# don't look more than 10 lines ahead when filtering (default)
307308
our $source_filter_lookahead = 10;
308309
# by default, don't treat expressions containing bitwise operators '|', '&', '~'
@@ -801,16 +802,11 @@ sub save_profile($)
801802
}
802803
}
803804

804-
sub set_rtl_extensions
805+
sub set_extensions
805806
{
806-
my $str = shift;
807-
$rtl_file_extensions = join('|', split($split_char, $str));
808-
}
809-
810-
sub set_c_extensions
811-
{
812-
my $str = shift;
813-
$c_file_extensions = join('|', split($split_char, $str));
807+
my ($type, $str) = @_;
808+
die("unknown language '$type'") unless exits($languageExtensions{$type});
809+
$languageExtensions{$type} = join('|', split($split_char, $str));
814810
}
815811

816812
sub do_mangle_check
@@ -1030,6 +1026,8 @@ my %deprecated_rc = ("genhtml_demangle_cpp" => "demangle_cpp",
10301026
"genhtml_function_coverage" => "function_coverage",
10311027
"genhtml_branch_coverage" => "branch_coverage",);
10321028
my @deprecated_uses;
1029+
my ($cExtensions, $rtlExtensions, $javaExtensions,
1030+
$perlExtensions, $pythonExtensions);
10331031

10341032
my %rc_common = (
10351033
'derive_function_end_line' => \$lcovutil::derive_function_end_line,
@@ -1057,6 +1055,9 @@ my %rc_common = (
10571055
'warn_once_per_file' => \$lcovutil::warn_once_per_file,
10581056
"rtl_file_extensions" => \$rtlExtensions,
10591057
"c_file_extensions" => \$cExtensions,
1058+
"perl_file_extensions" => \$perlExtensions,
1059+
"python_file_extensions" => \$pythonExtensions,
1060+
"java_file_extensions" => \$javaExtensions,
10601061
"filter_lookahead" => \$lcovutil::source_filter_lookahead,
10611062
"filter_bitwise_conditional" =>
10621063
\$lcovutil::source_filter_bitwise_are_conditional,
@@ -1198,10 +1199,14 @@ sub apply_rc_params($)
11981199
# Copy configuration file and --rc values to variables
11991200
$set_value |= apply_config(\%rcHash, $config, \%new_opt_rc);
12001201
}
1201-
lcovutil::set_rtl_extensions($rtlExtensions)
1202-
if $rtlExtensions;
1203-
lcovutil::set_c_extensions($cExtensions)
1204-
if $cExtensions;
1202+
foreach my $d (['rtl', $rtlExtensions],
1203+
['c', $cExtensions],
1204+
['perl', $perlExtensions],
1205+
['python', $pythonExtensions],
1206+
['java', $javaExtensions]
1207+
) {
1208+
lcovutil::set_extensions(@$d) if $d->[1];
1209+
}
12051210

12061211
return $set_value;
12071212
}
@@ -3473,7 +3478,7 @@ sub hit
34733478
sub isLambda
34743479
{
34753480
my $self = shift;
3476-
return (TraceFile::is_c_file($self->filename()) &&
3481+
return (TraceFile::is_language('c', $self->filename()) &&
34773482
$self->name() =~ /{lambda\(/);
34783483
}
34793484

@@ -5504,7 +5509,7 @@ sub _eraseFunctions
55045509
lcovutil::info(1, "no end line for '$name' at $key\n");
55055510
} elsif (
55065511
defined($removeTrivial) &&
5507-
is_c_file($source_file) &&
5512+
is_language('c', $source_file) &&
55085513
(defined($srcReader) &&
55095514
$srcReader->containsTrivialFunction($fcn->line(), $end_line))
55105515
) {
@@ -5555,17 +5560,19 @@ sub _eraseFunctions
55555560
sub _filterFile
55565561
{
55575562
my ($traceInfo, $source_file, $srcReader, $state) = @_;
5558-
my $region = $cov_filter[$FILTER_EXCLUDE_REGION];
5559-
my $range = $cov_filter[$lcovutil::FILTER_LINE_RANGE];
5560-
my $branch_histogram = $cov_filter[$FILTER_BRANCH_NO_COND];
5561-
my $brace_histogram = $cov_filter[$FILTER_LINE_CLOSE_BRACE];
5563+
my $region = $cov_filter[$FILTER_EXCLUDE_REGION];
5564+
my $branch_region = $cov_filter[$FILTER_EXCLUDE_BRANCH];
5565+
my $range = $cov_filter[$lcovutil::FILTER_LINE_RANGE];
5566+
my $branch_histogram = $cov_filter[$FILTER_BRANCH_NO_COND]
5567+
if (is_language('c', $source_file));
5568+
my $brace_histogram = $cov_filter[$FILTER_LINE_CLOSE_BRACE]
5569+
if (is_language('c', $source_file));
55625570
my $blank_histogram = $cov_filter[$FILTER_BLANK_LINE];
55635571
my $function_alias_histogram = $cov_filter[$FILTER_FUNCTION_ALIAS];
55645572
my $trivial_histogram = $cov_filter[$FILTER_TRIVIAL_FUNCTION];
55655573

55665574
my $context = MessageContext->new("filtering $source_file");
5567-
if (is_c_file($source_file) &&
5568-
lcovutil::is_filter_enabled()) {
5575+
if (lcovutil::is_filter_enabled()) {
55695576
lcovutil::info(1, "reading $source_file for lcov filtering\n");
55705577
$srcReader->open($source_file);
55715578
} else {
@@ -5617,8 +5624,7 @@ sub _filterFile
56175624
}
56185625

56195626
return
5620-
unless (is_c_file($source_file) &&
5621-
$srcReader->notEmpty() &&
5627+
unless ($srcReader->notEmpty() &&
56225628
lcovutil::is_filter_enabled());
56235629

56245630
my ($testdata, $sumcount, $funcdata, $checkdata,
@@ -5668,29 +5674,32 @@ sub _filterFile
56685674
# $testbrcount is undef if there are no branches in the scope
56695675
if ($lcovutil::br_coverage &&
56705676
defined($testbrcount) &&
5671-
($branch_histogram || $region || $range)) {
5677+
($branch_histogram || $region || $branch_region || $range)) {
56725678
foreach my $line ($testbrcount->keylist()) {
5679+
# for counting: keep track filter which triggered exclusion -
56735680
my $remove;
56745681
# omit if line excluded or branches excluded on this line
56755682
if ($srcReader->isOutOfRange($line, 'branch')) {
56765683
# only counting line coverpoints that got excluded
5677-
$remove = 1;
5678-
} elsif ($region &&
5684+
die("inconsistent state") unless $range;
5685+
$remove = $range;
5686+
} elsif (($region || $branch_region) &&
56795687
$srcReader->isExcluded($line, 2)) {
56805688
# all branches here
5681-
$remove = 1;
5689+
$remove = $region ? $region : $branch_region;
5690+
die("inconsistent") unless $remove;
56825691
} elsif ($branch_histogram &&
56835692
!$srcReader->containsConditional($line)) {
5684-
$remove = 1;
5693+
$remove = $branch_histogram;
5694+
}
5695+
if ($remove) {
56855696
my $brdata = $testbrcount->value($line);
5686-
++$branch_histogram->[0]; # one line where we skip
5687-
$branch_histogram->[1] += scalar($brdata->blocks());
5697+
++$remove->[0]; # one line where we skip
5698+
$remove->[1] += ($brdata->totals())[0];
56885699
lcovutil::info(2,
56895700
"filter BRDA '" .
56905701
$srcReader->getLine($line) .
56915702
"' $source_file:$line\n");
5692-
}
5693-
if ($remove) {
56945703
# now remove this branch everywhere...
56955704
foreach my $tn ($testbrdata->keylist()) {
56965705
my $d = $testbrdata->value($tn);
@@ -6190,15 +6199,20 @@ sub applyFilters
61906199
delete($self->[FILES]->{$source_file});
61916200
next;
61926201
}
6193-
# derive function end line for C/C++ code if requested
6194-
# (not trying to handle python nested functions, etc)
6202+
# derive function end line for C/C++ and java code if requested
6203+
# (not trying to handle python nested functions, etc.)
6204+
# However, see indent handling in the py2lcov script. Arguably, that
6205+
# could/should be done here/in Perl rather than in Python.)
6206+
# Jacoco pretends to report function end line - but it appears
6207+
# to be the last line executed - not the actual last line of
6208+
# the function - so broken/completely useless.
61956209
DERIVE:
61966210
if (0 == ($self->[STATE] & DID_DERIVE) &&
61976211
defined($lcovutil::derive_function_end_line) &&
61986212
$lcovutil::derive_function_end_line != 0 &&
61996213
defined($lcovutil::func_coverage) &&
62006214
($lcovutil::derive_end_line_all_files ||
6201-
is_c_file($source_file))
6215+
is_language('c|java|perl', $source_file))
62026216
) {
62036217
my @lines = sort { $a <=> $b } $traceInfo->sum()->keylist();
62046218
# sort functions by start line number
@@ -6311,7 +6325,7 @@ sub applyFilters
63116325
(0 != scalar(@lcovutil::exclude_function_patterns) ||
63126326
defined($lcovutil::cov_filter[$FILTER_TRIVIAL_FUNCTION]))
63136327
) ||
6314-
(is_c_file($source_file) &&
6328+
(is_language('c|perl|python|java', $source_file) &&
63156329
lcovutil::is_filter_enabled()));
63166330
push(@filter_workList, [$traceInfo, $name]);
63176331
} # foreach file
@@ -6325,22 +6339,15 @@ sub applyFilters
63256339
}
63266340
}
63276341

6328-
sub is_rtl_file
6342+
sub is_language
63296343
{
6330-
my $filename = shift;
6331-
return $filename =~ /\.($rtl_file_extensions)$/ ? 1 : 0;
6332-
}
6333-
6334-
sub is_java_file
6335-
{
6336-
my $filename = shift;
6337-
return $filename =~ /\.($java_file_extensions)$/ ? 1 : 0;
6338-
}
6339-
6340-
sub is_c_file
6341-
{
6342-
my $filename = shift;
6343-
return $filename =~ /\.($c_file_extensions)$/ ? 1 : 0;
6344+
my ($lang, $filename) = @_;
6345+
foreach my $l (split('\|', $lang)) {
6346+
die("unknown language '$l'")
6347+
unless exists($lcovutil::languageExtensions{$l});
6348+
return 1 if $filename =~ /\.($lcovutil::languageExtensions{$l})$/;
6349+
}
6350+
return 0;
63446351
}
63456352

63466353
# Read in the contents of the .info file specified by INFO_FILENAME. Data will
@@ -6476,7 +6483,7 @@ sub _read_info
64766483
# at the source for some previous file.
64776484
$readSourceCallback->close();
64786485
undef $currentBranchLine;
6479-
if (is_c_file($filename)) {
6486+
if (is_language('c', $filename)) {
64806487
$readSourceCallback->open($filename);
64816488
}
64826489
}
@@ -6686,7 +6693,7 @@ sub _read_info
66866693
# generate an CNF or truth-table like entry corresponding
66876694
# to the branch.
66886695

6689-
if (!is_c_file($filename)) {
6696+
if (!is_language('c', $filename)) {
66906697
# At least at present, Verilog/SystemVerilog/VHDL,
66916698
# java, python, etc don't need branch number fixing
66926699
my $key = "$line,$block";
@@ -6737,7 +6744,7 @@ sub _read_info
67376744
$fileData->version($version)
67386745
if (defined($version) && $version ne "");
67396746
}
6740-
if (is_c_file($filename)) {
6747+
if (is_language('c', $filename)) {
67416748
# RTL code was added directly - no issue with
67426749
# duplicate data entries in geninfo result
67436750
my $testcaseBranchData = $fileData->testbr($testname)

man/lcovrc.5

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,57 @@ This parameter must be set from the lcovrc file or via the
780780
command line option; note that you may need to protect the value from shell expansion in the latter case.
781781
.br
782782

783+
.PP
784+
785+
.BR java_file_extensions " ="
786+
.IR str[,str]+
787+
.IP
788+
Specify a comma-separated list of file extensions which should be assumed to be Java code.
789+
.br
790+
791+
If not specified, the default set is 'java'.
792+
If you want all files to be treated as Java code, you can use:
793+
.I java_file_extensions = .*
794+
795+
This parameter must be set from the lcovrc file or via the
796+
.I \-\-rc name=value
797+
command line option; note that you may need to protect the value from shell expansion in the latter case.
798+
.br
799+
800+
.PP
801+
802+
.BR perl_file_extensions " ="
803+
.IR str[,str]+
804+
.IP
805+
Specify a comma-separated list of file extensions which should be assumed to be Perl code.
806+
.br
807+
808+
If not specified, the default set is 'pl,pm'.
809+
If you want all files to be treated as Perl code, you can use:
810+
.I perl_file_extensions = .*
811+
812+
This parameter must be set from the lcovrc file or via the
813+
.I \-\-rc name=value
814+
command line option; note that you may need to protect the value from shell expansion in the latter case.
815+
.br
816+
817+
.PP
818+
819+
.BR python_file_extensions " ="
820+
.IR str[,str]+
821+
.IP
822+
Specify a comma-separated list of file extensions which should be assumed to be Python code.
823+
.br
824+
825+
If not specified, the default set is 'py'.
826+
If you want all files to be treated as Python code, you can use:
827+
.I python_file_extensions = .*
828+
829+
This parameter must be set from the lcovrc file or via the
830+
.I \-\-rc name=value
831+
command line option; note that you may need to protect the value from shell expansion in the latter case.
832+
.br
833+
783834

784835
.PP
785836

0 commit comments

Comments
 (0)