Skip to content

Commit 146a4ed

Browse files
committed
More consistency checking for function decls, usage.
Suppress warnings for functions which will be dropped. See #327 Signed-off-by: Henry Cox <[email protected]>
1 parent 3f50526 commit 146a4ed

File tree

4 files changed

+191
-39
lines changed

4 files changed

+191
-39
lines changed

lib/lcovutil.pm

Lines changed: 110 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ our $lcov_filter_chunk_size;
262262
our $fail_under_lines;
263263
our $fail_under_branches;
264264

265+
our $fix_inconsistency = 1;
266+
265267
sub default_info_impl(@);
266268

267269
our $info_callback = \&default_info_impl;
@@ -345,6 +347,8 @@ our $trivial_function_threshold = 5;
345347
# list of regexps applied to line text - if exclude if matched
346348
our @omit_line_patterns;
347349
our @exclude_function_patterns;
350+
# need a pattern copy that we don't disable for function message suppressions
351+
our @suppress_function_patterns;
348352

349353
our %languageExtensions = ('c' => 'c|h|i|C|H|I|icc|cpp|cc|cxx|hh|hpp|hxx',
350354
'rtl' => 'v|vh|sv|vhdl?',
@@ -1704,6 +1708,7 @@ sub munge_file_patterns
17041708
die("invalid '" . $regexp->[0] . "' exclude pattern: $error")
17051709
if $error;
17061710
}
1711+
@suppress_function_patterns = map({ $_->[0] } @exclude_function_patterns);
17071712
}
17081713

17091714
sub warn_file_patterns
@@ -1929,7 +1934,7 @@ sub is_ignored($)
19291934
my $code = shift;
19301935
die("invalid error code $code")
19311936
unless 0 <= $code && $code < scalar(@ignore);
1932-
return $ignore[$code];
1937+
return $ignore[$code] || (defined($stop_on_error) && 0 == $stop_on_error);
19331938
}
19341939

19351940
our %explainOnce; # append explanation to first error/warning message (only)
@@ -4424,6 +4429,12 @@ sub line
44244429
return $self->[FIRST];
44254430
}
44264431

4432+
sub set_line
4433+
{
4434+
my ($self, $line) = @_;
4435+
return $self->[FIRST] = $line;
4436+
}
4437+
44274438
sub end_line
44284439
{
44294440
my $self = shift;
@@ -4470,7 +4481,9 @@ sub addAlias
44704481
$count = 0;
44714482
} elsif (defined($lcovutil::excessive_count_threshold) &&
44724483
$count > $lcovutil::excessive_count_threshold) {
4473-
$self->_format_error($lcovutil::ERROR_EXCESSIVE_COUNT, $name, $count);
4484+
$self->_format_error($lcovutil::ERROR_EXCESSIVE_COUNT, $name, $count)
4485+
unless grep({ $name =~ $_ || $self->name() =~ $_ }
4486+
@lcovutil::suppress_function_patterns);
44744487
}
44754488
my $changed;
44764489
my $aliases = $self->[ALIASES];
@@ -4641,12 +4654,32 @@ sub list_functions
46414654

46424655
sub define_function
46434656
{
4644-
my ($self, $fnName, $start_line, $end_line) = @_;
4657+
my ($self, $fnName, $start_line, $end_line, $location) = @_;
46454658
#lcovutil::info("define: $fnName " . $self->$filename() . ":$start_line->$end_line\n");
46464659
# could check that function ranges within file are non-overlapping
46474660
my ($locationMap, $nameMap) = @$self;
46484661

4649-
my $data;
4662+
my $data = $self->findName($fnName);
4663+
if (defined($data) &&
4664+
#TraceFile::is_language('c', $self->filename()) &&
4665+
$data->line() != $start_line
4666+
) {
4667+
lcovutil::ignorable_error($lcovutil::ERROR_INCONSISTENT_DATA,
4668+
(defined($location) ? "$location: " : '') .
4669+
"duplicate function '$fnName' starts on line $start_line but previous definition started on "
4670+
. $data->line() . '.')
4671+
unless
4672+
grep({ $fnName =~ $_ } @lcovutil::suppress_function_patterns);
4673+
# if ignored, just return the function we already have -
4674+
# record the function location as the smallest line number we saw
4675+
if ($start_line < $data->line()) {
4676+
delete $self->[0]->{$data->line()};
4677+
$data->set_line($start_line);
4678+
$self->[0]->{$start_line} = $data;
4679+
}
4680+
return $data;
4681+
}
4682+
46504683
if (exists($locationMap->{$start_line})) {
46514684
$data = $locationMap->{$start_line};
46524685
unless ((defined($end_line) &&
@@ -4663,7 +4696,9 @@ sub define_function
46634696
" -> "
46644697
.
46654698
(defined($end_line) ? $end_line :
4666-
'undef'));
4699+
'undef'))
4700+
unless
4701+
grep({ $fnName =~ $_ } @lcovutil::suppress_function_patterns);
46674702
# pick the highest end line if we didn't error out
46684703
$data->set_end_line($end_line)
46694704
if (defined($end_line) &&
@@ -4781,9 +4816,6 @@ sub union
47814816
}
47824817
# merge in all the new aliases
47834818
while (my ($alias, $count) = each(%{$thatData->aliases()})) {
4784-
$self->define_function($alias, $thisData->line(),
4785-
$thisData->end_line())
4786-
unless ($self->findName($alias));
47874819
if ($thisData->addAlias($alias, $count)) {
47884820
$changed = 1;
47894821
}
@@ -7029,12 +7061,13 @@ sub _deriveFunctionEndLines
70297061
my $end = $func->end_line();
70307062
#unless (defined($lineData->value($first))) {
70317063
# lcovutil::ignorable_error($lcovutil::ERROR_INCONSISTENT_DATA,
7032-
# '"' . $func->filename() .
7064+
# '"' . $func->filename() .
70337065
# "\":$first: first line of function has no linecov.");
70347066
# $lineData->append($first, $func->hit());
70357067
#}
7036-
while ($first < $currentLine) {
7068+
while ($first > $currentLine) {
70377069
if (@lines) {
7070+
last if $lines[0] > $first;
70387071
$currentLine = shift @lines;
70397072
} else {
70407073
if (!defined($end)) {
@@ -7155,6 +7188,30 @@ sub _consistencySuffix
71557188
);
71567189
}
71577190

7191+
sub _fixFunction
7192+
{
7193+
my ($traceInfo, $func, $count) = @_;
7194+
7195+
my @fix = ($func);
7196+
my $line = $func->line();
7197+
my $per_testcase = $traceInfo->testfnc();
7198+
foreach my $testname ($per_testcase->keylist()) {
7199+
my $data = $traceInfo->testfnc($testname);
7200+
my $f = $data->findKey($line);
7201+
push(@fix, $f) if defined($f);
7202+
}
7203+
7204+
foreach my $f (@fix) {
7205+
$f->[FunctionEntry::COUNT] = $count;
7206+
7207+
# and mark that each alias was hit...
7208+
my $aliases = $f->aliases();
7209+
foreach my $alias (keys %$aliases) {
7210+
$aliases->{$alias} += $count;
7211+
}
7212+
}
7213+
}
7214+
71587215
sub _checkConsistency
71597216
{
71607217
return unless $lcovutil::check_data_consistency;
@@ -7208,30 +7265,46 @@ sub _checkConsistency
72087265
$currentLine = shift(@lines);
72097266
next;
72107267
}
7211-
7268+
my $suffix =
7269+
($lcovutil::fix_inconsistency && lcovutil::is_ignored(
7270+
$lcovutil::ERROR_INCONSISTENT_DATA)
7271+
) ? ": function marked 'hit'" :
7272+
'';
72127273
lcovutil::ignorable_error($lcovutil::ERROR_INCONSISTENT_DATA,
7213-
'"' . $func->filename() .
7214-
"\":$first: function '" . $func->name() .
7215-
"' is not hit but line $currentLine is." .
7216-
_consistencySuffix());
7217-
# if message was ignored, then mark the function hit
7218-
$func->[FunctionEntry::COUNT] = 1;
7219-
$imHit = 1;
7220-
$modified = 1;
7274+
'"' . $func->filename() .
7275+
"\":$first: function '" . $func->name() .
7276+
"' is not hit but line $currentLine is$suffix." .
7277+
_consistencySuffix());
7278+
if ($lcovutil::fix_inconsistency) {
7279+
# if message was ignored, then mark the function and all
7280+
# its aliases hit
7281+
$imHit = 1;
7282+
$modified = 1;
7283+
_fixFunction($traceInfo, $func, $hit);
7284+
}
72217285
last; # only warn on the first hit line in the function
72227286
}
72237287
last if $lineHit && $hit; # can stop looking at this function now
72247288
last unless (@lines);
72257289
$currentLine = shift @lines;
72267290
}
72277291
if ($imHit && !$lineHit) {
7292+
my $suffix =
7293+
($lcovutil::fix_inconsistency &&
7294+
lcovutil::is_ignored($lcovutil::ERROR_INCONSISTENT_DATA)) ?
7295+
": function marked 'not hit'" :
7296+
'';
72287297
lcovutil::ignorable_error($lcovutil::ERROR_INCONSISTENT_DATA,
7229-
'"' . $traceInfo->filename() .
7230-
"\":$first: function '" . $func->name() .
7231-
"' is hit but no contained lines are hit." .
7232-
_consistencySuffix());
7233-
# if message was ignored, then mark the function not hit
7234-
$func->[FunctionEntry::COUNT] = 0;
7298+
'"' . $traceInfo->filename() .
7299+
"\":$first: function '" . $func->name() .
7300+
"' is hit but no contained lines are hit$suffix." .
7301+
_consistencySuffix());
7302+
if ($lcovutil::fix_inconsistency) {
7303+
# if message was ignored, then mark the function and its aliases
7304+
# not hit
7305+
$modified = 1;
7306+
_fixFunction($traceInfo, $func, 0);
7307+
}
72357308
}
72367309
}
72377310

@@ -7386,7 +7459,6 @@ sub _filterFile
73867459
}
73877460

73887461
if (defined($lcovutil::func_coverage) &&
7389-
!$state->[0]->[1] &&
73907462
(0 != scalar(@lcovutil::exclude_function_patterns) ||
73917463
defined($trivial_histogram))
73927464
) {
@@ -8296,8 +8368,8 @@ sub _read_info
82968368
#if ($self->contains($filename)) {
82978369
# # we expect there to be only one entry for each source file in each section
82988370
# lcovutil::ignorable_warning($lcovutil::ERROR_FORMAT,
8299-
# "Duplicate entries for \"$filename\""
8300-
# . ($testname ? " in testcase '$testname'" : '') . '.');
8371+
# "Duplicate entries for \"$filename\""
8372+
# . ($testname ? " in testcase '$testname'" : '') . '.');
83018373
#}
83028374
$filename = ReadCurrentSource::resolve_path($1, 1);
83038375
# should this one be skipped?
@@ -8455,23 +8527,23 @@ sub _read_info
84558527
my $lineNo = $1;
84568528
my $fnName = $4;
84578529
my $end_line = $3;
8458-
if ($lineNo <= 0 ||
8459-
(defined($end_line) && $end_line <= 0)) {
8530+
if (!grep({ $fnName =~ $_ }
8531+
@lcovutil::suppress_function_patterns) &&
8532+
($lineNo <= 0 ||
8533+
(defined($end_line) && $end_line <= 0))
8534+
) {
84608535
lcovutil::ignorable_error($lcovutil::ERROR_FORMAT,
84618536
"\"$tracefile\":$.: unexpected function line '$lineNo' in .info file record '$_'"
84628537
) if $lineNo <= 0;
84638538
lcovutil::ignorable_error($lcovutil::ERROR_FORMAT,
84648539
"\"$tracefile\":$.: unexpected function end line '$end_line' in .info file record '$_'"
84658540
) if defined($end_line) && $end_line <= 0;
8466-
8467-
last;
84688541
}
84698542
# the function may already be defined by another testcase
84708543
# (for the same file)
84718544
$functionMap->define_function($fnName, $lineNo,
8472-
$end_line ? $end_line : undef)
8473-
unless defined($functionMap->findName($fnName));
8474-
8545+
$end_line ? $end_line : undef,
8546+
, "\"$tracefile\":$.");
84758547
last;
84768548
};
84778549

@@ -8482,7 +8554,6 @@ sub _read_info
84828554
my $hit = $1;
84838555
# error checking is in the addAlias method
84848556
$functionMap->add_count($fnName, $hit);
8485-
84868557
last;
84878558
};
84888559

@@ -8507,7 +8578,8 @@ sub _read_info
85078578
unless exists($fnIdxMap{$fnIndex});
85088579
my ($lineNo, $end_line) = @{$fnIdxMap{$fnIndex}};
85098580
my $fn =
8510-
$functionMap->define_function($alias, $lineNo, $end_line);
8581+
$functionMap->define_function($alias, $lineNo, $end_line,
8582+
"\"$tracefile\":$.");
85118583
$fn->addAlias($alias, $hit);
85128584
last;
85138585
};
@@ -8783,7 +8855,7 @@ sub write_info($$$)
87838855
lcovutil::ignorable_error($lcovutil::ERROR_FORMAT,
87848856
"\"$source_file\": unexpected line number '$line' for function $alias"
87858857
);
8786-
next;
8858+
# if message is ignored, leave bogus entry in the data
87878859
}
87888860
++$fnIndex;
87898861
my $endLine =

tests/lcov/merge/a.dat

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
SF:project/common/trace/tracer_singleton.cpp
2+
FN:23,_ZN5project5trace15TracerSingleton11get_backendEv
3+
FN:18,_ZN5project5trace15TracerSingleton11set_backendESt10unique_ptrINS0_17TracerBackendBaseESt14default_deleteIS3_EE
4+
FN:12,_ZN5project5trace15TracerSingleton3getEv
5+
FN:7,_ZN5project5trace15TracerSingletonC2Ev
6+
FNDA:1920,_ZN5project5trace15TracerSingleton11get_backendEv
7+
FNDA:27,_ZN5project5trace15TracerSingleton11set_backendESt10unique_ptrINS0_17TracerBackendBaseESt14default_deleteIS3_EE
8+
FNDA:1949,_ZN5project5trace15TracerSingleton3getEv
9+
FNDA:34,_ZN5project5trace15TracerSingletonC2Ev
10+
FNF:4
11+
FNH:4
12+
DA:7,34
13+
DA:8,34
14+
DA:9,34
15+
DA:12,1949
16+
DA:13,1949
17+
DA:14,1949
18+
DA:15,1949
19+
DA:18,27
20+
DA:19,27
21+
DA:20,27
22+
DA:23,1920
23+
DA:24,1920
24+
DA:25,1920
25+
LH:13
26+
LF:13
27+
end_of_record

tests/lcov/merge/b.dat

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
SF:project/common/trace/tracer_singleton.cpp
2+
FN:22,_ZN5project5trace15TracerSingleton11get_backendEv
3+
FN:17,_ZN5project5trace15TracerSingleton11set_backendENSt3__110unique_ptrINS0_17TracerBackendBaseENS2_14default_deleteIS4_EEEE
4+
FN:11,_ZN5project5trace15TracerSingleton3getEv
5+
FN:7,_ZN5project5trace15TracerSingletonC2Ev
6+
FNDA:0,_ZN5project5trace15TracerSingleton11get_backendEv
7+
FNDA:0,_ZN5project5trace15TracerSingleton11set_backendENSt3__110unique_ptrINS0_17TracerBackendBaseENS2_14default_deleteIS4_EEEE
8+
FNDA:0,_ZN5project5trace15TracerSingleton3getEv
9+
FNDA:0,_ZN5project5trace15TracerSingletonC2Ev
10+
FNF:4
11+
FNH:0
12+
BRDA:13,0,0,-
13+
BRDA:13,0,1,-
14+
BRDA:13,0,2,-
15+
BRDA:13,0,3,-
16+
BRDA:13,0,4,-
17+
BRDA:13,0,5,-
18+
BRDA:13,0,6,-
19+
BRDA:13,0,7,-
20+
BRF:8
21+
BRH:0
22+
DA:7,0
23+
DA:9,0
24+
DA:11,0
25+
DA:13,0
26+
DA:14,0
27+
DA:17,0
28+
DA:19,0
29+
DA:20,0
30+
DA:22,0
31+
DA:24,0
32+
LH:0
33+
LF:10
34+
end_of_record

tests/lcov/merge/merge.sh

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ if [ 0 != $? ] ; then
239239
fi
240240
fi
241241
242-
for count in 'FNF:2' 'FNH:1' ; do
242+
for count in 'FNF:2' 'FNH:2' ; do
243243
grep $count func.info
244244
if [ 0 != $? ] ; then
245245
echo "Error: didn't find expected count '$count' in function merge"
@@ -250,6 +250,25 @@ for count in 'FNF:2' 'FNH:1' ; do
250250
fi
251251
done
252252
253+
$COVER $LCOV_TOOL $LCOV_OPTS -o inconsistent.info -a a.dat -a b.dat --ignore inconsistent --msg-log inconsistent.log
254+
if [ 0 != $? ] ; then
255+
echo "Error: function merge2 failed"
256+
257+
status=1
258+
if [ $KEEP_GOING == 0 ] ; then
259+
exit 1
260+
fi
261+
fi
262+
grep -E "duplicate function .+ starts on line .+ but previous definition" inconsistent.log
263+
if [ 0 != $? ] ; then
264+
echo "Error: didn't find definition message"
265+
266+
status=1
267+
if [ $KEEP_GOING == 0 ] ; then
268+
exit 1
269+
fi
270+
fi
271+
253272
if [ 0 == $status ] ; then
254273
echo "Tests passed"
255274
else

0 commit comments

Comments
 (0)