diff --git a/lcovrc b/lcovrc index 0e7b50ad..7a18354e 100644 --- a/lcovrc +++ b/lcovrc @@ -510,6 +510,15 @@ lcov_json_module = auto # override end of exclude region regexp #lcov_excl_stop = LCOV_EXCL_STOP +# override unreachable line default line exclusion regexp +#lcov_unreachable_line = LCOV_UNREACHABLE_LINE + +# override start of unreachable region regexp +#lcov_unreachable_start = LCOV_UNREACHABLE_START + +# override end of unreachable region regexp +#lcov_unreachable_stop = LCOV_UNREACHABLE_STOP + # override start of branch exclude region regexp #lcov_excl_br_start = LCOV_EXCL_BR_START diff --git a/lib/lcovutil.pm b/lib/lcovutil.pm index 9c44cc69..06f60eaa 100644 --- a/lib/lcovutil.pm +++ b/lib/lcovutil.pm @@ -58,6 +58,7 @@ our @EXPORT_OK = qw($tool_name $tool_dir $lcov_version $lcov_url $VERSION $EXCL_START $EXCL_STOP $EXCL_BR_START $EXCL_BR_STOP $EXCL_EXCEPTION_BR_START $EXCL_EXCEPTION_BR_STOP $EXCL_LINE $EXCL_BR_LINE $EXCL_EXCEPTION_LINE + $UNREACHABLE_START $UNREACHABLE_STOP $UNREACHABLE_LINE @exclude_file_patterns @include_file_patterns %excluded_files @omit_line_patterns @exclude_function_patterns $case_insensitive munge_file_patterns warn_file_patterns transform_pattern @@ -79,7 +80,7 @@ our @EXPORT_OK = qw($tool_name $tool_dir $lcov_version $lcov_url $VERSION $ERROR_UNSUPPORTED $ERROR_DEPRECATED $ERROR_INCONSISTENT_DATA $ERROR_CALLBACK $ERROR_RANGE $ERROR_UTILITY $ERROR_USAGE $ERROR_INTERNAL $ERROR_PARALLEL $ERROR_PARENT $ERROR_CHILD $ERROR_FORK - $ERROR_EXCESSIVE_COUNT $ERROR_MISSING + $ERROR_EXCESSIVE_COUNT $ERROR_MISSING $ERROR_UNREACHABLE report_parallel_error report_exit_status check_parent_process report_unknown_child @@ -148,6 +149,7 @@ our $ERROR_PARALLEL; # error in fork/join our $ERROR_DEPRECATED; # deprecated feature our $ERROR_CALLBACK; # callback produced an error our $ERROR_INCONSISTENT_DATA; # something wrong with .info +our $ERROR_UNREACHABLE; # coverpoint hit in "unreachable" region our $ERROR_RANGE; # line number out of range our $ERROR_UTILITY; # some tool failed - e.g., 'find' our $ERROR_USAGE; # misusing some feature @@ -189,6 +191,7 @@ my @lcovErrs = (["annotate", \$ERROR_ANNOTATE_SCRIPT], ["range", \$ERROR_RANGE], ["source", \$ERROR_SOURCE], ["unmapped", \$ERROR_UNMAPPED_LINE], + ["unreachable", \$ERROR_UNREACHABLE], ["unsupported", \$ERROR_UNSUPPORTED], ["unused", \$ERROR_UNUSED], ['usage', \$ERROR_USAGE], @@ -329,6 +332,12 @@ our @cov_filter; # 'undef' if filter is not enabled, our $EXCL_START = "LCOV_EXCL_START"; our $EXCL_STOP = "LCOV_EXCL_STOP"; +# Marker to say that this code is unreachable - so exclude from +# report, but also generate error if anything in the region is hit +our $UNREACHABLE_START = "LCOV_UNREACHABLE_START"; +our $UNREACHABLE_STOP = "LCOV_UNREACHABLE_STOP"; +our $UNREACHABLE_LINE = "LCOV_UNREACHABLE_LINE"; +our $retainUnreachableCoverpointIfHit = 1; # Marker to exclude branch coverage but keep function and line coverage our $EXCL_BR_START = "LCOV_EXCL_BR_START"; our $EXCL_BR_STOP = "LCOV_EXCL_BR_STOP"; @@ -351,6 +360,11 @@ our $trivial_function_threshold = 5; # list of regexps applied to line text - if exclude if matched our @omit_line_patterns; +# HGC: does not really make sense to support command-line '--unreachable-line +# patterns. Unreachable is typically a branch clause/structural feature - +# as opposed to an 'omit' pattern is typically trace/debug or logging code +# which may or may not be executed (and we don't care) +#our @unreachable_line_patterns; our @exclude_function_patterns; # need a pattern copy that we don't disable for function message suppressions our @suppress_function_patterns; @@ -1070,6 +1084,11 @@ my %rc_common = ( "lcov_excl_br_stop" => \$lcovutil::EXCL_BR_STOP, "lcov_excl_exception_br_start" => \$lcovutil::EXCL_EXCEPTION_BR_START, "lcov_excl_exception_br_stop" => \$lcovutil::EXCL_EXCEPTION_BR_STOP, + 'lcov_unreachable_start' => \$lcovutil::UNREACHABLE_START, + 'lcov_unreachable_stop' => \$lcovutil::UNREACHABLE_STOP, + 'lcov_unreachable_line' => \$lcovutil::UNREACHABLE_LINE, + 'retain_unreachable_coverpoints_if_executed' => + \$lcovutil::retainUnreachableCoverpointIfHit, "lcov_function_coverage" => \$lcovutil::func_coverage, "lcov_branch_coverage" => \$lcovutil::br_coverage, "ignore_errors" => \@rc_ignore, @@ -1695,7 +1714,10 @@ sub munge_file_patterns ], ["lcov_excl_exception_br_stop", \$lcovutil::EXCL_EXCEPTION_BR_STOP - ] + ], + ["lcov_unreachable_start", \$lcovutil::UNREACHABLE_START], + ["lcov_unreachable_stop", \$lcovutil::UNREACHABLE_STOP], + ["lcov_excl_line", \$lcovutil::UNREACHABLE_LINE], ) { eval 'qr/' . $regexp->[1] . '/'; my $error = $@; @@ -5450,6 +5472,13 @@ sub difference package FilterBranchExceptions; +use constant { + EXCEPTION_f => 0, + ORPHAN_f => 1, + REGION_f => 2, + BRANCH_f => 3 # branch filter +}; + sub new { my $class = shift; @@ -5464,11 +5493,15 @@ sub new sub removeBranches { - my ($self, $line, $branches, $filter, $isMasterData) = @_; + my ($self, $line, $branches, $filter, $unreachable, $isMasterData) = @_; my $brdata = $branches->value($line); return 0 unless defined($brdata); - + # 'unreachable' and 'excluded' branches have already been removed + # by 'region' filter along with their parent line - so no need to + # do anything here + die("unexpected unreachable branch") + if ($unreachable && 0 != $brdata->count()); my $modified = 0; my $count = 0; foreach my $block_id ($brdata->blocks()) { @@ -5500,14 +5533,14 @@ sub removeBranches lcovutil::info("$line: remove exception block $block_id\n"); $brdata->removeBlock($block_id, $branches); } elsif (1 == scalar(@replace) && - defined($self->[1])) { # filter orphan + defined($self->[ORPHAN_f])) { # filter orphan lcovutil::info(2, "$line: remove orphan exception block $block_id\n"); $brdata->removeBlock($block_id, $branches); - ++$self->[1]->[-2] + ++$self->[ORPHAN_f]->[-2] if $isMasterData; - ++$self->[1]->[-1]; + ++$self->[ORPHAN_f]->[-1]; } } if (0 == scalar($brdata->blocks())) { @@ -5520,12 +5553,13 @@ sub removeBranches sub applyFilter { - my ($self, $filter, $line, $branches, $perTestBranches) = @_; - my $modified = $self->removeBranches($line, $branches, $filter, 1); + my ($self, $filter, $line, $branches, $perTestBranches, $unreachable) = @_; + my $modified = + $self->removeBranches($line, $branches, $filter, $unreachable, 1); foreach my $tn ($perTestBranches->keylist()) { # want to remove matching branches everytwhere - so we don't want short-circuit evaluation my $m = $self->removeBranches($line, $perTestBranches->value($tn), - $filter, 0); + $filter, $unreachable, 0); $modified ||= $m; } return $modified; @@ -5535,22 +5569,32 @@ sub filter { my ($self, $line, $srcReader, $branches, $perTestBranches) = @_; - if ($srcReader->isExcluded($line, 4)) { + my $reason; + if (0 != ($reason = $srcReader->isExcluded($line, $srcReader->e_EXCEPTION))) + { # exception branch excluded.. - if (defined($self->[2])) { # exclude region + if (defined($self->[REGION_f])) { # exclude region + # don't filter out if this line is "unreachable" and + # some branch here is hit return - $self->applyFilter($self->[2], $line, $branches, - $perTestBranches); - } elsif (defined($self->[3])) { # exclude branches + $self->applyFilter($self->[REGION_f], + $line, + $branches, + $perTestBranches, + 0 != ($reason & $srcReader->e_UNREACHABLE)); + } elsif (defined($self->[BRANCH_f])) { # exclude branches + # filter out bogus branches - even if this region is unreachable return - $self->applyFilter($self->[3], $line, $branches, - $perTestBranches); + $self->applyFilter($self->[BRANCH_f], $line, $branches, + $perTestBranches, 0); } } # apply if filtering exceptions, orphans, or both - if (defined($self->[0]) || defined($self->[1])) { - return $self->applyFilter($self->[0], $line, $branches, - $perTestBranches); + if (defined($self->[EXCEPTION_f]) || defined($self->[ORPHAN_f])) { + # filter exceptions and orphans - even if the region is "unreachable" + return + $self->applyFilter($self->[EXCEPTION_f], $line, $branches, + $perTestBranches, 0); } return 0; } @@ -5961,6 +6005,12 @@ use constant { EXCLUDE_BRANCH_REGION => 0x20, EXCLUDE_DIRECTIVE => 0x40, OMIT_LINE => 0x80, + + # recorded exclusion markers + e_LINE => 0x1, + e_BRANCH => 0x2, + e_EXCEPTION => 0x4, + e_UNREACHABLE => 0x8, }; sub new @@ -6053,16 +6103,19 @@ sub parseLines my $exclude_region; my $exclude_br_region; my $exclude_exception_region; - my $line = 0; - my $excl_start = qr($lcovutil::EXCL_START); - my $excl_stop = qr($lcovutil::EXCL_STOP); - my $excl_line = qr($lcovutil::EXCL_LINE); - my $excl_br_start = qr($lcovutil::EXCL_BR_START); - my $excl_br_stop = qr($lcovutil::EXCL_BR_STOP); - my $excl_br_line = qr($lcovutil::EXCL_BR_LINE); - my $excl_ex_start = qr($lcovutil::EXCL_EXCEPTION_BR_START); - my $excl_ex_stop = qr($lcovutil::EXCL_EXCEPTION_BR_STOP); - my $excl_ex_line = qr($lcovutil::EXCL_EXCEPTION_LINE); + my $line = 0; + my $excl_start = qr(\b$lcovutil::EXCL_START\b); + my $excl_stop = qr(\b$lcovutil::EXCL_STOP\b); + my $excl_line = qr(\b$lcovutil::EXCL_LINE\b); + my $excl_br_start = qr(\b$lcovutil::EXCL_BR_START\b); + my $excl_br_stop = qr(\b$lcovutil::EXCL_BR_STOP\b); + my $excl_br_line = qr(\b$lcovutil::EXCL_BR_LINE\b); + my $excl_ex_start = qr(\b$lcovutil::EXCL_EXCEPTION_BR_START\b); + my $excl_ex_stop = qr(\b$lcovutil::EXCL_EXCEPTION_BR_STOP\b); + my $excl_ex_line = qr(\b$lcovutil::EXCL_EXCEPTION_LINE\b); + my $unreachable_start = qr(\b$lcovutil::UNREACHABLE_START\b); + my $unreachable_stop = qr(\b$lcovutil::UNREACHABLE_STOP\b); + my $unreachable_line = qr(\b$lcovutil::UNREACHABLE_LINE\b); # @todo: if we had annotated data here, then we could whine at the # author of the unmatched start, extra end, etc. @@ -6075,23 +6128,29 @@ sub parseLines if (defined($lcovutil::cov_filter[$lcovutil::FILTER_EXCLUDE_REGION])) { push(@excludes, [$excl_start, $excl_stop, - \$exclude_region, 3 | EXCLUDE_REGION, + \$exclude_region, e_LINE | e_BRANCH | EXCLUDE_REGION, $lcovutil::EXCL_START, $lcovutil::EXCL_STOP ]); + push(@excludes, + [$unreachable_start, $unreachable_stop, + \$exclude_region, e_UNREACHABLE | EXCLUDE_REGION, + $lcovutil::UNREACHABLE_START, $lcovutil::UNREACHABLE_STOP + ]); } else { - $excl_line = undef; + $excl_line = undef; + $unreachable_line = undef; } if (defined($lcovutil::cov_filter[$lcovutil::FILTER_EXCLUDE_BRANCH])) { push(@excludes, [$excl_ex_start, $excl_ex_stop, - \$exclude_exception_region, 4 | EXCLUDE_BRANCH_REGION, + \$exclude_exception_region, e_EXCEPTION | EXCLUDE_BRANCH_REGION, $lcovutil::EXCL_BR_START, $lcovutil::EXCL_BR_STOP, ], [$excl_br_start, $excl_br_stop, \$exclude_br_region, - 2 | EXCLUDE_BRANCH_REGION, + e_BRANCH | EXCLUDE_BRANCH_REGION, $lcovutil::EXCL_EXCEPTION_BR_START, $lcovutil::EXCL_EXCEPTION_BR_STOP, ]); @@ -6108,13 +6167,15 @@ sub parseLines s/\r//; # remove carriage return if (defined($exclude_directives) && $_ =~ $exclude_directives) { - push(@excluded, 3 | EXCLUDE_DIRECTIVE); #everything excluded + # line contains compiler directive - exclude everything + push(@excluded, e_LINE | e_BRANCH | EXCLUDE_DIRECTIVE); lcovutil::info(2, "directive '#$1' on $filename:$line\n"); next; } foreach my $d (@excludes) { - # note: $d->[4] is the 'start' string (not converted to perl regexp) + # note: $d->[3] is the exclude reason (mask) + # $d->[4] is the 'start' string (not converted to perl regexp) # $d->[5] is the 'stop' string my ($start, $stop, $ref, $reason) = @$d; if ($_ =~ $start) { @@ -6124,33 +6185,42 @@ sub parseLines " at line $line - but no matching " . $d->[5] . ' for ' . $d->[4] . ' at line ' . $$ref->[0]) if $$ref; - $$ref = [$line, $reason]; + $$ref = [$line, $reason, $d->[4], $d->[5]]; last; } elsif ($_ =~ $stop) { lcovutil::ignorable_error($lcovutil::ERROR_MISMATCH, "$filename: found " . $d->[5] . " directive at line $line without matching " . - $d->[4] . ' directive') - unless $$ref; + ($$ref ? $$ref->[2] : $d->[4]) . ' directive') + unless $$ref && + $$ref->[2] eq $d->[4] && + $$ref->[3] eq $d->[5]; $$ref = undef; last; } } if (defined($excl_line) && $_ =~ $excl_line) { - push(@excluded, 3 | EXCLUDE_REGION); #everything excluded + push(@excluded, e_LINE | e_BRANCH | EXCLUDE_REGION) + ; #everything excluded + next; + } elsif (defined($unreachable_line) && + $_ =~ $unreachable_line) { + push(@excluded, e_UNREACHABLE | EXCLUDE_REGION) + ; #everything excluded next; } elsif (defined($excl_br_line) && $_ =~ $excl_br_line) { - $exclude_branch_line = 2 | EXCLUDE_BRANCH_REGION; + $exclude_branch_line = e_BRANCH | EXCLUDE_BRANCH_REGION; } elsif (defined($excl_ex_line) && $_ =~ $excl_ex_line) { - $exclude_branch_line = 4 | EXCLUDE_BRANCH_REGION; + $exclude_branch_line = e_EXCEPTION | EXCLUDE_BRANCH_REGION; } elsif (0 != scalar(@lcovutil::omit_line_patterns)) { foreach my $p (@lcovutil::omit_line_patterns) { my $pat = $p->[0]; if ($_ =~ $pat) { - push(@excluded, 3 | OMIT_LINE); #everything excluded + push(@excluded, e_LINE | e_BRANCH | OMIT_LINE) + ; #everything excluded #lcovutil::info("'" . $p->[-2] . "' matched \"$_\", line \"$filename\":"$line\n"); ++$p->[-1]; next LINES; @@ -6163,9 +6233,20 @@ sub parseLines $exclude_exception_region ? $exclude_exception_region->[1] : 0 ) | $exclude_branch_line | $exclude_exception_branch_line); } - foreach my $t ([$exclude_region, $lcovutil::EXCL_START, - $lcovutil::EXCL_STOP - ], + my @dangling; + if ($exclude_region) { + if ($exclude_region->[1] & e_UNREACHABLE) { + push(@dangling, + [$exclude_region, $lcovutil::UNREACHABLE_START, + $lcovutil::UNREACHABLE_STOP + ]); + } else { + push(@dangling, + [$exclude_region, $lcovutil::EXCL_START, $lcovutil::EXCL_STOP] + ); + } + } + foreach my $t (@dangling, [$exclude_br_region, $lcovutil::EXCL_BR_START, $lcovutil::EXCL_BR_STOP ], @@ -6305,13 +6386,24 @@ sub excludeReason sub isExcluded { - my ($self, $lineNo, $branch) = @_; + # returns: the value of the matched flags + # - non-zero if the line is excluded (in an excluded or unreachable + # region), or if '$flags" is set and the exclusion reason includes + # at least one of the flags. + # - The latter condition is used to check for branch-only or execption- + # only exclusions, as well as to check whether this line is + # unreachable (as opposed to excluded). + my ($self, $lineNo, $flags, $skipRangeCheck) = @_; my $data = $self->[0]; - if (!defined($data->[EXCLUDE]) || - scalar(@{$data->[EXCLUDE]}) < $lineNo) { + if (!defined($data->[EXCLUDE]) || scalar(@{$data->[EXCLUDE]}) < $lineNo) { # this can happen due to version mismatches: data extracted with # version N of the file, then generating HTML with version M # "--version-script callback" option can be used to detect this + + # if we are just checking whether this line in in an unreachable region, + # then don't check for out-of-range (that check happens later) + return 0 + if $skipRangeCheck; my $key = $self->filename(); $key .= $lineNo unless ($lcovutil::warn_once_per_file); my $suffix = lcovutil::explain_once( @@ -6333,10 +6425,12 @@ sub isExcluded $suffix) if lcovutil::warn_once($lcovutil::ERROR_RANGE, $key); return 0; # even though out of range - this is not excluded by filter } - return 1 - if ($branch && - 0 != ($data->[EXCLUDE]->[$lineNo - 1] & $branch)); - return 0 != ($data->[EXCLUDE]->[$lineNo - 1] & 1); + my $reason; + if ($flags && + 0 != ($reason = ($data->[EXCLUDE]->[$lineNo - 1] & $flags))) { + return $reason; + } + return $data->[EXCLUDE]->[$lineNo - 1] & (e_LINE | e_UNREACHABLE); } sub removeComments @@ -7036,6 +7130,25 @@ sub _eraseFunctions } # if match } # foreach alias } # foreach pattern + # warn if the function is in an unreachable region but is hit - + # easiest to check here so we emit only one message per function + my $line; + my $reason; + if ($srcReader && + 0 != ($reason = + $srcReader->isExcluded(($line = $fcn->line()), + $srcReader->e_UNREACHABLE, 1)) && + 0 != ($reason & $srcReader->e_UNREACHABLE) && + 0 != $fcn->hit() + ) { + + lcovutil::ignorable_error($lcovutil::ERROR_UNREACHABLE, + "\"$source_file\":$line: function $name is executed but was marked unreachable." + ); + next + if $lcovutil::retainUnreachableCoverpointIfHit; + } + } # foreach function return $modified; } @@ -7465,7 +7578,8 @@ sub _filterFile if (defined($lcovutil::func_coverage) && (0 != scalar(@lcovutil::exclude_function_patterns) || - defined($trivial_histogram)) + defined($trivial_histogram) || + defined($region)) ) { # filter excluded function line ranges my $funcData = $traceInfo->testfnc(); @@ -7473,7 +7587,7 @@ sub _filterFile my $branchData = $traceInfo->testbr(); my $mcdcData = $traceInfo->testcase_mcdc(); my $checkData = $traceInfo->check(); - my $reader = defined($trivial_histogram) && + my $reader = (defined($trivial_histogram) || defined($region)) && $srcReader->notEmpty() ? $srcReader : undef; foreach my $tn ($lineData->keylist()) { @@ -7509,6 +7623,7 @@ sub _filterFile my $testbrcount = $testbrdata->value($testname); my $mcdc_count = $testmcdc->value($testname); + my $reason; my $functionMap = $testfncdata->{$testname}; if ($lcovutil::func_coverage && $functionMap && @@ -7526,12 +7641,18 @@ sub _filterFile "filter FN " . $data->name() . ' ' . $data->file() . ":$line\n"); ++$range->[-2]; # one location where this applied - } elsif ($srcReader->isExcluded($line)) { + } elsif (0 != ($reason = $srcReader->isExcluded($line))) { + # we already warned about this one + next + if (0 != ($reason & $srcReader->e_UNREACHABLE) && + 0 != $data->hit() && + $lcovutil::retainUnreachableCoverpointIfHit); + $remove = 1; - my $reason = $srcReader->excludeReason($line); + my $r = $srcReader->excludeReason($line); foreach my $f ([ReadCurrentSource::EXCLUDE_REGION, $region], [ReadCurrentSource::OMIT_LINE, $omit]) { - if ($reason & $f->[0]) { + if ($r & $f->[0]) { $f->[1]->[-2] += scalar(keys %{$data->aliases()}); last; } @@ -7578,9 +7699,14 @@ sub _filterFile # only counting line coverpoints that got excluded die("inconsistent state") unless $range; $remove = $range; - } elsif ($srcReader->isExcluded($line, 2)) { + } elsif ( + 0 != ( + $reason = + $srcReader->isExcluded($line, $srcReader->e_BRANCH) + ) + ) { # all branches here - my $reason = $srcReader->excludeReason($line); + my $r = $srcReader->excludeReason($line); foreach my $f ([ReadCurrentSource::EXCLUDE_REGION, $region], [ReadCurrentSource::OMIT_LINE, $omit], [ReadCurrentSource::EXCLUDE_DIRECTIVE, @@ -7590,7 +7716,7 @@ sub _filterFile $branch_region ] ) { - if ($reason & $f->[0]) { + if ($r & $f->[0]) { $remove = $f->[1]; last; } @@ -7608,6 +7734,17 @@ sub _filterFile my $brdata = $sumCount->value($line); # might not be MCDC here, even if there is a branch next unless $brdata; + + if ($reason && + 0 != ($reason & $srcReader->e_UNREACHABLE) && + 0 != ($brdata->totals())[1]) { + lcovutil::ignorable_error( + $lcovutil::ERROR_UNREACHABLE, + "\"$source_file\":$line: $str record in 'unreachable' region has non-zero hit count." + ); + next + if $lcovutil::retainUnreachableCoverpointIfHit; + } ++$remove->[-2]; # one line where we skip $remove->[-1] += ($brdata->totals())[0]; lcovutil::info(2, @@ -7651,6 +7788,7 @@ sub _filterFile ++$mcdc_single->[-2]; # one MC/DC skipped $mcdc->remove($line); # remove at top + $modified = 1; } } } @@ -7666,6 +7804,23 @@ sub _filterFile # Line related data my %initializerListRange; foreach my $line ($testcount->keylist()) { + + # warn about inconsistency if executed line is marked unreachable + my $l_hit = $testcount->value($line); + if ($l_hit && + 0 != ($reason = + $srcReader->isExcluded( + $line, $srcReader->e_UNREACHABLE, 1 + )) && + 0 != ($reason & $srcReader->e_UNREACHABLE) + ) { + lcovutil::ignorable_error($lcovutil::ERROR_UNREACHABLE, + "\"$source_file\":$line: 'unreachable' line has non-zero hit count." + ); + next + if $lcovutil::retainUnreachableCoverpointIfHit; + } + # don't suppresss if this line has associated branch or MC/DC data next if ( @@ -7718,7 +7873,6 @@ sub _filterFile } } } - my $l_hit = $testcount->value($line); my $isCloseBrace = ($brace_histogram && $srcReader->suppressCloseBrace($line, $l_hit, $testcount)) diff --git a/man/genhtml.1 b/man/genhtml.1 index ce7e1d20..d0bd1582 100644 --- a/man/genhtml.1 +++ b/man/genhtml.1 @@ -2301,12 +2301,12 @@ Ignore line and branch coverpoints on lines which are out-of range/whose line nu .PP .IP region: 3 -apply LCOV_EXCL_START/LCOV_EXCL_STOP directives found in source text to the coverpoints found in the current and baseline .info files. +apply LCOV_EXCL_START/LCOV_EXCL_STOP/LCOV_EXCL_LINE and LCOV_UNREACHABLE_START/LCOV_UNREACHABLE_STOP/LCOV_UNREACHABLE_LINE directives found in source text to the coverpoints found in the current and baseline .info files. This option may be useful in cases that the source code was not found during 'lcov \-\-capture ...' but is accessible now. .PP .IP branch_region: 3 -apply LCOV_EXCL_BR_START/LCOV_EXCL_BR_STOP directives found in source text to the coverpoints found in the current and baseline .info files. +apply LCOV_EXCL_BR_START/LCOV_EXCL_BR_STOP/LCOV_EXCL_BR_LINE directives found in source text to the coverpoints found in the current and baseline .info files. This is similar to the 'region option, above - but applies to branch coverpoints only. .PP @@ -3130,6 +3130,20 @@ Coverage data for a particular line cannot be found, possibly because the source This can happen if the source file used in HTML generation is not the same as the file used to generate the coverage data - for example, lines have been added or removed. .PP +.IP unreachable: 3 +a coverpoint (line, branch, function, or MC/DC) within an "unreachable" region is executed (hit); either the code, directive placement, or both are wrong. +If the error is ignored, the offending coverpoint is retained (not excluded) or not, depending on the value of the +.I retain_unreachable_coverpoints_if_executed +configuration parameter. +See man +.B lcovrc(5) +and the +.I "Exclusion markers" +section of man +.B geninfo(1) +for more information. +.PP + .IP unsupported: 3 The requested feature is not supported for this tool configuration. For example, function begin/end line range exclusions use some GCOV features that are not available in older GCC releases. .PP diff --git a/man/geninfo.1 b/man/geninfo.1 index 699ed186..c88d8b24 100644 --- a/man/geninfo.1 +++ b/man/geninfo.1 @@ -233,13 +233,29 @@ man page for more information on .gcda, .gcno and .gcov output formats. .SS "Exclusion markers" To exclude specific lines of code from a tracefile, you can add exclusion -markers to the source code. Additionally you can exclude specific branches from -branch coverage without excluding the involved lines from line and function -coverage. Exclusion markers are keywords which can for example be added in the +markers to the source code. Similarly, you can mark specific regions of code +as "unreachable". An "unreachable" error message is generated if any +coverpoints in unreachable regions are executed ( +.I i.e., +have non-zero hit counts. +See the +.I retain_unreachable_coverpoints_if_executed +section in man +.B lcovrc(1) +for a description of the actions taken in this case. + +Additionally you can exclude specific branches or MC/DC expressions from +without excluding the involved lines from line and function +coverage. + + Exclusion markers are keywords which can for example be added in the form of a comment. See man .BR lcovrc (5) -how to override some of them. +how to override the exclusion keywords ( +.I e.g., +to reuse markers inserted for other tools or to generate reports with different +sets of excluded regions). The following markers are recognized by geninfo: @@ -266,6 +282,34 @@ section. .br .RE +.B LCOV_UNREACHABLE_LINE +.br +.RS +If the marked line is 'hit', then generate an error: we believe the marked code +is unreachable and so there is a bug in the code, the plaement of the directive, or both. +Lines containing this marker will be excluded from reporting. +.br +Apart from error reporting, this directive is equivalent to +.I LCOV_EXCL_LINE. +.RE + +.B LCOV_UNREACHABLE_START +.br +.RS +Marks the beginning of an unreachable section of code. The current line in part of this region. +.br +As described in the +.I LCOV_UNREACHABLE_LINE +section, above: an error is generated if any code in the region is hit, but the code is excluded from reporting. +.RE + +.B LCOV_UNREACHABLE_STOP +.br +.RS +Marks the end of the region of unreachable code. The current line not part of this +section. +.RE + .B LCOV_EXCL_BR_LINE .br .RS @@ -319,7 +363,9 @@ The current line not part of this section In general, (almost) all .B geninfo options can also be specified in your personal, group, project, or site -configuration file - see man +configuration file - see the +.I \-\-config\-file +section, below, and man .B lcovrc(5) for details. @@ -1013,7 +1059,19 @@ data. .IP source: 3 the source code file for a data set could not be found. .PP -`< + +.IP unreachable: 3 +a coverpoint (line, branch, function, or MC/DC) within an "unreachable" region is executed (hit); either the code, directive placement, or both are wrong. +If the error is ignored, the offending coverpoint is retained (not excluded) or not, depending on the value of the +.I retain_unreachable_coverpoints_if_executed +configuration parameter. +See man +.B lcovrc(5) +and the +.I "Exclusion markers" +section, above. +.PP + .IP unsupported: 3 the requested feature is not supported for this tool configuration. For example, function begin/end line range exclusions use some GCOV features that are not available in older GCC releases. .PP diff --git a/man/lcov.1 b/man/lcov.1 index 208ee223..6838d0a5 100644 --- a/man/lcov.1 +++ b/man/lcov.1 @@ -1445,6 +1445,20 @@ data. the source code file for a data set could not be found. .PP +.IP unreachable: 3 +a coverpoint (line, branch, function, or MC/DC) within an "unreachable" region is executed (hit); either the code, directive placement, or both are wrong. +If the error is ignored, the offending coverpoint is retained (not excluded) or not, depending on the value of the +.I retain_unreachable_coverpoints_if_executed +configuration parameter. +See man +.B lcovrc(5) +and the +.I "Exclusion markers" +section of man +.B geninfo(1) +for more information. +.PP + .IP unsupported: 3 the requested feature is not supported for this tool configuration. For example, function begin/end line range exclusions use some GCOV features that are not available in older GCC releases. .PP diff --git a/man/lcovrc.5 b/man/lcovrc.5 index bafb8ce4..015a140a 100644 --- a/man/lcovrc.5 +++ b/man/lcovrc.5 @@ -714,6 +714,24 @@ maximum during parallel processing. #lcov_excl_stop = LCOV_EXCL_STOP .br +.br +# override unreachable line default line exclusion regexp +.br +#lcov_unreachable_line = LCOV_UNREACHABLE_LINE +.br +.br +# override start of unreachable region regexp +.br +#lcov_unreachable_start = LCOV_UNREACHABLE_START +.br + +.br +# override end of unreachable region regexp +.br +#lcov_unreachable_stop = LCOV_UNREACHABLE_STOP +.br + + .br # override start of branch exclude region regexp .br @@ -2551,6 +2569,37 @@ Specify the regexp used to mark the end of a region where exception-related bran Default is 'LCOV_EXCL_EXECEPTION_BR_STOP'. +.BR lcov_unreachable_line " =" +.I expression +.IP +Specify the regular expression of unreachable line which should be excluded from reporting, but should generate an "inconsistent" error if hit. +That is: we believe that the marked code is unreachable, so there is a bug in the code, the placement of the directive, or both if the "unreachable" code is executed. +Line, branch, and function coverpoints are associated with lines where this regexp is found are dropped. +.br + +Default is 'LCOV_UNREACHABLE_LINE'. +.PP + +.BR lcov_unreachable_start " =" +.IR expression +.IP +Specify the regexp mark the start of an unreachable code block. +All coverpoints within exception regions are dropped, but the tool will generate +an "inconsistent" error if any code in the block is executed. +.br + +Default is 'LCOV_UNREACHABLE_START'. + +.PP + +.BR lcov_unreachable_stop " =" +.IR expression +.IP +Specify the regexp mark the end of the unreachable code block. +.br + +Default is 'LCOV_UNREACHABLE_STOP'. + .PP .BR fail_under_branches " =" @@ -2565,7 +2614,21 @@ for more detailes. .br The default is 0 (no threshold). +.PP + +.BR retain_unreachable_coverpoints_if_executed " =" +.I [0 | 1] +.IP +Specify whether coverpoints in "unreachable" regions which are 'hit' are +dropped (0) - because the region is excluded - or retained (1) - because +the directive appears to be incorrect. +.br +See the "Exclusion markers" section in man +.B geninfo(1) +for more details. + +The default is 1 (retain the coverpoints). .PP .BR fail_under_lines " =" diff --git a/tests/lcov/exception/exception.sh b/tests/lcov/exception/exception.sh index bd03f815..d1c52441 100755 --- a/tests/lcov/exception/exception.sh +++ b/tests/lcov/exception/exception.sh @@ -48,6 +48,24 @@ if [ $NO_INITIAL_CAPTURE != $? ] ; then fi fi +# enable branch filter without line/region filter - to hit some additional code +$COVER $CAPTURE $LCOV_OPTS --initial -o initial_br.info $IGNORE_EMPTY $IGNORE_USAGE --filter branch_region +if [ $NO_INITIAL_CAPTURE != $? ] ; then + echo "Error: unexpected error code from lcov --initial" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi +for info in initial.info initial_br.info ; do + grep 'BRDA:8,e0' $info + if [ 0 == $? ] ; then + echo "Error: exception branch should be filtered out of $info" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi + fi +done + ./a.out if [ 0 != $? ] ; then echo "Error: unexpected error return from a.out" diff --git a/tests/lcov/extract/extract.cpp b/tests/lcov/extract/extract.cpp index 482668fb..d2c5fb72 100644 --- a/tests/lcov/extract/extract.cpp +++ b/tests/lcov/extract/extract.cpp @@ -3,7 +3,7 @@ #include #include -int main(int argc, const char *argv[]) +int main(int argc, const char *argv[]) // TEST_UNREACH_FUNCTION { bool b = false; if (strcmp(argv[1], "1") == 0) @@ -18,17 +18,19 @@ int main(int argc, const char *argv[]) // TEST_OVERLAP_START // TEST_OVERLAP_START + // TEST_UNREACHABLE_START std::string str("asdads"); + // TEST_UNREACHABLE_END str = "cd"; // TEST_OVERLAP_END //TEST_DANGLING_START //TEST_UNMATCHED_END - std::cout << str << std::endl; + std::cout << str << std::endl; // TEST_UNREACHABLE_LINE - // LCOV_EXCL_START + // LCOV_EXCL_START_1 std::cout << "adding some code to ignore" << std::endl; - // LCOV_EXCL_STOP + // LCOV_EXCL_STOP_1 return 0; } diff --git a/tests/lcov/extract/extract.sh b/tests/lcov/extract/extract.sh index dfa1cc2f..fe61beb5 100755 --- a/tests/lcov/extract/extract.sh +++ b/tests/lcov/extract/extract.sh @@ -63,7 +63,7 @@ if [ "${VER[0]}" -lt 8 ] ; then DERIVE_END='--rc derive_function_end_line=0' fi -if [ 1 != $NO_INITIAL_CAPTURE ] ; then +if [ 1 != "$NO_INITIAL_CAPTURE" ] ; then $COVER $CAPTURE . $LCOV_OPTS --initial -o initial.info $IGNORE_EMPTY $IGNORE_USAGE if [ 0 != $? ] ; then echo "Error: unexpected error code from lcov --initial" @@ -299,10 +299,19 @@ if [ 0 != $? ] ; then fi fi +# applying EXCLUDE directive - so we can test both EXCLUDE and UNREACHABLE +# without changing the test much +#CAPTURE="$GENINFO_TOOL --rc lcov_excl_start=LCOV_EXCL_START_1 --rc lcov_excl_stop=LCOV_EXCL_STOP_1" -$COVER $CAPTURE . $LCOV_OPTS --no-external -o internal.info +$COVER $CAPTURE . $LCOV_OPTS --no-external -o internal.info --rc lcov_excl_start=LCOV_EXCL_START_1 --rc lcov_excl_stop=LCOV_EXCL_STOP_1 +if [ 0 != $? ] ; then + echo "Error: unexpected error from capture-internal" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi -# substiture PWD so the test isn't dependent on directory layout. +# substitute PWD so the test isn't dependent on directory layout. # quiet, to suppress core count and (empty) message summary $COVER $LCOV_TOOL $LCOV_OPTS --list internal.info --subst "s#$PWD#.#" -q -q --filter function > list.dat @@ -329,7 +338,7 @@ fi INITIAL_COUNT=`grep -c BRDA internal.info` # capture again, using --all - should pick up 'unused.c' -$COVER $CAPTURE . $LCOV_OPTS --all -o all_internal.info --no-external $FILTER $IGNORE +$COVER $CAPTURE . $LCOV_OPTS --all -o all_internal.info --no-external $FILTER $IGNORE --rc lcov_excl_start=LCOV_EXCL_START_1 --rc lcov_excl_stop=LCOV_EXCL_STOP_1 if [ 0 != $? ] ; then echo "Error: unexpected error code from lcov --capture --all" if [ $KEEP_GOING == 0 ] ; then @@ -433,7 +442,7 @@ fi # workaround: depending on compiler version, we see a coverpoint on the # close brace line (gcc/6 for example) or we don't (gcc/10 for example) -BRACE_LINE='^DA:34' +BRACE_LINE='^DA:36' MARKER_LINES=`grep -v $BRACE_LINE internal.info | grep -c "^DA:"` # check 'no-markers': is the excluded line back? @@ -453,70 +462,73 @@ if [ $NOMARKER_LINES != '13' ] ; then fi fi -# override excl region start/stop and look for error -$COVER $CAPTURE . $LCOV_OPTS --no-external -o regionErr1.info --rc lcov_excl_start=TEST_OVERLAP_START --rc lcov_excl_stop=TEST_OVERLAP_END --msg-log -if [ $? == 0 ] ; then - echo "error expected overlap fail" - if [ $KEEP_GOING == 0 ] ; then - exit 1 +# check overlap detection for both exclude and unreachable attributes +for attrib in "excl" "unreachable" ; do + # override excl region start/stop and look for error + $COVER $CAPTURE . $LCOV_OPTS --no-external -o regionErr1.info --rc lcov_${attrib}_start=TEST_OVERLAP_START --rc lcov_${attrib}_stop=TEST_OVERLAP_END --msg-log + if [ $? == 0 ] ; then + echo "error expected overlap $attrib fail" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi fi -fi -grep -E 'overlapping exclude directives. Found TEST_OVERLAP_START at .+ but no matching TEST_OVERLAP_END for TEST_OVERLAP_START at line ' regionErr1.msg -if [ 0 != $? ] ; then - echo "error expected overlap message but didn't find" - if [ $KEEP_GOING == 0 ] ; then - exit 1 + grep -E 'overlapping exclude directives. Found TEST_OVERLAP_START at .+ but no matching TEST_OVERLAP_END for TEST_OVERLAP_START at line ' regionErr1.msg + if [ 0 != $? ] ; then + echo "error expected overlap message but didn't find" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi fi -fi -$COVER $CAPTURE . $LCOV_OPTS --no-external -o regionErr2.info --rc lcov_excl_start=TEST_DANGLING_START --rc lcov_excl_stop=TEST_DANGLING_END --msg-log -if [ $? == 0 ] ; then - echo "error expected dangling fail" - if [ $KEEP_GOING == 0 ] ; then - exit 1 + $COVER $CAPTURE . $LCOV_OPTS --no-external -o regionErr2.info --rc lcov_${attrib}_start=TEST_DANGLING_START --rc lcov_${attrib}_stop=TEST_DANGLING_END --msg-log + if [ $? == 0 ] ; then + echo "error expected dangling fail" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi fi -fi -grep -E 'unmatched TEST_DANGLING_START at line .+ saw EOF while looking for matching TEST_DANGLING_END' regionErr2.msg -if [ 0 != $? ] ; then - echo "error expected dangling message but didn't find" - if [ $KEEP_GOING == 0 ] ; then - exit 1 + grep -E 'unmatched TEST_DANGLING_START at line .+ saw EOF while looking for matching TEST_DANGLING_END' regionErr2.msg + if [ 0 != $? ] ; then + echo "error expected dangling message but didn't find" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi fi -fi -$COVER $CAPTURE . $LCOV_OPTS --no-external -o regionErr3.info --rc lcov_excl_start=TEST_UNMATCHED_START --rc lcov_excl_stop=TEST_UNMATCHED_END --msg-log -if [ $? == 0 ] ; then - echo "error expected unmatched fail" - if [ $KEEP_GOING == 0 ] ; then - exit 1 + $COVER $CAPTURE . $LCOV_OPTS --no-external -o regionErr3.info --rc lcov_${attrib}_start=TEST_UNMATCHED_START --rc lcov_${attrib}_stop=TEST_UNMATCHED_END --msg-log + if [ $? == 0 ] ; then + echo "error expected unmatched fail" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi fi -fi -grep -E 'found TEST_UNMATCHED_END directive at line .+ without matching TEST_UNMATCHED_START' regionErr3.msg -if [ 0 != $? ] ; then - echo "error expected unmapted message but didn't find" - if [ $KEEP_GOING == 0 ] ; then - exit 1 + grep -E 'found TEST_UNMATCHED_END directive at line .+ without matching TEST_UNMATCHED_START' regionErr3.msg + if [ 0 != $? ] ; then + echo "error expected unmapted message but didn't find" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi fi -fi -# override excl_line start/stop - and make sure we didn't match -$COVER $CAPTURE . $LCOV_OPTS --no-external -o excl.info --rc lcov_excl_start=nomatch_start --rc lcov_excl_stop=nomatch_end -if [ $? != 0 ] ; then - echo "error return from marker override" - if [ $KEEP_GOING == 0 ] ; then - exit 1 + # override excl_line start/stop - and make sure we didn't match + $COVER $CAPTURE . $LCOV_OPTS --no-external -o ${attrib}.info --rc lcov_${attrib}_start=nomatch_start --rc lcov_${attrib}_stop=nomatch_end + if [ $? != 0 ] ; then + echo "error return from marker override" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi fi -fi -EXCL_LINES=`grep -v $BRACE_LINE excl.info | grep -c "^DA:"` -if [ $EXCL_LINES != $NOMARKER_LINES ] ; then - echo "did not honor marker override: expected $NOMARKER_LINES found $EXCL_LINES" - if [ $KEEP_GOING == 0 ] ; then - exit 1 + EXCL_LINES=`grep -v $BRACE_LINE ${attrib}.info | grep -c "^DA:"` + if [ $EXCL_LINES != $NOMARKER_LINES ] ; then + echo "did not honor marker override: expected $NOMARKER_LINES found $EXCL_LINES" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi fi -fi +done # override excl_br line start/stop - and make sure we match match $COVER $CAPTURE . $LCOV_OPTS --no-external -o exclbr.info --rc lcov_excl_br_start=TEST_BRANCH_START --rc lcov_excl_br_stop=TEST_BRANCH_STOP @@ -553,7 +565,7 @@ if [ $EXCL_LINE_BRANCHES != $EXCL_BRANCHES ] ; then fi # check to see if "--omit-lines" works properly... -$COVER $CAPTURE . $LCOV_OPTS --no-external --omit-lines '\s+std::string str.+' -o omit.info 2>&1 | tee omitLines.log +$COVER $CAPTURE . $LCOV_OPTS --no-external --omit-lines '\s+std::string str.+' -o omit.info --rc lcov_excl_start=LCOV_EXCL_START_1 --rc lcov_excl_stop=LCOV_EXCL_STOP_1 2>&1 | tee omitLines.log if [ 0 != ${PIPESTATUS[0]} ] ; then echo "Error: unexpected error code from lcov --omit" @@ -562,7 +574,7 @@ if [ 0 != ${PIPESTATUS[0]} ] ; then fi fi -BRACE_LINE="DA:34" +BRACE_LINE="DA:36" # a bit of a hack: gcc/10 doesn't put a DA entry on the closing brace COUNT=`grep -v $BRACE_LINE omit.info | grep -c ^DA:` if [ $COUNT != '11' ] ; then @@ -580,7 +592,7 @@ if [ 0 == $? ] ; then fi fi -$COVER $CAPTURE . $LCOV_OPTS --no-external --omit-lines 'xyz\s+std::string str.+' -o omitWarn.info --ignore unused +$COVER $CAPTURE . $LCOV_OPTS --no-external --omit-lines 'xyz\s+std::string str.+' -o omitWarn.info --ignore unused --rc lcov_excl_start=LCOV_EXCL_START_1 --rc lcov_excl_stop=LCOV_EXCL_STOP_1 if [ 0 != $? ] ; then echo "Error: unexpected expected error code from lcov --omit --ignore.." @@ -609,7 +621,7 @@ fi echo "ignore_errors = unused" >> testRC echo "ignore_errors = empty" >> testRC -$COVER $CAPTURE . $LCOV_OPTS --no-external --config-file testRC -o rc_omitWarn.info +$COVER $CAPTURE . $LCOV_OPTS --no-external --config-file testRC -o rc_omitWarn.info --rc lcov_excl_start=LCOV_EXCL_START_1 --rc lcov_excl_stop=LCOV_EXCL_STOP_1 if [ 0 != $? ] ; then echo "Error: saw unexpected error code from lcov --config with ignored bad omit" @@ -658,6 +670,160 @@ if [ $? == 0 ] ; then fi fi +# some tests for 'unreachable' implementation +$COVER $CAPTURE . $LCOV_OPTS --no-external -o unreachable.info --rc lcov_unreachable_start=LCOV_EXCL_START_1 --rc lcov_unreachable_stop=LCOV_EXCL_STOP_1 2>&1 | tee unreachableErr1.txt +if [ 0 == ${PIPESTATUS[0]} ] ; then + echo "Error: unexpected error from capture-internal" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + +grep -E "\(unreachable\) .+ BRDA record in 'unreachable' region has non-zero hit count" unreachableErr1.txt +if [ 0 != $? ] ; then + echo "Error: didn't find expected unreachable DA record" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + +# exclude branch coverage and run again - to get to unreachable line error +NOBRANCH_OPT=${LCOV_OPTS/--branch-coverage} +$COVER $CAPTURE . $NOBRANCH_OPT --no-external -o unreachable.info --rc lcov_unreachable_start=LCOV_EXCL_START_1 --rc lcov_unreachable_stop=LCOV_EXCL_STOP_1 2>&1 | tee unreachableErr2.txt +if [ 0 == ${PIPESTATUS[0]} ] ; then + echo "Error: unexpected error from capture-internal" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + +grep -E "\(unreachable\) .+ 'unreachable' line has non-zero hit count" unreachableErr2.txt +if [ 0 != $? ] ; then + echo "Error: didn't find expected unreachable DA record" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + +$COVER $CAPTURE . $LCOV_OPTS --no-external -o unreachable.info --rc lcov_unreachable_start=LCOV_EXCL_START_1 --rc lcov_unreachable_stop=LCOV_EXCL_STOP_1 --ignore unreachable 2>&1 | tee unreachableWarn1.txt +if [ 0 != ${PIPESTATUS[0]} ] ; then + echo "Error: unexpected error from capture-internal" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + +COUNT=`grep -c -E "\(unreachable\) .+ 'unreachable' .+ has non-zero hit count" unreachableWarn1.txt` +if [ $COUNT != 2 ] ; then + echo "Error: didn't find expected 'unreachable warnings" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi + +fi + +$COVER $CAPTURE . $LCOV_OPTS --no-external -o exclLine.info --rc lcov_excl_line=TEST_UNREACHABLE_LINE +if [ 0 != ${PIPESTATUS[0]} ] ; then + echo "Error: unexpected error from exclude line" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + +grep DA:30 exclLine.info +if [ 0 == $? ] ; then + echo "Error: line exclusion didn't exclude" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + + +$COVER $CAPTURE . $LCOV_OPTS --no-external -o unreachLine.info --rc lcov_unreachable_line=TEST_UNREACHABLE_LINE --ignore unreachable +if [ 0 != ${PIPESTATUS[0]} ] ; then + echo "Error: unexpected error from unreachable_line" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + +grep DA:30 unreachLine.info +if [ 0 != $? ] ; then + echo "Error: unreached line dropped by default" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + +$COVER $LCOV_TOOL $LCOV_OPTS -a unreachLine.info --rc lcov_unreachable_line=TEST_UNREACHABLE_LINE --filter region --ignore unreachable --rc retain_unreachable_coverpoints_if_executed=0 -o removeUnreach.info +if [ 0 != $? ] ; then + echo "Error: lcov unreached failed" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + +grep DA:30 removeUnreach.info +if [ 0 == $? ] ; then + echo "Error: unreached line not removed" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + +$COVER $CAPTURE . $LCOV_OPTS --no-external -o unreachable.info --rc lcov_unreachable_line=TEST_UNREACH_FUNCTION 2>&1 | tee unreachableErr3.txt +if [ 0 == ${PIPESTATUS[0]} ] ; then + echo "Error: unexpected error from unreach function" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + +grep -E '\(unreachable\) .+ function main is executed but was marked unreachable' unreachableErr3.txt +if [ 0 != $? ] ; then + echo "Error: didn't find expected unreachable function record" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi +grep -E "\(unreachable\) .+ 'unreachable' line has non-zero hit count" unreachableErr3.txt +if [ 0 == $? ] ; then + echo "Error: found unexpected unreachable DA record (should have stopped at function)" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + +$COVER $LCOV_TOOL $LCOV_OPTS -a unreachLine.info --rc lcov_unreachable_line=TEST_UNREACH_FUNCTION --filter region --ignore unreachable --rc retain_unreachable_coverpoints_if_executed=0 -o removeUnreachFunc.info 2>&1 | tee unreachFunc.txt +if [ 0 != ${PIPESTATUS[0]} ] ; then + echo "Error: lcov unreached failed" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi +grep -E '\(unreachable\) .+ function main is executed but was marked unreachable' unreachFunc.txt +if [ 0 != $? ] ; then + echo "Error: expected unreached function message" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi +grep -E "\(unreachable\) .+ 'unreachable' line has non-zero hit count" unreachFunc.txt +if [ 0 != $? ] ; then + echo "Error: didn't find expected unreachable DA warning" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + +grep FNA:0,1,main removeUnreachFunc.info +if [ 0 == $? ] ; then + echo "Error: expected function record to be removed" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi +fi + # check case when build dir and GCOV_PREFIX directory are not the same - # so .gcno and .gcda files are in different places export DEPTH=0 @@ -893,7 +1059,7 @@ mkdir -pv ./mytest echo "int main(){}" > './mytest/main space.cpp' ( cd ./mytest ; ${CXX} -c 'main space.cpp' --coverage ) -if [ 1 != $NO_INITIAL_CAPTURE ] ; then +if [ 1 != "$NO_INITIAL_CAPTURE" ] ; then $COVER $CAPTURE mytest -i -o spaces.info if [ 0 != $? ] ; then echo "Error: unexpected error from filename containing space" @@ -919,7 +1085,6 @@ if [ 1 != $NO_INITIAL_CAPTURE ] ; then fi fi - echo "Tests passed" if [ "x$COVER" != "x" ] && [ $LOCAL_COVERAGE == 1 ]; then diff --git a/tests/lcov/mcdc/mcdc.sh b/tests/lcov/mcdc/mcdc.sh index 27ba3c03..9aa14e10 100755 --- a/tests/lcov/mcdc/mcdc.sh +++ b/tests/lcov/mcdc/mcdc.sh @@ -35,6 +35,7 @@ STATUS=0 function runClang() ( # runClang exeName srcFile flags + echo "clang++ -fprofile-instr-generate -fcoverage-mapping -fcoverage-mcdc -o $1 main.cpp test.cpp $2" clang++ -fprofile-instr-generate -fcoverage-mapping -fcoverage-mcdc -o $1 main.cpp test.cpp $2 if [ $? != 0 ] ; then echo "ERROR from clang++ $1" @@ -81,6 +82,7 @@ function runGcc() shift ARG=$1 shift + echo "g++ --coverage -fcondition-coverage -o $NAME main.cpp test.cpp $ARG" # runGcc exeName srcFile flags eval g++ --coverage -fcondition-coverage -o $NAME main.cpp test.cpp $ARG if [ $? != 0 ] ; then @@ -88,6 +90,7 @@ function runGcc() return 1 fi ./$NAME + echo "$GENINFO_TOOL -o $NAME.info --mcdc --branch $NAME-test.gcda $@" $COVER $GENINFO_TOOL -o $NAME.info --mcdc --branch $NAME-test.gcda $@ if [ $? != 0 ] ; then echo "ERROR from geninfo $NAME"