@@ -746,8 +746,9 @@ sub merge_child_profile($)
746
746
if (exists ($lcovutil::profileData {$key }{$f })
747
747
&&
748
748
grep (/ ^$key $ / ,
749
- ( ' version' , ' parse' , ' append' , ' total' ,
750
- ' resolve' ))
749
+ ( ' version' , ' parse' ,
750
+ ' append' , ' total' ,
751
+ ' resolve' , ' derive_end' ))
751
752
) {
752
753
$lcovutil::profileData {$key }{$f } += $t ;
753
754
} else {
@@ -1325,7 +1326,7 @@ sub parseOptions
1325
1326
[\@opt_ignore_errors , \@rc_ignore ],
1326
1327
[\@lcovutil::exclude_file_patterns , \@rc_exclude_patterns ],
1327
1328
[\@lcovutil::include_file_patterns , \@rc_include_patterns ],
1328
- [\@lcovutil::subst_file_patterns , \@rc_subst_patterns ],
1329
+ [\@lcovutil::file_subst_patterns , \@rc_subst_patterns ],
1329
1330
[\@lcovutil::omit_line_patterns , \@rc_omit_patterns ],
1330
1331
[\@lcovutil::exclude_function_patterns , \@rc_erase_patterns
1331
1332
],
@@ -4961,8 +4962,7 @@ sub parseLines
4961
4962
++$lcovutil::cov_filter [$lcovutil::FILTER_DIRECTIVE ]-> [0];
4962
4963
++$lcovutil::cov_filter [$lcovutil::FILTER_DIRECTIVE ]-> [1];
4963
4964
push (@excluded , 3); # everything excluded
4964
- lcovutil::info(2,
4965
- " exclude '#$1 ' directive on $filename :$line \n " );
4965
+ lcovutil::info(2, " exclude '#$1 ' directive on $filename :$line \n " );
4966
4966
next ;
4967
4967
}
4968
4968
@@ -5660,9 +5660,152 @@ sub _eraseFunctions
5660
5660
return $modified ;
5661
5661
}
5662
5662
5663
+ sub _deriveFunctionEndLines
5664
+ {
5665
+ my $traceInfo = shift ;
5666
+ my $modified = 0;
5667
+
5668
+ my $start = Time::HiRes::gettimeofday();
5669
+ my @lines = sort { $a <=> $b } $traceInfo -> sum()-> keylist();
5670
+ # sort functions by start line number
5671
+ # ignore lambdas - which we don't process correctly at the moment
5672
+ # (would need to do syntactic search for the end line)
5673
+ my @functions = sort { $a -> line() <=> $b -> line() }
5674
+ grep ({ !$_ -> isLambda() } $traceInfo -> func()-> valuelist());
5675
+
5676
+ my $currentLine = @lines ? shift (@lines ) : 0;
5677
+ my $funcData = $traceInfo -> testfnc();
5678
+ FUNC: while (@functions ) {
5679
+ my $func = shift (@functions );
5680
+ my $first = $func -> line();
5681
+ my $end = $func -> end_line();
5682
+ while ($first < $currentLine ) {
5683
+ if (@lines ) {
5684
+ $currentLine = shift @lines ;
5685
+ } else {
5686
+ if (!defined ($end )) {
5687
+ my $suffix =
5688
+ lcovutil::explain_once(' derive_end_line' ,
5689
+ " See lcovrc man entry for 'derive_function_end_line'."
5690
+ );
5691
+ lcovutil::ignorable_error(
5692
+ $lcovutil::ERROR_INCONSISTENT_DATA ,
5693
+ ' "' . $traceInfo -> filename() .
5694
+ " \" :$first : function " . $func -> name() .
5695
+ " found on line but no corresponding 'line' coverage data point. Cannot derive function end line."
5696
+ . $suffix );
5697
+ }
5698
+ next FUNC;
5699
+ }
5700
+ }
5701
+ if (!defined ($end )) {
5702
+ # where is the next function? Find the last 'line' coverpoint
5703
+ # less than the start line of that function..
5704
+ if (@lines ) {
5705
+ # if there are no more lines in this file - then everything
5706
+ # must be ending on the last line we saw
5707
+ if (@functions ) {
5708
+ my $next_func = $functions [0];
5709
+ my $start = $next_func -> line();
5710
+ while (@lines &&
5711
+ $lines [0] < $start ) {
5712
+ $currentLine = shift @lines ;
5713
+ }
5714
+ } else {
5715
+ # last line in the file must be the last line
5716
+ # of this function
5717
+ if (@lines ) {
5718
+ $currentLine = $lines [-1];
5719
+ } else {
5720
+ my $suffix = lcovutil::explain_once(' derive_end_line' ,
5721
+ " See lcovrc man entry for 'derive_function_end_line'."
5722
+ );
5723
+ lcovutil::ignorable_error(
5724
+ $lcovutil::ERROR_INCONSISTENT_DATA ,
5725
+ ' "' . $traceInfo -> filenname() .
5726
+ " \" :$first : function " . $func -> name() .
5727
+ " : last line in file is not last line of function.$suffix "
5728
+ );
5729
+ next FUNC;
5730
+ }
5731
+ }
5732
+ } elsif ($currentLine < $first ) {
5733
+ # we ran out of lines in the data...check for inconsistency
5734
+ my $suffix =
5735
+ lcovutil::explain_once(' derive_end_line' ,
5736
+ " See lcovrc man entry for 'derive_function_end_line'." );
5737
+ lcovutil::ignorable_error($lcovutil::ERROR_INCONSISTENT_DATA ,
5738
+ ' "' . $traceInfo -> filename() .
5739
+ " \" :$first : function " . $func -> name() .
5740
+ " found on line but no corresponding 'line' coverage data point. Cannot derive function end line."
5741
+ . $suffix );
5742
+
5743
+ # last FUNC; # quit looking here - all the other functions after this one will have same issue
5744
+ next FUNC; # warn about them all
5745
+ }
5746
+ lcovutil::info(1,
5747
+ ' "' . $traceInfo -> filename() .
5748
+ " \" :$currentLine : assign end_line " .
5749
+ $func -> name() . " \n " );
5750
+ $func -> set_end_line($currentLine );
5751
+ $modified = 1;
5752
+ }
5753
+ # we may not have set the end line above due to inconsistency
5754
+ # but we also might not have line data
5755
+ # - see .../tests/lcov/extract with gcc/4.8
5756
+ if (!defined ($func -> end_line())) {
5757
+ my $suffix =
5758
+ lcovutil::explain_once(' derive_end_line' ,
5759
+ " See lcovrc man entry for 'derive_function_end_line'." );
5760
+ lcovutil::ignorable_error($lcovutil::ERROR_INCONSISTENT_DATA ,
5761
+ ' "' . $func -> filename() . ' ":' . $func -> line() .
5762
+ ' : failed to set end line for function ' .
5763
+ $func -> name() . ' .' . $suffix );
5764
+ next FUNC;
5765
+ }
5766
+
5767
+ # now look for this function in each testcase -
5768
+ # set the same endline (if not already set)
5769
+ my $key = $func -> file() . ' :' . $first ;
5770
+ foreach my $tn ($funcData -> keylist()) {
5771
+ my $d = $funcData -> value($tn );
5772
+ my $f = $d -> findKey($key );
5773
+ if (defined ($f )) {
5774
+ if (!defined ($f -> end_line())) {
5775
+ $f -> set_end_line($func -> end_line());
5776
+ $modified = 1;
5777
+ } else {
5778
+ if ($f -> end_line() != $func -> end_line()) {
5779
+ lcovutil::ignorable_error(
5780
+ $lcovutil::ERROR_INCONSISTENT_DATA ,
5781
+ ' "' . $func -> file() .
5782
+ ' ":' . $first . ' : function \' ' .
5783
+ $func -> name() . ' last line is ' .
5784
+ $func -> end_line() . ' but is ' .
5785
+ $f -> end_line() . " in testcase '$tn '"
5786
+ );
5787
+ }
5788
+ }
5789
+ }
5790
+ } # foreach testcase
5791
+ } # for each function
5792
+ my $end = Time::HiRes::gettimeofday();
5793
+ $lcovutil::profileData {derive_end }{$traceInfo -> filename()} = $end - $start ;
5794
+ return $modified ;
5795
+ }
5796
+
5663
5797
sub _filterFile
5664
5798
{
5665
- my ($traceInfo , $source_file , $srcReader , $state ) = @_ ;
5799
+ my ($traceInfo , $source_file , $actions , $srcReader , $state ) = @_ ;
5800
+
5801
+ my $modified = 0;
5802
+
5803
+ if (0 != ($actions & DID_DERIVE)) {
5804
+ $modified = _deriveFunctionEndLines($traceInfo );
5805
+ if (0 == ($actions & DID_FILTER)) {
5806
+ return [$traceInfo , $modified ];
5807
+ }
5808
+ }
5666
5809
my $region = $cov_filter [$FILTER_EXCLUDE_REGION ];
5667
5810
my $branch_region = $cov_filter [$FILTER_EXCLUDE_BRANCH ];
5668
5811
my $range = $cov_filter [$lcovutil::FILTER_LINE_RANGE ];
@@ -5696,7 +5839,6 @@ sub _filterFile
5696
5839
return ($traceInfo , 0);
5697
5840
}
5698
5841
5699
- my $modified = 0;
5700
5842
if (defined ($lcovutil::func_coverage ) &&
5701
5843
!$state -> [0]-> [1] &&
5702
5844
(0 != scalar (@lcovutil::exclude_function_patterns ) ||
@@ -6306,6 +6448,12 @@ sub applyFilters
6306
6448
# due to differences in #ifdefs when the corresponding tests were compiled.
6307
6449
my @filter_workList ;
6308
6450
6451
+ my $computeEndLine =
6452
+ (0 == ($self -> [STATE] & DID_DERIVE) &&
6453
+ defined ($lcovutil::derive_function_end_line ) &&
6454
+ $lcovutil::derive_function_end_line != 0 &&
6455
+ defined ($lcovutil::func_coverage ));
6456
+
6309
6457
foreach my $name ($self -> files()) {
6310
6458
my $traceInfo = $self -> data($name );
6311
6459
die (" expected TraceInfo, got '" . ref ($traceInfo ) . " '" )
@@ -6323,152 +6471,38 @@ sub applyFilters
6323
6471
# Jacoco pretends to report function end line - but it appears
6324
6472
# to be the last line executed - not the actual last line of
6325
6473
# the function - so broken/completely useless.
6326
- DERIVE:
6327
- if (0 == ($self -> [STATE] & DID_DERIVE) &&
6328
- defined ($lcovutil::derive_function_end_line ) &&
6329
- $lcovutil::derive_function_end_line != 0 &&
6330
- defined ($lcovutil::func_coverage ) &&
6331
- ($lcovutil::derive_end_line_all_files ||
6474
+ my $actions = 0;
6475
+ if ($computeEndLine &&
6476
+ ($lcovutil::derive_function_end_line_all_files ||
6332
6477
is_language(' c|java|perl' , $source_file ))
6333
6478
) {
6334
- my @lines = sort { $a <=> $b } $traceInfo -> sum()-> keylist();
6335
- # sort functions by start line number
6336
- # ignore lambdas - which we don't process correctly at the moment
6337
- # (would need to do syntactic search for the end line)
6338
- my @functions = sort { $a -> line() <=> $b -> line() }
6339
- grep ({ !$_ -> isLambda() } $traceInfo -> func()-> valuelist());
6340
-
6341
- my $currentLine = @lines ? shift (@lines ) : 0;
6342
- my $funcData = $traceInfo -> testfnc();
6343
- FUNC: while (@functions ) {
6344
- my $func = shift (@functions );
6345
- my $first = $func -> line();
6346
- my $end = $func -> end_line();
6347
- while ($first < $currentLine ) {
6348
- if (@lines ) {
6349
- $currentLine = shift @lines ;
6350
- } else {
6351
- if (!defined ($end )) {
6352
- my $suffix =
6353
- lcovutil::explain_once(' derive_end_line' ,
6354
- " See lcovrc man entry for 'derive_function_end_line'."
6355
- );
6356
- lcovutil::ignorable_error(
6357
- $lcovutil::ERROR_INCONSISTENT_DATA ,
6358
- " \" $name \" :$first : function " . $func -> name() .
6359
- " found on line but no corresponding 'line' coverage data point. Cannot derive function end line."
6360
- . $suffix );
6361
- }
6362
- next FUNC;
6363
- }
6364
- }
6365
- if (!defined ($end )) {
6366
- # where is the next function? Find the last 'line' coverpoint
6367
- # less than the start line of that function..
6368
- if (@lines ) {
6369
- # if there are no more lines in this file - then everything
6370
- # must be ending on the last line we saw
6371
- if (@functions ) {
6372
- my $next_func = $functions [0];
6373
- my $start = $next_func -> line();
6374
- while (@lines &&
6375
- $lines [0] < $start ) {
6376
- $currentLine = shift @lines ;
6377
- }
6378
- } else {
6379
- # last line in the file must be the last line
6380
- # of this function
6381
- if (@lines ) {
6382
- $currentLine = $lines [-1];
6383
- } else {
6384
- my $suffix = lcovutil::explain_once(' derive_end_line' ,
6385
- " See lcovrc man entry for 'derive_function_end_line'."
6386
- :
6387
- );
6388
- lcovutil::ignorable_error(
6389
- $lcovutil::ERROR_INCONSISTENT_DATA ,
6390
- " \" $name \" :$first : function " .
6391
- $func -> name() .
6392
- " : last line in file is not last line of function.$suffix "
6393
- );
6394
- next FUNC;
6395
- }
6396
- }
6397
- } elsif ($currentLine < $first ) {
6398
- # we ran out of lines in the data...check for inconsistency
6399
- my $suffix =
6400
- lcovutil::explain_once(' derive_end_line' ,
6401
- " See lcovrc man entry for 'derive_function_end_line'." );
6402
- lcovutil::ignorable_error(
6403
- $lcovutil::ERROR_INCONSISTENT_DATA ,
6404
- " \" $name \" :$first : function " . $func -> name() .
6405
- " found on line but no corresponding 'line' coverage data point. Cannot derive function end line."
6406
- . $suffix );
6407
-
6408
- # last FUNC; # quit looking here - all the other functions after this one will have same issue
6409
- next FUNC; # warn about them all
6410
- }
6411
- lcovutil::info(1,
6412
- " \" $name \" :$currentLine : assign end_line " .
6413
- $func -> name() . " \n " );
6414
- $func -> set_end_line($currentLine );
6415
- }
6416
- # we may not have set the end line above due to inconsistency
6417
- # but we also might not have line data
6418
- # - see .../tests/lcov/extract with gcc/4.8
6419
- if (!defined ($func -> end_line())) {
6420
- my $suffix =
6421
- lcovutil::explain_once(' derive_end_line' ,
6422
- " See lcovrc man entry for 'derive_function_end_line'." );
6423
-
6424
- lcovutil::ignorable_error(
6425
- $lcovutil::ERROR_INCONSISTENT_DATA ,
6426
- ' "' . $func -> filename() . ' ":' . $func -> line() .
6427
- ' : failed to set end line for function ' .
6428
- $func -> name() . ' .' . $suffix );
6429
- next FUNC;
6430
- }
6431
-
6432
- # now look for this function in each testcase -
6433
- # set the same endline (if not already set)
6434
- my $key = $func -> file() . ' :' . $first ;
6435
- foreach my $tn ($funcData -> keylist()) {
6436
- my $d = $funcData -> value($tn );
6437
- my $f = $d -> findKey($key );
6438
- if (defined ($f )) {
6439
- if (!defined ($f -> end_line())) {
6440
- $f -> set_end_line($func -> end_line());
6441
- } else {
6442
- if ($f -> end_line() != $func -> end_line()) {
6443
- lcovutil::ignorable_error(
6444
- $lcovutil::ERROR_INCONSISTENT_DATA ,
6445
- ' "' . $func -> file() .
6446
- ' ":' . $first . ' : function \' ' .
6447
- $func -> name() . ' last line is ' .
6448
- $func -> end_line() . ' but is ' .
6449
- $f -> end_line() . " in testcase '$tn '"
6450
- );
6451
- }
6452
- }
6453
- }
6454
- } # foreach testcase
6455
- } # for each function
6479
+ # try to derive end lines if at least one is unknown.
6480
+ # can't compute for lambdas because we can't distinguish
6481
+ # the last line reliably.
6482
+ $actions = DID_DERIVE
6483
+ if grep ({ !($_ -> isLambda() || defined ($_ -> end_line())) }
6484
+ $traceInfo -> func()-> valuelist());
6456
6485
}
6457
6486
6458
6487
# munge the source file name, if requested
6459
6488
# die("unexpected path substitution for '$source_file': '" .
6460
6489
# lcovutil::subst_file_name($source_file) . "'")
6461
6490
# unless ($source_file eq lcovutil::subst_file_name($source_file));
6462
6491
6463
- next
6464
- unless (
6465
- (defined ($lcovutil::func_coverage ) &&
6466
- (0 != scalar (@lcovutil::exclude_function_patterns ) ||
6467
- defined ($lcovutil::cov_filter [$FILTER_TRIVIAL_FUNCTION ]))
6468
- ) ||
6469
- (is_language(' c|perl|python|java' , $source_file ) &&
6470
- lcovutil::is_filter_enabled()));
6471
- push (@filter_workList , [$traceInfo , $name ]);
6492
+ if ((defined ($lcovutil::func_coverage ) &&
6493
+ (0 != scalar (@lcovutil::exclude_function_patterns ) ||
6494
+ defined ($lcovutil::cov_filter [$FILTER_TRIVIAL_FUNCTION ]))) ||
6495
+ (is_language(' c|perl|python|java' , $source_file ) &&
6496
+ lcovutil::is_filter_enabled())
6497
+ ) {
6498
+ # we are forking anyway - so also compute end lines there
6499
+ $actions |= DID_FILTER;
6500
+ push (@filter_workList , [$traceInfo , $name , $actions ]);
6501
+ } elsif (0 != $actions ) {
6502
+ # all we are doing is deriving function end lines - which doesn't
6503
+ # take long enough to be worth forking
6504
+ TraceFile::_deriveFunctionEndLines($traceInfo );
6505
+ }
6472
6506
} # foreach file
6473
6507
$self -> [STATE] |= DID_DERIVE;
6474
6508
@@ -7353,9 +7387,10 @@ sub merge
7353
7387
++$idx ;
7354
7388
}
7355
7389
lcovutil::info(" Using " .
7356
- scalar (@segments ) . ' segment' . (scalar (@segments ) > 1 ? ' s' : ' ' ) .
7357
- " of $testsPerSegment test" . ($testsPerSegment > 1 ? ' s' : ' ' ) .
7358
- " \n " );
7390
+ scalar (@segments ) .
7391
+ ' segment' . (scalar (@segments ) > 1 ? ' s' : ' ' ) .
7392
+ " of $testsPerSegment test" .
7393
+ ($testsPerSegment > 1 ? ' s' : ' ' ) . " \n " );
7359
7394
$lcovutil::profileData {config } = {}
7360
7395
unless exists ($lcovutil::profileData {config });
7361
7396
$lcovutil::profileData {config }{segments } = scalar (@segments );
0 commit comments