@@ -262,6 +262,8 @@ our $lcov_filter_chunk_size;
262
262
our $fail_under_lines ;
263
263
our $fail_under_branches ;
264
264
265
+ our $fix_inconsistency = 1;
266
+
265
267
sub default_info_impl (@);
266
268
267
269
our $info_callback = \&default_info_impl;
@@ -345,6 +347,8 @@ our $trivial_function_threshold = 5;
345
347
# list of regexps applied to line text - if exclude if matched
346
348
our @omit_line_patterns ;
347
349
our @exclude_function_patterns ;
350
+ # need a pattern copy that we don't disable for function message suppressions
351
+ our @suppress_function_patterns ;
348
352
349
353
our %languageExtensions = (' c' => ' c|h|i|C|H|I|icc|cpp|cc|cxx|hh|hpp|hxx' ,
350
354
' rtl' => ' v|vh|sv|vhdl?' ,
@@ -1704,6 +1708,7 @@ sub munge_file_patterns
1704
1708
die (" invalid '" . $regexp -> [0] . " ' exclude pattern: $error " )
1705
1709
if $error ;
1706
1710
}
1711
+ @suppress_function_patterns = map ({ $_ -> [0] } @exclude_function_patterns );
1707
1712
}
1708
1713
1709
1714
sub warn_file_patterns
@@ -1929,7 +1934,7 @@ sub is_ignored($)
1929
1934
my $code = shift ;
1930
1935
die (" invalid error code $code " )
1931
1936
unless 0 <= $code && $code < scalar (@ignore );
1932
- return $ignore [$code ];
1937
+ return $ignore [$code ] || ( defined ( $stop_on_error ) && 0 == $stop_on_error ) ;
1933
1938
}
1934
1939
1935
1940
our %explainOnce ; # append explanation to first error/warning message (only)
@@ -4424,6 +4429,12 @@ sub line
4424
4429
return $self -> [FIRST];
4425
4430
}
4426
4431
4432
+ sub set_line
4433
+ {
4434
+ my ($self , $line ) = @_ ;
4435
+ return $self -> [FIRST] = $line ;
4436
+ }
4437
+
4427
4438
sub end_line
4428
4439
{
4429
4440
my $self = shift ;
@@ -4470,7 +4481,9 @@ sub addAlias
4470
4481
$count = 0;
4471
4482
} elsif (defined ($lcovutil::excessive_count_threshold ) &&
4472
4483
$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 );
4474
4487
}
4475
4488
my $changed ;
4476
4489
my $aliases = $self -> [ALIASES];
@@ -4641,12 +4654,32 @@ sub list_functions
4641
4654
4642
4655
sub define_function
4643
4656
{
4644
- my ($self , $fnName , $start_line , $end_line ) = @_ ;
4657
+ my ($self , $fnName , $start_line , $end_line , $location ) = @_ ;
4645
4658
# lcovutil::info("define: $fnName " . $self->$filename() . ":$start_line->$end_line\n");
4646
4659
# could check that function ranges within file are non-overlapping
4647
4660
my ($locationMap , $nameMap ) = @$self ;
4648
4661
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
+
4650
4683
if (exists ($locationMap -> {$start_line })) {
4651
4684
$data = $locationMap -> {$start_line };
4652
4685
unless ((defined ($end_line ) &&
@@ -4663,7 +4696,9 @@ sub define_function
4663
4696
" -> "
4664
4697
.
4665
4698
(defined ($end_line ) ? $end_line :
4666
- ' undef' ));
4699
+ ' undef' ))
4700
+ unless
4701
+ grep ({ $fnName =~ $_ } @lcovutil::suppress_function_patterns );
4667
4702
# pick the highest end line if we didn't error out
4668
4703
$data -> set_end_line($end_line )
4669
4704
if (defined ($end_line ) &&
@@ -4781,9 +4816,6 @@ sub union
4781
4816
}
4782
4817
# merge in all the new aliases
4783
4818
while (my ($alias , $count ) = each (%{$thatData -> aliases()})) {
4784
- $self -> define_function($alias , $thisData -> line(),
4785
- $thisData -> end_line())
4786
- unless ($self -> findName($alias ));
4787
4819
if ($thisData -> addAlias($alias , $count )) {
4788
4820
$changed = 1;
4789
4821
}
@@ -7029,12 +7061,13 @@ sub _deriveFunctionEndLines
7029
7061
my $end = $func -> end_line();
7030
7062
# unless (defined($lineData->value($first))) {
7031
7063
# lcovutil::ignorable_error($lcovutil::ERROR_INCONSISTENT_DATA,
7032
- # '"' . $func->filename() .
7064
+ # '"' . $func->filename() .
7033
7065
# "\":$first: first line of function has no linecov.");
7034
7066
# $lineData->append($first, $func->hit());
7035
7067
# }
7036
- while ($first < $currentLine ) {
7068
+ while ($first > $currentLine ) {
7037
7069
if (@lines ) {
7070
+ last if $lines [0] > $first ;
7038
7071
$currentLine = shift @lines ;
7039
7072
} else {
7040
7073
if (!defined ($end )) {
@@ -7155,6 +7188,30 @@ sub _consistencySuffix
7155
7188
);
7156
7189
}
7157
7190
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
+
7158
7215
sub _checkConsistency
7159
7216
{
7160
7217
return unless $lcovutil::check_data_consistency ;
@@ -7208,30 +7265,46 @@ sub _checkConsistency
7208
7265
$currentLine = shift (@lines );
7209
7266
next ;
7210
7267
}
7211
-
7268
+ my $suffix =
7269
+ ($lcovutil::fix_inconsistency && lcovutil::is_ignored(
7270
+ $lcovutil::ERROR_INCONSISTENT_DATA )
7271
+ ) ? " : function marked 'hit'" :
7272
+ ' ' ;
7212
7273
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
+ }
7221
7285
last ; # only warn on the first hit line in the function
7222
7286
}
7223
7287
last if $lineHit && $hit ; # can stop looking at this function now
7224
7288
last unless (@lines );
7225
7289
$currentLine = shift @lines ;
7226
7290
}
7227
7291
if ($imHit && !$lineHit ) {
7292
+ my $suffix =
7293
+ ($lcovutil::fix_inconsistency &&
7294
+ lcovutil::is_ignored($lcovutil::ERROR_INCONSISTENT_DATA )) ?
7295
+ " : function marked 'not hit'" :
7296
+ ' ' ;
7228
7297
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
+ }
7235
7308
}
7236
7309
}
7237
7310
@@ -7386,7 +7459,6 @@ sub _filterFile
7386
7459
}
7387
7460
7388
7461
if (defined ($lcovutil::func_coverage ) &&
7389
- !$state -> [0]-> [1] &&
7390
7462
(0 != scalar (@lcovutil::exclude_function_patterns ) ||
7391
7463
defined ($trivial_histogram ))
7392
7464
) {
@@ -8296,8 +8368,8 @@ sub _read_info
8296
8368
# if ($self->contains($filename)) {
8297
8369
# # we expect there to be only one entry for each source file in each section
8298
8370
# 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'" : '') . '.');
8301
8373
# }
8302
8374
$filename = ReadCurrentSource::resolve_path($1 , 1);
8303
8375
# should this one be skipped?
@@ -8455,23 +8527,23 @@ sub _read_info
8455
8527
my $lineNo = $1 ;
8456
8528
my $fnName = $4 ;
8457
8529
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
+ ) {
8460
8535
lcovutil::ignorable_error($lcovutil::ERROR_FORMAT ,
8461
8536
" \" $tracefile \" :$. : unexpected function line '$lineNo ' in .info file record '$_ '"
8462
8537
) if $lineNo <= 0;
8463
8538
lcovutil::ignorable_error($lcovutil::ERROR_FORMAT ,
8464
8539
" \" $tracefile \" :$. : unexpected function end line '$end_line ' in .info file record '$_ '"
8465
8540
) if defined ($end_line ) && $end_line <= 0;
8466
-
8467
- last ;
8468
8541
}
8469
8542
# the function may already be defined by another testcase
8470
8543
# (for the same file)
8471
8544
$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 \" :$. " );
8475
8547
last ;
8476
8548
};
8477
8549
@@ -8482,7 +8554,6 @@ sub _read_info
8482
8554
my $hit = $1 ;
8483
8555
# error checking is in the addAlias method
8484
8556
$functionMap -> add_count($fnName , $hit );
8485
-
8486
8557
last ;
8487
8558
};
8488
8559
@@ -8507,7 +8578,8 @@ sub _read_info
8507
8578
unless exists ($fnIdxMap {$fnIndex });
8508
8579
my ($lineNo , $end_line ) = @{$fnIdxMap {$fnIndex }};
8509
8580
my $fn =
8510
- $functionMap -> define_function($alias , $lineNo , $end_line );
8581
+ $functionMap -> define_function($alias , $lineNo , $end_line ,
8582
+ " \" $tracefile \" :$. " );
8511
8583
$fn -> addAlias($alias , $hit );
8512
8584
last ;
8513
8585
};
@@ -8783,7 +8855,7 @@ sub write_info($$$)
8783
8855
lcovutil::ignorable_error($lcovutil::ERROR_FORMAT ,
8784
8856
" \" $source_file \" : unexpected line number '$line ' for function $alias "
8785
8857
);
8786
- next ;
8858
+ # if message is ignored, leave bogus entry in the data
8787
8859
}
8788
8860
++$fnIndex ;
8789
8861
my $endLine =
0 commit comments