@@ -156,10 +156,6 @@ sub parse
156156 if (defined ($version ) && $version ne " " );
157157
158158 my $lineData = $fileInfo -> test($testname );
159- # use branch data to derive MC/DC expression - so need
160- # it, even if user didn't ask
161- my $branchData = $fileInfo -> testbr($testname )
162- if $lcovutil::br_coverage || $lcovutil::mcdc_coverage ;
163159 my $mcdcData = $fileInfo -> testcase_mcdc($testname )
164160 if $lcovutil::mcdc_coverage ;
165161
@@ -170,129 +166,239 @@ sub parse
170166 my $mcdc = $f -> {mcdc_records }
171167 if $lcovutil::mcdc_coverage && exists ($f -> {mcdc_records });
172168
173- foreach my $s (@$segments ) {
174- die (" unexpected segment data" ) unless scalar (@$s ) == 6;
175- my ($line , $col , $count , $hasCount , $isRegion , $isGap ) =
176- @$s ;
177- next unless $hasCount ;
178- $lineData -> append($line , $count );
169+ my $index = 0;
170+ my $currentLine = 0;
171+
172+ while ($index < $# $segments ) {
173+ my $segment = $segments -> [$index ];
174+ die (" unexpected segment data" )
175+ unless scalar (@$segment ) == 6;
176+ my ($line , $col , $count , $hasCount , $isRegionEntry , $isGap )
177+ = @$segment ;
178+ $currentLine = $line if !$currentLine ;
179+ if ($hasCount ) {
180+ $segment = $segments -> [$index + 1];
181+ die (" unexpected segment data" )
182+ unless scalar (@$segment ) == 6;
183+ my ($next_line , $next_col , $next_count , $next_hasCount ,
184+ $next_isRegionEntry , $next_isGap )
185+ = @$segment ;
186+ if ($currentLine == $next_line && !$next_isRegionEntry )
187+ {
188+ while ($next_line == $currentLine &&
189+ ++$index < $# $segments ) {
190+ $segment = $segments -> [$index + 1];
191+ die (" unexpected segment data" )
192+ unless scalar (@$segment ) == 6;
193+ $next_line = $segment -> [0];
194+ $count = $next_count
195+ if ($count &&
196+ $next_count > $count &&
197+ $currentLine == $next_line );
198+ $next_count = $segment -> [2];
199+ }
200+ $lineData -> append($currentLine , $count );
201+ ++$currentLine ;
202+ } else {
203+ my $bound = $next_line ;
204+ my $i = $index ;
205+ while (!$next_isRegionEntry &&
206+ $next_line == $bound &&
207+ ++$i < $# $segments ) {
208+ $segment = $segments -> [$i + 1];
209+ die (" unexpected segment data" )
210+ unless scalar (@$segment ) == 6;
211+ $next_line = $segment -> [0];
212+ $next_isRegionEntry = $segment -> [4];
213+ }
214+ --$bound
215+ if ($next_isRegionEntry &&
216+ $next_line == $bound &&
217+ !($isRegionEntry && $line == $next_line ));
218+ $count = $next_count
219+ if $next_count > $count && $line == $next_line ;
220+ while ($currentLine <= $bound ) {
221+ $lineData -> append($currentLine , $count );
222+ ++$currentLine ;
223+ }
224+ ++$index ;
225+ }
226+ } else {
227+ do {
228+ ++$index ;
229+ $segment = $segments -> [$index ];
230+ die (" unexpected segment data" )
231+ unless scalar (@$segment ) == 6;
232+ ($line , $col , $count , $hasCount ,
233+ $isRegionEntry , $isGap ) = @$segment ;
234+ } while (!$hasCount && $index < $# $segments );
235+ $currentLine = $isRegionEntry ? $line : $line + 1;
236+ }
179237 }
180-
181- if ($branchData ) {
182- my $currentLine = -1;
183- my $branchIdx ;
238+ if ($mcdc ) {
239+ my @mcdcBranches ; # array (start line, start column, expression)
184240 foreach my $branch (@$branches ) {
185241 die (" unexpected branch data" )
186242 unless scalar (@$branch ) == 9;
243+ # Consider only branches of "MCDCBranchRegion" kind.
244+ next if ($branch -> [-1] != 6);
187245 my ($line , $startCol , $endline ,
188246 $endcol , $trueCount , $falseCount ,
189247 $fileId , $expandedId , $kind ) = @$branch ;
190- if ($line != $currentLine &&
191- defined ($lineData -> value($line ))) {
192- $branchIdx = 0; # restart counter
193- $currentLine = $line ;
194- } else {
195- # this branch is part of the current group
196- ++$branchIdx ;
197- }
198248 my $expr =
199249 $srcReader -> getExpr($line , $startCol , $endline ,
200250 $endcol )
201251 if $srcReader -> notEmpty();
202-
203- my $br =
204- BranchBlock-> new($branchIdx , $trueCount , $expr );
205- $branchData -> append($line , 0, $br , $filename );
252+ push (@mcdcBranches , [$line , $startCol , $expr ]);
206253 }
207- }
208- if ($mcdc ) {
209254 foreach my $m (@$mcdc ) {
210- # what are fileID and kind?
211255 die (" unexpected MC/DC data" ) unless scalar (@$m ) == 7;
212- my ($line , $startCol , $endLine , $endcol , $fileId ,
256+ my ($line , $startCol , $endLine , $endCol , $expandedId ,
213257 $kind , $cov )
214258 = @$m ;
215259 die (" unexpected MC/DC cov" )
216260 unless ' ARRAY' eq ref ($cov );
217- my $groupSize = scalar (@$cov );
218261
219262 # read the source line and extract the expression...
220263 my $expr =
221264 $srcReader -> getExpr($line , $startCol , $endLine ,
222- $endcol )
265+ $endCol )
223266 if ($srcReader -> notEmpty());
224-
267+ my @brExprs ;
268+ foreach my $branch (@mcdcBranches ) {
269+ my ($brLine , $brCol , $brExpr ) = @$branch ;
270+ if (($brLine > $line ||
271+ ($brLine == $line && $brCol >= $startCol ))
272+ &&
273+ ($brLine < $endLine ||
274+ ($brLine == $endLine && $brCol <= $endCol ))
275+ ) {
276+ push (@brExprs , [$brLine , $brCol , $brExpr ]);
277+ }
278+ }
279+ @brExprs =
280+ sort { $a -> [0] <=> $b -> [0] || $a -> [1] <=> $b -> [1] }
281+ @brExprs ;
225282 my $current_mcdc =
226283 $mcdcData -> new_mcdc($mcdcData , $line );
227- my $branch = $branchData -> value( $line );
228- my $idx = 0;
284+ my $groupSize = scalar ( @$cov );
285+ my $idx = 0;
229286 foreach my $c (@$cov ) {
230- my $branchExpr =
231- $branch -> getBlock(0)-> [$idx ]-> expr()
232- if $branch &&
233- (scalar (@{$branch -> getBlock(0)}) > $idx );
234- $branchExpr =
235- defined ($branchExpr ) ?
236- " '$branchExpr ' in '$expr '" :
287+ my $branchExpr = $brExprs [$idx ]-> [2]
288+ if $groupSize == scalar (@brExprs );
289+ my $fullExpr =
290+ defined ($branchExpr ) &&
291+ defined ($expr ) ? " '$branchExpr ' in '$expr '" :
237292 $idx ;
238-
239293 $current_mcdc -> insertExpr($filename , $groupSize , 0,
240- $c , $idx , $branchExpr );
294+ $c , $idx , $fullExpr );
241295 $current_mcdc -> insertExpr($filename , $groupSize , 1,
242- $c , $idx , $branchExpr );
296+ $c , $idx , $fullExpr );
243297 ++$idx ;
244298 }
245299 $mcdcData -> close_mcdcBlock($current_mcdc );
246300 }
247- } # MCDC
248- $fileInfo -> testbr()-> remove($testname )
249- if $lcovutil::mcdc_coverage && !$lcovutil::br_coverage ;
301+ }
250302 lcovutil::info(2, " finished parsing $filename \n " );
251303 }
252304
253- next unless $lcovutil::func_coverage ;
254305 foreach my $f (@{$k -> {functions }}) {
255306 my $name = $f -> {name };
256307 my $filenames = $f -> {filenames }; # array
257- if ($# $filenames != 0) {
258- lcovutil::ignorable_error($lcovutil::ERROR_USAGE ,
259- " unsupported: function $name associated with multiple files"
260- );
261- next ;
262- }
263308 my $filename =
264309 ReadCurrentSource::resolve_path($filenames -> [0], 1);
265- if (TraceFile::skipCurrentFile($filename )) {
266- if (!exists ($lcovutil::excluded_files {$filename })) {
267- $lcovutil::excluded_files {$filename } = 1;
268- lcovutil::info(" Excluding $filename \n " );
269- }
270- next ;
271- }
310+ next if (TraceFile::skipCurrentFile($filename ));
272311 die (' unexpected unknown file \' ' . $filenames -> [0] . ' \' ' )
273312 unless $top -> file_exists($filename );
274- my $info = $top -> data($filename );
275- my $count = $f -> {count };
276- my $regions = $f -> {regions }; # startline/col, endline/col/
313+ $srcReader -> open ($filename );
314+
315+ my $info = $top -> data($filename );
316+ my $count = $f -> {count };
317+ my $regions = $f -> {regions }; # startline/col, endline/col/
318+ my $branches = $f -> {branches };
277319
278320 my $functionMap = $info -> testfnc($testname );
321+ # use branch data to derive MC/DC expression - so need
322+ # it, even if user didn't ask
323+ my $branchData = $info -> testbr($testname )
324+ if $lcovutil::br_coverage ;
279325 my $startLine = $regions -> [0]-> [0]; # startline of first region
280- # NOTE: might be a mistake to grab the end line of the last region -
281- # LCOV follows GCC behaviour and associates lines with where they
282- # start - not where they end...
283- my $endline = $regions -> [-1]-> [2]; # endline of last region
284- my $func =
285- $functionMap -> define_function($name , $startLine , $endline )
286- unless defined ($functionMap -> findName($name ));
287- $functionMap -> add_count($name , $count );
288-
289- # for the moment - don't worry about the coverpoints in the function
290- # my $branches = $f->{branches};
291- # my $mcdc = $f->{mcdc_records} if exists($f->{mcdc_records});
292- # foreach my $r (@$regions) {
293- # my ($startLine, $startCol, $endLine, $endCol, $count, $fileId,
294- # $expandedId, $kind) = @$r;
295- # }
326+ my $endline = $regions -> [0]-> [2]; # endline of last region
327+ if ($lcovutil::func_coverage ) {
328+ my $func =
329+ $functionMap -> define_function($name , $startLine ,
330+ $endline )
331+ unless defined ($functionMap -> findName($name ));
332+ $functionMap -> add_count($name , $count );
333+ }
334+ if ($branchData ) {
335+ my $funcBranchData = BranchData-> new();
336+ my $regionIdx = 0;
337+ foreach my $b (@$branches ) {
338+ die (" unexpected branch data" ) unless scalar (@$b ) == 9;
339+ my ($brStartLine , $brStartCol , $endLine ,
340+ $endCol , $trueCount , $falseCount ,
341+ $fileId , $expandedId , $kind ) = @$b ;
342+ my ($line , $col ) = ($brStartLine , $brStartCol );
343+ my $expr ;
344+
345+ if ($fileId == 0) {
346+ $expr =
347+ $srcReader -> getExpr($line , $col , $endLine ,
348+ $endCol )
349+ if $srcReader -> notEmpty();
350+ } else {
351+ # Find a source range, which contains the branch.
352+ while ($regionIdx < scalar (@$regions )) {
353+ my ($rStartLine , $rStartCol , $rEndLine ,
354+ $rEndCol , $rCount , $rFileId ,
355+ $rExpandedId , $rKind
356+ ) = @{$regions -> [$regionIdx ]};
357+ if ($rExpandedId == $fileId && $rKind == 1) {
358+ if ($rFileId != 0) {
359+ # Check previous regions to find one
360+ # that describes lines of the function's
361+ # source file.
362+ my $rIdx = $regionIdx - 1;
363+ $fileId = $rFileId ;
364+ while ($fileId != 0 && $rIdx >= 0) {
365+ ($rStartLine , $rStartCol ,
366+ $rEndLine , $rEndCol ,
367+ $rCount , $rFileId ,
368+ $rExpandedId , $rKind
369+ ) = @{$regions -> [$rIdx ]};
370+ $fileId = $rFileId
371+ if ($rExpandedId == $fileId &&
372+ $rKind == 1);
373+ --$rIdx ;
374+ }
375+ }
376+ ($line , $col ) = ($rStartLine , $rStartCol );
377+ last ;
378+ }
379+ ++$regionIdx ;
380+ }
381+ }
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 );
399+ }
400+ $branchData -> union($funcBranchData );
401+ }
296402 }
297403 }
298404 lcovutil::info(2, " finished $jsonFile \n " );
@@ -324,7 +430,8 @@ my %opts = ('test-name|t=s' => \$testname,
324430 ' output-filename|o=s' => \$output_filename ,);
325431my %rc_opts ;
326432if (!lcovutil::parseOptions(\%rc_opts , \%opts , \$output_filename )) {
327- print (STDERR " argparse failed" );
433+ print (STDERR " argparse failed\n " );
434+ exit (1);
328435}
329436
330437my $info = parse($testname , @ARGV );
0 commit comments