35
35
# - enable MC/DC instrumentation in your compile/link steps, and
36
36
# - pass the '--mcdc-coverage' flag to llvm2lcov
37
37
#
38
+ # You can also use LLVM/21 or newer to generate MC/DC data more cleanly.
39
+ #
38
40
# See 'llvm2lcov --help' for more usage information
39
41
#
40
42
# See the LLVM documentation for more information on flags and compilation options.
41
43
42
44
use strict;
45
+ use version;
43
46
use warnings;
44
47
require Exporter;
45
48
@@ -131,6 +134,7 @@ sub parse
131
134
unless (defined ($json ) &&
132
135
exists ($json -> {data }) &&
133
136
' ARRAY' eq ref ($json -> {data }));
137
+ my $json_version = version-> parse($json -> {version });
134
138
135
139
lcovutil::info(" read $jsonFile \n " );
136
140
@@ -156,8 +160,6 @@ sub parse
156
160
if (defined ($version ) && $version ne " " );
157
161
158
162
my $lineData = $fileInfo -> test($testname );
159
- my $mcdcData = $fileInfo -> testcase_mcdc($testname )
160
- if $lcovutil::mcdc_coverage ;
161
163
162
164
my $summary = $f -> {summary };
163
165
my $branches = $f -> {branches };
@@ -235,7 +237,8 @@ sub parse
235
237
$currentLine = $isRegionEntry ? $line : $line + 1;
236
238
}
237
239
}
238
- if ($mcdc ) {
240
+ if ($mcdc && $json_version < version-> parse(" 3.0.1" )) {
241
+ my $mcdcData = $fileInfo -> testcase_mcdc($testname );
239
242
my @mcdcBranches ; # array (start line, start column, expression)
240
243
foreach my $branch (@$branches ) {
241
244
die (" unexpected branch data" )
@@ -316,12 +319,21 @@ sub parse
316
319
my $count = $f -> {count };
317
320
my $regions = $f -> {regions }; # startline/col, endline/col/
318
321
my $branches = $f -> {branches };
322
+ # The version "3.0.1" adds fileId to mcdc.
323
+ # This allows using MC/DC branches from expansions for placing MC/DC entries defined in expansions to expansions call sites.
324
+ my $mcdc = $f -> {mcdc_records }
325
+ if ($lcovutil::mcdc_coverage &&
326
+ $json_version >= version-> parse(" 3.0.1" ) &&
327
+ exists ($f -> {mcdc_records }));
319
328
320
329
my $functionMap = $info -> testfnc($testname );
321
330
# use branch data to derive MC/DC expression - so need
322
331
# it, even if user didn't ask
323
332
my $branchData = $info -> testbr($testname )
324
- if $lcovutil::br_coverage ;
333
+ if $lcovutil::br_coverage || $mcdc ;
334
+ my $mcdcData = $info -> testcase_mcdc($testname )
335
+ if ($json_version >= version-> parse(" 3.0.1" ) &&
336
+ $lcovutil::mcdc_coverage );
325
337
my $startLine = $regions -> [0]-> [0]; # startline of first region
326
338
my $endline = $regions -> [0]-> [2]; # endline of last region
327
339
if ($lcovutil::func_coverage ) {
@@ -331,6 +343,10 @@ sub parse
331
343
unless defined ($functionMap -> findName($name ));
332
344
$functionMap -> add_count($name , $count );
333
345
}
346
+
347
+ my @mcdcBranches ; # array (fileId, start line, start column, expression)
348
+ my %expanded_mcdcBranches ; # hash of branch's fileId -> branch's start line
349
+
334
350
if ($branchData ) {
335
351
my $funcBranchData = BranchData-> new();
336
352
my $regionIdx = 0;
@@ -379,26 +395,99 @@ sub parse
379
395
++$regionIdx ;
380
396
}
381
397
}
382
- # Processed branch on the same line doesn't have to be the previous.
383
- my $brEntry = $funcBranchData -> value($line );
384
- my $branchIdx =
385
- !defined ($brEntry ) ? 0 :
386
- scalar (@{$brEntry -> getBlock(0)});
387
- my $br =
388
- BranchBlock-> new($branchIdx , $trueCount ,
389
- !defined ($expr ) ? $branchIdx :
390
- " (" . $expr . " ) == True" );
391
- $funcBranchData -> append($line , 0, $br , $filename );
392
-
393
- ++$branchIdx ;
394
- $br =
395
- BranchBlock-> new($branchIdx , $falseCount ,
396
- !defined ($expr ) ? $branchIdx :
397
- " (" . $expr . " ) == False" );
398
- $funcBranchData -> append($line , 0, $br , $filename );
398
+ $fileId = $b -> [6];
399
+ # Consider only branches of "MCDCBranchRegion" kind.
400
+ if ($mcdc &&
401
+ $kind == 6 &&
402
+ !defined ($expanded_mcdcBranches {$fileId })) {
403
+ if ($fileId &&
404
+ scalar (@mcdcBranches ) &&
405
+ $fileId == $mcdcBranches [-1]-> [0]) {
406
+ pop (@mcdcBranches );
407
+ $expanded_mcdcBranches {$fileId } = $line ;
408
+ } else {
409
+ push (@mcdcBranches ,
410
+ [$fileId , $line , $col , $expr ]);
411
+ }
412
+ }
413
+
414
+ if ($lcovutil::br_coverage ) {
415
+ # Processed branch on the same line doesn't have to be the previous.
416
+ my $brEntry = $funcBranchData -> value($line );
417
+ my $branchIdx =
418
+ !defined ($brEntry ) ? 0 :
419
+ scalar (@{$brEntry -> getBlock(0)});
420
+ my $br =
421
+ BranchBlock-> new($branchIdx , $trueCount ,
422
+ !defined ($expr ) ? $branchIdx :
423
+ " (" . $expr . " ) == True" );
424
+ $funcBranchData -> append($line , 0, $br , $filename );
425
+
426
+ ++$branchIdx ;
427
+ $br =
428
+ BranchBlock-> new($branchIdx , $falseCount ,
429
+ !defined ($expr ) ? $branchIdx :
430
+ " (" . $expr . " ) == False" );
431
+ $funcBranchData -> append($line , 0, $br , $filename );
432
+ }
433
+ }
434
+ $branchData -> union($funcBranchData )
435
+ if $lcovutil::br_coverage ;
436
+ }
437
+ if ($mcdc ) {
438
+ foreach my $m (@$mcdc ) {
439
+ die (" unexpected MC/DC data" ) unless scalar (@$m ) == 10;
440
+ my ($line , $col , $endLine , $endCol ,
441
+ $trueCount , $falseCount , $fileId , $expandedId ,
442
+ $kind , $cov ) = @$m ;
443
+ die (" unexpected MC/DC cov" )
444
+ unless ' ARRAY' eq ref ($cov );
445
+ my $expr ;
446
+ my @brExprs ;
447
+ if ($fileId == $expandedId ) {
448
+ foreach my $branch (@mcdcBranches ) {
449
+ my ($brFileId , $brLine , $brCol , $brExpr ) =
450
+ @$branch ;
451
+ if (($brLine > $line ||
452
+ ($brLine == $line && $brCol >= $col ))
453
+ &&
454
+ ($brLine < $endLine ||
455
+ ($brLine == $endLine && $brCol <= $endCol ))
456
+ ) {
457
+ push (@brExprs , [$brLine , $brCol , $brExpr ]);
458
+ }
459
+ }
460
+ @brExprs = sort {$a -> [0] <=> $b -> [0] ||
461
+ $a -> [1] <=> $b -> [1]
462
+ } @brExprs ;
463
+ $expr =
464
+ $srcReader -> getExpr($line , $col ,
465
+ $endLine , $endCol )
466
+ if $srcReader -> notEmpty();
467
+ } else {
468
+ $line = $expanded_mcdcBranches {$fileId };
469
+ }
470
+ my $current_mcdc =
471
+ $mcdcData -> new_mcdc($mcdcData , $line );
472
+ my $groupSize = scalar (@$cov );
473
+ my $idx = 0;
474
+ foreach my $c (@$cov ) {
475
+ my $brExpr = $brExprs [$idx ]-> [2]
476
+ if ($fileId == $expandedId &&
477
+ $idx < scalar (@brExprs ));
478
+ my $fullExpr = defined ($brExpr ) &&
479
+ defined ($expr ) ? " '$brExpr ' in '$expr '" : $idx ;
480
+ $current_mcdc -> insertExpr($filename , $groupSize , 0,
481
+ $c , $idx , $fullExpr );
482
+ $current_mcdc -> insertExpr($filename , $groupSize , 1,
483
+ $c , $idx , $fullExpr );
484
+ ++$idx ;
485
+ }
486
+ $mcdcData -> close_mcdcBlock($current_mcdc );
399
487
}
400
- $branchData -> union($funcBranchData );
401
488
}
489
+ $info -> testbr()-> remove($testname )
490
+ if $mcdc && !$lcovutil::br_coverage ;
402
491
}
403
492
}
404
493
lcovutil::info(2, " finished $jsonFile \n " );
0 commit comments