From c1b16a675dbba5f6ca4467ed6f20630a27aba488 Mon Sep 17 00:00:00 2001 From: Henry Cox Date: Tue, 12 Nov 2024 06:46:10 -0500 Subject: [PATCH] Fix function data merge bug - see #327. Signed-off-by: Henry Cox --- bin/genhtml | 19 ++++++++----- lib/lcovutil.pm | 52 +++++++++++++++++++++++++++--------- tests/perl2lcov/perltest1.sh | 3 ++- tests/xml2lcov/xml2lcov.sh | 5 +++- 4 files changed, 58 insertions(+), 21 deletions(-) diff --git a/bin/genhtml b/bin/genhtml index 9d7a638..ca18404 100755 --- a/bin/genhtml +++ b/bin/genhtml @@ -2430,12 +2430,15 @@ sub differential_mcdc sub _mergeFunctionData { my ($self, $loc, $functionData) = @_; + die('expected FunctionEntry found ' . ref($functionData)) + unless 'FunctionEntry' eq ref($functionData); my $function = $self->[FUNCTION_DATA]; if (defined($function->[$loc])) { my $current = $function->[$loc]; $current->merge($functionData); } else { - $function->[$loc] = Storable::dclone($functionData); + # also clone hit count data + $function->[$loc] = $functionData->cloneWithEndLine(1, 1); } } @@ -3253,10 +3256,13 @@ sub _categorizeFunctionCov my $base = $data->baseline_function(); my $categorized; if (defined($curr)) { - $categorized = $curr->cloneWithEndLine(1); # also copy the end lien + # also copy the end line + $categorized = $curr->cloneWithEndLine(1); } else { - $categorized = $base->cloneWithEndLine(0) - ; # not in current - don't copy end line + # not in current - don't copy end line + # @todo if needed, could compute where the end line of the deleted + # function is now + $categorized = $base->cloneWithEndLine(0); } my $name = $categorized->name(); $differentialMap->{$name} = $categorized; @@ -4842,8 +4848,9 @@ sub _countLineTlaData if (!exists($SummaryInfo::tlaLocation{$tla})) { # this case can happen if the line number annotations are - # wrong in the .info file - so the branch coverage line - # number turns out not to be an executable source code line + # wrong in the .info file - so the first line of some function + # or some branch coverage line number turns out not to be an + # executable source code line lcovutil::ignorable_error($lcovutil::ERROR_UNKNOWN_CATEGORY, "unexpected category $tla for line " . $self->path() . ":$line"); return; diff --git a/lib/lcovutil.pm b/lib/lcovutil.pm index 7d8401c..740fe64 100644 --- a/lib/lcovutil.pm +++ b/lib/lcovutil.pm @@ -4331,10 +4331,18 @@ sub new sub cloneWithEndLine { - my ($self, $withEnd) = @_; - return - FunctionEntry->new($self->[NAME], $self->[MAP], $self->[FIRST], - $withEnd ? $self->[LAST] : undef); + my ($self, $withEnd, $cloneAliases) = @_; + my $fn = FunctionEntry->new($self->[NAME], $self->[MAP], $self->[FIRST], + $withEnd ? $self->[LAST] : undef); + if ($cloneAliases) { + my $count = 0; + while (my ($alias, $hit) = each(%{$self->aliases()})) { + $fn->[ALIASES]->{$alias} = $hit; + $count += $hit; + } + $fn->[COUNT] = $count; + } + return $fn; } sub name @@ -6775,7 +6783,7 @@ sub data my $key = $lcovutil::case_insensitive ? lc($file) : $file; my $files = $self->[FILES]; - if (!defined($files->{$key})) { + if (!exists($files->{$key})) { if (defined $checkMatchingBasename) { # check if there is a file in the map that has the same basename # as the lone we are looking for. @@ -6802,6 +6810,13 @@ sub data return $files->{$key}; } +sub contains +{ + my ($self, $file) = @_; + my $key = $lcovutil::case_insensitive ? lc($file) : $file; + my $files = $self->[FILES]; + return exists($files->{$key}); +} sub remove { @@ -6966,8 +6981,9 @@ sub _deriveFunctionEndLines my $traceInfo = shift; my $modified = 0; - my $start = Time::HiRes::gettimeofday(); - my @lines = sort { $a <=> $b } $traceInfo->sum()->keylist(); + my $start = Time::HiRes::gettimeofday(); + my $lineData = $traceInfo->sum(); + my @lines = sort { $a <=> $b } $lineData->keylist(); # sort functions by start line number # ignore lambdas - which we don't process correctly at the moment # (would need to do syntactic search for the end line) @@ -6980,6 +6996,12 @@ sub _deriveFunctionEndLines my $func = shift(@functions); my $first = $func->line(); my $end = $func->end_line(); + #unless (defined($lineData->value($first))) { + # lcovutil::ignorable_error($lcovutil::ERROR_INCONSISTENT_DATA, + # '"' . $func->filename() . + # "\":$first: first line of function has no linecov."); + # $lineData->append($first, $func->hit()); + #} while ($first < $currentLine) { if (@lines) { $currentLine = shift @lines; @@ -7143,7 +7165,7 @@ sub _checkConsistency my $hit = $lineData->value($currentLine); $lineHit = 1 if $hit; if ($hit && !$imHit) { - # don't wan about the first line of a lambda: + # don't warn about the first line of a lambda: # - the decl may executed even if the lambda function itself is # not called # - if no other lines are hit, then then the function is not @@ -8240,6 +8262,12 @@ sub _read_info $skipCurrentFile = 1; next; } + #if ($self->contains($filename)) { + # # we expect there to be only one entry for each source file in each section + # lcovutil::ignorable_warning($lcovutil::ERROR_FORMAT, + # "Duplicate entries for \"$filename\"" + # . ($testname ? " in testcase '$testname'" : '') . '.'); + #} $filename = ReadCurrentSource::resolve_path($1, 1); # should this one be skipped? $skipCurrentFile = skipCurrentFile($filename); @@ -8272,13 +8300,10 @@ sub _read_info ($testdata, $sumcount, $funcdata, $checkdata, $testfncdata, $testbrdata, $sumbrcount, $mcdcCount, $testMcdc) = $fileData->get_info(); - $functionMap = - defined($testname) ? FunctionMap->new($filename) : $funcdata; if (defined($testname)) { - $testcount = $fileData->test($testname); - $testfnccount = $fileData->testfnc($testname); - $testbrcount = $fileData->testbr($testname); + $testcount = $fileData->test($testname); + $functionMap = $fileData->testfnc($testname); $testbrcount = $fileData->testbr($testname); $testcase_mcdc = $fileData->testcase_mcdc($testname); } else { @@ -8286,6 +8311,7 @@ sub _read_info $testfnccount = CountData->new($filename, 0); $testbrcount = BranchData->new(); $testcase_mcdc = MCDC_Data->new(); + $functionMap = FunctionMap->new($filename); } next; } diff --git a/tests/perl2lcov/perltest1.sh b/tests/perl2lcov/perltest1.sh index 657e21a..c2709aa 100755 --- a/tests/perl2lcov/perltest1.sh +++ b/tests/perl2lcov/perltest1.sh @@ -266,7 +266,8 @@ if [ 0 != $? ] ; then fi cover cover_genhtml -silent 1 -$COVER ${EXEC_COVER} $PERL2LCOV_TOOL --output genhtml.info --testname genhtml_test ./cover_genhtml +# ignore inconsistency: line hit but no branch on line is hit +$COVER ${EXEC_COVER} $PERL2LCOV_TOOL --output genhtml.info --testname genhtml_test ./cover_genhtml --ignore inconsistent if [ 0 != $? ] ; then echo "perl2lcov genhtml" if [ 0 == $KEEP_GOING ] ; then diff --git a/tests/xml2lcov/xml2lcov.sh b/tests/xml2lcov/xml2lcov.sh index ed8ea4b..4271952 100755 --- a/tests/xml2lcov/xml2lcov.sh +++ b/tests/xml2lcov/xml2lcov.sh @@ -247,7 +247,10 @@ if [ 0 == $? ] ; then fi # aggregate the files - as a syntax check -$COVER $LCOV_TOOL $LCOV_OPTS -o aggregate.info -a test.info +# the file contains inconsistent data for 'org/jasig/portal/EntityTypes.java' +# function 'mapRow' is declared twice at different locations and +# overlaps with a previous decl +$COVER $LCOV_TOOL $LCOV_OPTS -o aggregate.info -a test.info --ignore inconsistent if [ 0 != $? ] ; then echo "lcov aggregate failed" if [ 0 == $KEEP_GOING ] ; then