diff --git a/bin/genhtml b/bin/genhtml index 492cba0..f968498 100755 --- a/bin/genhtml +++ b/bin/genhtml @@ -2544,10 +2544,6 @@ sub new $diffMap, $verbose) if ($lcovutil::func_coverage); - while (my ($lineNo, $deleted) = each(%{$self->[DELETED_LINE_LEADER]})) { - @$deleted = - sort({ $a->lineNo('base') <=> $b->lineNo('base') } @$deleted); - } return $self; } @@ -2813,6 +2809,12 @@ sub _categorizeLineCov my $val = $lineCovBase->value($bline); $linedata->base_count($val); } + # walk the diff data here to mark deleted regions so we can highlight + # them in the source view + my $deletedLineData = $diffMap->compute_deleted_lines($filename); + $self->[DELETED_LINE_LEADER] = $deletedLineData + if $deletedLineData; + if ($verbose) { print(" line data map:\n"); foreach my $line (sort keys %$lineDataMap) { @@ -2946,6 +2948,7 @@ sub _categorizeBranchCov } else { # the line has been deleted...just record the data my $deleteKey = "<<<" . $base_line; + $branchCovLines{$deleteKey} = 1; } my $baseBranchData = $branchBaseline->value($base_line); $data->baseline_branch($baseBranchData, $filename); @@ -2953,7 +2956,6 @@ sub _categorizeBranchCov # go through all the branch data for each line, and categorize everything foreach my $line (keys(%branchCovLines)) { - next if ($line <= 0); # ignore bogus my $data = $self->lineMap()->{$line}; my $type = $data->type(); my $curr = $data->current_branch(); @@ -3119,6 +3121,7 @@ sub _categorizeMcdcCov } else { # the line has been deleted...just record the data my $deleteKey = "<<<" . $base_line; + $mcdcCovLines{$deleteKey} = 1; } my $baseMcdcData = $mcdcBaseline->value($base_line); $data->baseline_mcdc($baseMcdcData, $filename); @@ -3583,16 +3586,35 @@ sub recreateBaseline my $deleted = $self->[BASELINE]->{$self->findName($filename)}; my @lines; + my $didWarn = 0; foreach my $chunk (@$diffs) { if ($chunk->[TYPE] eq 'equal') { my ($from, $to) = @{$chunk->[NEW]}; - push(@lines, @{$currentSrcLines}[($from - 1) .. ($to - 1)]); + my $f = $from - 1; + my $t = $to - 1; + if ($t <= $#$currentSrcLines) { + push(@lines, @{$currentSrcLines}[$f .. $t]); + } else { + lcovutil::ignorable_error( + $lcovutil::ERROR_INCONSISTENT_DATA, + + "$filename: inconsistent diff data vs current source code: diff refers to 'current' line range [$f:$t] but source code has only " + . scalar(@$currentSrcLines) + . " lines") unless $didWarn; + $didWarn = 1; + # if error is ignored, then append up to the data we have + while ($f <= $#$currentSrcLines) { + push(@lines, $currentSrcLines->[$f++]); + } + } } elsif ($chunk->[TYPE] eq 'delete') { my $r = $chunk->[OLD]; for (my $i = $r->[_START]; $i <= $r->[_END]; ++$i) { die("missing baseline line $i") unless defined($deleted) && exists($deleted->{$i}); - push(@lines, $deleted->{$i}); + my $d = $deleted->{$i}; + die("undef deleted line $filename:$i") unless defined($d); + push(@lines, $d); } } # else 'insert': nothing to do/those lines are not in baseline @@ -3672,6 +3694,21 @@ sub type return $chunk->[TYPE]; } +sub compute_deleted_lines +{ + my ($self, $filename) = @_; + my $file = $self->findName($filename); + my $lineMap = $self->[LINEMAP]->{$file}; + return undef unless defined($lineMap); + my %hash; + foreach my $chunk (@$lineMap) { + next unless $chunk->[TYPE] eq 'delete'; + + $hash{$chunk->[NEW]->[_START]} = $chunk->[OLD]; + } + return %hash ? \%hash : undef; +} + sub baseline_file_name { # file may have been moved between baseline and current... @@ -3965,7 +4002,7 @@ sub _read_udiff } foreach ($line) { /^Git Root: (.+)$/ && do { - $self->[DIFF_ROOT] = $1; + $self->[DIFF_ROOT] = ReadCurrentSource::resolve_path($1, 1); last; }; @@ -4637,29 +4674,34 @@ sub _countBranchTlaData my %foundBranchTlas; my ($src_age, $developer, $srcLine); my $lineTla = $lineData->tla(); - $srcLine = $self->line($line); - if (!defined($srcLine)) { - lcovutil::ignorable_error($lcovutil::ERROR_UNMAPPED_LINE, + + if ($SummaryInfo::tlaLocation{$lineTla} & 0x1) { + # skip check if line was deleted - no age/owner data for deleted code + $srcLine = $self->line($line); + if (!defined($srcLine)) { + lcovutil::ignorable_error($lcovutil::ERROR_UNMAPPED_LINE, "no data for 'branch' line:$line, file:" . $self->path()) - if (!$lcovutil::warn_once_per_file || - lcovutil::warn_once($lcovutil::ERROR_UNMAPPED_LINE, $self->path())); - } else { - $srcLine->branchElem($differentialData); - if (@SourceFile::annotateScript && - !grep(/^$lineTla$/, ('DUB', 'DCB'))) { - # deleted lines don't have owner data... - # if this line is not in the project (e.g., from some 3rd party - # library - then we might not have file history for it. - $src_age = $srcLine->age(); - $developer = $srcLine->owner(); - - if (defined($developer)) { - my $shash = $self->[BRANCH_OWNERS]; - if (!exists($shash->{$developer})) { - $shash->{$developer} = {}; - $shash->{$developer}->{lines} = []; + if (!$lcovutil::warn_once_per_file || + lcovutil::warn_once($lcovutil::ERROR_UNMAPPED_LINE, + $self->path())); + } else { + $srcLine->branchElem($differentialData); + if (@SourceFile::annotateScript && + !grep(/^$lineTla$/, ('DUB', 'DCB'))) { + # deleted lines don't have owner data... + # if this line is not in the project (e.g., from some 3rd party + # library - then we might not have file history for it. + $src_age = $srcLine->age(); + $developer = $srcLine->owner(); + + if (defined($developer)) { + my $shash = $self->[BRANCH_OWNERS]; + if (!exists($shash->{$developer})) { + $shash->{$developer} = {}; + $shash->{$developer}->{lines} = []; + } + push(@{$shash->{$developer}->{lines}}, $line); } - push(@{$shash->{$developer}->{lines}}, $line); } } } @@ -4756,29 +4798,33 @@ sub _countMcdcTlaData my %foundMcdcTlas; my ($src_age, $developer, $srcLine); my $lineTla = $lineData->tla(); - $srcLine = $self->line($line); - if (!defined($srcLine)) { - lcovutil::ignorable_error($lcovutil::ERROR_UNMAPPED_LINE, + if ($SummaryInfo::tlaLocation{$lineTla} & 0x1) { + # skip check if line was deleted - no age/owner data for deleted code + $srcLine = $self->line($line); + if (!defined($srcLine)) { + lcovutil::ignorable_error($lcovutil::ERROR_UNMAPPED_LINE, "no data for 'MC/DC' line:$line, file:" . $self->path()) - if (!$lcovutil::warn_once_per_file || - lcovutil::warn_once($lcovutil::ERROR_UNMAPPED_LINE, $self->path())); - } else { - $srcLine->mcdcElem($differentialData); - if (@SourceFile::annotateScript && - !grep(/^$lineTla$/, ('DUB', 'DCB'))) { - # deleted lines don't have owner data... - # if this line is not in the project (e.g., from some 3rd party - # library - then we might not have file history for it. - $src_age = $srcLine->age(); - $developer = $srcLine->owner(); - - if (defined($developer)) { - my $shash = $self->[MCDC_OWNERS]; - if (!exists($shash->{$developer})) { - $shash->{$developer} = {}; - $shash->{$developer}->{lines} = []; + if (!$lcovutil::warn_once_per_file || + lcovutil::warn_once($lcovutil::ERROR_UNMAPPED_LINE, + $self->path())); + } else { + $srcLine->mcdcElem($differentialData); + if (@SourceFile::annotateScript && + !grep(/^$lineTla$/, ('DUB', 'DCB'))) { + # deleted lines don't have owner data... + # if this line is not in the project (e.g., from some 3rd party + # library - then we might not have file history for it. + $src_age = $srcLine->age(); + $developer = $srcLine->owner(); + + if (defined($developer)) { + my $shash = $self->[MCDC_OWNERS]; + if (!exists($shash->{$developer})) { + $shash->{$developer} = {}; + $shash->{$developer}->{lines} = []; + } + push(@{$shash->{$developer}->{lines}}, $line); } - push(@{$shash->{$developer}->{lines}}, $line); } } } @@ -11313,12 +11359,14 @@ sub write_source_line(*$$$$$$$) my $lineNumTag = 'lineNum'; my $lineNumTitle = ''; if (defined($deletedLines)) { - my $first = $deletedLines->[0]->lineNo('base'); - my $last = $deletedLines->[-1]->lineNo('base'); + my $first = $deletedLines->[0]; + my $last = $deletedLines->[1]; die("invalid deleted lines array") unless $first <= $last; + my $count = $last - $first + 1; $lineNumTitle = ' title="' . - (($first != $last) ? "removed lines [$first:$last]" : + (($first != $last) ? + "removed $count lines ([$first:$last] inclusive)" : "removed line $first") . ' from baseline version"'; $lineNumTag = 'lineNumWithDelete'; diff --git a/example/README b/example/README index 1a8f9c2..6c3facb 100644 --- a/example/README +++ b/example/README @@ -1,5 +1,13 @@ -To see some examples of LCOV generated HTML coverage reports, -and point a web browser into the resulting reports: +To see some examples of LCOV generated HTML coverage reports, run + + $ make + +in the .../examples directory, review the 'make' log and the generated +data, and then point a web browser into the resulting reports. + +The example builds with GCC by default. +You will need to make a few changes if you want to use LLVM instead. + Default view: @@ -40,7 +48,7 @@ Differential coverage: Code review: - point your browser to - exampleRepo/differential/index.html + exampleRepo/review/index.html - This example builds on the "Differential coverage" example, above to emulate a possible code review methodology in which adds code diff --git a/scripts/select.pm b/scripts/select.pm index 5d211db..1b5122e 100644 --- a/scripts/select.pm +++ b/scripts/select.pm @@ -275,11 +275,12 @@ sub save sub restore { my ($self, $data) = @_; - $self->[TOTAL] += $data->[TOTAL]; - foreach my $i (0 .. $#$data) { + $self->[TOTAL] += $data->[0]; + my $d = $data->[1]; + foreach my $i (0 .. $#$d) { my $l = $self->[COUNTS]->[$i]; foreach my $j (0 .. $#$l) { - $l->[$j] += $data->[$i]->[$j]; + $l->[$j] += $d->[$i]->[$j]; } } } diff --git a/tests/gendiffcov/simple/script.sh b/tests/gendiffcov/simple/script.sh index c2960ae..72e1151 100755 --- a/tests/gendiffcov/simple/script.sh +++ b/tests/gendiffcov/simple/script.sh @@ -654,15 +654,37 @@ for opt in "" "--show-details" "--hier"; do for o in "" $opt ; do OPTS="$TEST_OPTS $o" outdir=./differential${EXT}${o} + outFile=differential${EXT}${o}.log echo ${LCOV_HOME}/bin/genhtml $OPTS --baseline-file ./baseline.info --diff-file diff.txt --annotate-script `pwd`/annotate.sh --show-owners all --ignore-errors source -o $outdir ./current.info $IGNORE $POPUP - $COVER ${GENHTML_TOOL} $OPTS --baseline-file ./baseline.info --diff-file diff.txt --annotate-script `pwd`/annotate.sh --show-owners all --ignore-errors source -o $outdir ./current.info $GENHTML_PORT $IGNORE $POPUP - if [ 0 != $? ] ; then + $COVER ${GENHTML_TOOL} $OPTS --baseline-file ./baseline.info --diff-file diff.txt --annotate-script `pwd`/annotate.sh --show-owners all --ignore-errors source -o $outdir ./current.info $GENHTML_PORT $IGNORE $POPUP 2>&1 | tee $outFile + if [ 0 != ${PIPESTATUS[0]} ] ; then echo "ERROR: genhtml $outdir failed (2)" status=1 if [ 0 == $KEEP_GOING ] ; then exit 1 fi fi + # expect to see non-zero deleted branch count + for tla in DUB DCB ; do + grep -E branch:.+$(tla):1 $outFile + if [ 0 != $? ] ; then + echo "ERROR: did not find expected $tla branches" + status = 1 + if [ 0 != $KEEP_GOING ] ; then + exit 1 + fi + fi + if [ "$ENABLE_MCDC" == '1' ] ; then + grep -E mcdc:.+$(tla):1 $outFile + if [ 0 != $? ] ; then + echo "ERROR: did not find expected $tla branches" + status = 1 + if [ 0 != $KEEP_GOING ] ; then + exit 1 + fi + fi + fi + done if [[ $OPTS =~ "show-details" ]] ; then found=0 diff --git a/tests/gendiffcov/simple/simple.cpp b/tests/gendiffcov/simple/simple.cpp index 4e3541f..c3f1467 100644 --- a/tests/gendiffcov/simple/simple.cpp +++ b/tests/gendiffcov/simple/simple.cpp @@ -37,7 +37,7 @@ main(int ac, char ** av) #endif std::cout << " this code will be DUB" << std::endl; } - if (cond == 1) + if (1 == cond) std::cout << "cond == " << cond << "... code exercised" << std::endl;// LBC else if (cond == 2) std::cout << "cond == " << cond << "... code not exercised" << std::endl; diff --git a/tests/gendiffcov/simple/simple2.cpp.annotated b/tests/gendiffcov/simple/simple2.cpp.annotated index 37c73bc..bd74fc1 100644 --- a/tests/gendiffcov/simple/simple2.cpp.annotated +++ b/tests/gendiffcov/simple/simple2.cpp.annotated @@ -37,7 +37,7 @@ 1|henry.cox|274| std::cout << " this code will be EUB" << std::endl; 1|henry.cox|274|#endif 1|henry.cox|274| } -1|henry.cox|274| if (cond == 1) +1|henry.cox|3| if (1 == cond) 7|roderick.glossop|122| std::cout << "cond == " << cond << "... code exercised" << std::endl;// LBC 1|henry.cox|274| else if (cond == 2) 1|henry.cox|274| std::cout << "cond == " << cond << "... code exercised" << std::endl;