Skip to content

Commit b1cbb6d

Browse files
committed
Feature to select lines contained in [list of] SHAs/changelists.
See 'genhtml --select-script ...' Add file name and line number to 'select' callback. Clarify '--select-script' documentation. Signed-off-by: Henry Cox <[email protected]>
1 parent ef26ead commit b1cbb6d

File tree

4 files changed

+200
-34
lines changed

4 files changed

+200
-34
lines changed

bin/genhtml

Lines changed: 96 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3586,35 +3586,99 @@ sub _read_udiff
35863586
package InInterestingRegion;
35873587

35883588
use constant {
3589-
NEXT => 0,
3590-
PREV => 1,
3591-
STACK => 2,
3589+
NEXT => 0,
3590+
PREV => 1,
3591+
STACK => 2,
3592+
ANNOTATE_OBJ => 3,
3593+
LINECOV_HASH => 4,
3594+
# non-code line in a contiguous region before or after the
3595+
# 'interesting' code lie - should also be included -
3596+
# keep track of the length of that region, above and below
3597+
LINES_BEFORE => 5,
3598+
LINES_AFTER => 6,
3599+
35923600
};
35933601

35943602
our $num_context_lines = 5;
35953603

35963604
sub new
35973605
{
3598-
my $class = shift;
3599-
my $self = [undef, undef, Storable::dclone(\@_)];
3606+
my ($class, $srcFileStruct, $lineCovHash) = @_;
3607+
3608+
my $self = [undef, undef,
3609+
Storable::dclone($srcFileStruct->interesting_lines()),
3610+
$srcFileStruct, $lineCovHash
3611+
];
3612+
# we will call the $annotateObj->line(int) to collect annotate data
3613+
# for certain lines - to find out of a non-code line is in a
3614+
# continguous region by the same author, in the same SHA or etc.
36003615
$self->[NEXT] = shift(@{$self->[STACK]});
3616+
if (defined($self->[NEXT]) && $self->[NEXT] != 1) {
3617+
_computeContextBefore($self, 0);
3618+
}
36013619
return bless $self, $class;
36023620
}
36033621

3622+
sub _computeContextBefore
3623+
{
3624+
my ($self, $prev) = @_;
3625+
3626+
my $count = 0;
3627+
my $data = $self->[LINECOV_HASH];
3628+
my $annotate = $self->[ANNOTATE_OBJ];
3629+
# find contiguous source region which matches the select criteria.
3630+
# That might include non-code lined (e.g., commments)
3631+
for (my $l = $self->[NEXT] - 1; $l > $prev; --$l) {
3632+
my $lineData = $data->{$l} if exists($data->{$l});
3633+
my $annotateData = $annotate->line($l);
3634+
last
3635+
unless $selectCallback->select($lineData, $annotateData,
3636+
$self->[ANNOTATE_OBJ]->path(), $l);
3637+
++$count;
3638+
}
3639+
# region of interest is the (possibly empty) contigous region we found
3640+
# plus the number of context lines
3641+
$self->[LINES_BEFORE] = $num_context_lines + $count;
3642+
}
3643+
36043644
sub interesting
36053645
{
36063646
my ($self, $lineNum) = @_;
3647+
die("unexpected lineNum '$lineNum'") if $lineNum < 1;
36073648
if (defined($self->[NEXT])) {
36083649
if ($lineNum == $self->[NEXT]) {
36093650
$self->[PREV] = $self->[NEXT];
36103651
$self->[NEXT] = shift(@{$self->[STACK]});
3652+
# compute following context lines - starting from here
3653+
# and going to either end of file or next interesting line
3654+
my $max = defined($self->[NEXT]) ? $self->[NEXT] :
3655+
$self->[ANNOTATE_OBJ]->num_lines();
3656+
my $count = 0;
3657+
my $data = $self->[LINECOV_HASH];
3658+
my $annotate = $self->[ANNOTATE_OBJ];
3659+
for (my $l = $self->[PREV] + 1; $l < $max; ++$l) {
3660+
my $lineData = $data->{$l} if exists($data->{$l});
3661+
my $annotateData = $annotate->line($l);
3662+
last
3663+
if !$selectCallback->select($lineData, $annotateData,
3664+
$self->[ANNOTATE_OBJ]->path(), $l);
3665+
++$count;
3666+
}
3667+
$self->[LINES_AFTER] = $num_context_lines + $count;
3668+
3669+
# and how many lines before the next interesting one?
3670+
if (defined($self->[NEXT])) {
3671+
$self->_computeContextBefore($self->[PREV]);
3672+
} else {
3673+
$self->[LINES_BEFORE] = 0;
3674+
}
36113675
return 1;
3612-
} elsif ($lineNum >= $self->[NEXT] - $num_context_lines) {
3676+
} elsif ($lineNum >= $self->[NEXT] - $self->[LINES_BEFORE]) {
36133677
return 1;
36143678
}
36153679
}
36163680
if (defined($self->[PREV])) {
3617-
if ($lineNum <= $self->[PREV] + $num_context_lines) {
3681+
if ($lineNum <= $self->[PREV] + $self->[LINES_AFTER]) {
36183682
return 1;
36193683
}
36203684
$self->[PREV] = undef;
@@ -3784,20 +3848,36 @@ sub new
37843848
my @lineArray; # interesting line numbers
37853849
my $inRegion;
37863850
if (defined($selectCallback)) {
3851+
# This implementation looks for all the 'line' coverpoints - then
3852+
# expands the selected region around those points - e.g., by
3853+
# adding noncode lines which are in the selected changelist and
3854+
# surrounding the selected region with 'num_context_lines' of
3855+
# context.
3856+
# A side effect of this criteria is that disjoint noncode regions -
3857+
# e.g., comments or unused #ifdef code - will not be selected.
3858+
# A different implementation would go through the annotated source
3859+
# and mark all selected lines, then go through again to add
3860+
# context.
3861+
# It isn't clear which approach is best - but the current approach
3862+
# seems to match user expectations - so I'm going with it, at
3863+
# least for now.
3864+
# Not too hard to do - but significant overkill - to make the
3865+
# approach configurable. Let's see if there is user demand.
37873866
while (my ($line, $lne) = each(%$lineCovData)) {
37883867
# ignore deleted lines as they don't appear in source listing
37893868
my $tla = $lne->tla();
37903869
# no annotations for deleted line
37913870
my $annotateData = $self->line($line)
37923871
unless grep(/$tla/, ('DUB', 'DCB'));
37933872
# callback arguments are (LineData, SourceLine)
3794-
if ($selectCallback->select($lne, $annotateData)) {
3873+
if ($selectCallback->select($lne, $annotateData,
3874+
$self->path(), $line)) {
37953875
push(@lineArray, $line);
37963876
}
37973877
}
37983878
@lineArray = sort({ $a <=> $b } @lineArray);
37993879
$self->[INTERESTING_LINES] = \@lineArray;
3800-
$inRegion = InInterestingRegion->new(@lineArray);
3880+
$inRegion = InInterestingRegion->new($self, $lineCovData);
38013881
}
38023882
foreach my $line (sort({
38033883
my $ka =
@@ -4176,6 +4256,12 @@ sub lines
41764256
return $self->[LINES];
41774257
}
41784258

4259+
sub num_lines
4260+
{
4261+
my $self = shift;
4262+
return scalar(@{$self->[LINES]});
4263+
}
4264+
41794265
sub is_empty
41804266
{
41814267
my $self = shift;
@@ -11141,7 +11227,7 @@ sub write_source($$$$$$$)
1114111227

1114211228
my ($region, $empty);
1114311229
if ($selectCallback) {
11144-
$region = InInterestingRegion->new(@{$srcfile->interesting_lines()});
11230+
$region = InInterestingRegion->new($srcfile, $fileCovInfo->lineMap());
1114511231
$empty = '';
1114611232
if ($srcfile->isProjectFile()) {
1114711233
$empty .= ' ' x $main::age_field_width;

lib/lcovutil.pm

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2633,11 +2633,13 @@ sub check_criteria
26332633

26342634
sub select
26352635
{
2636-
my ($self, $lineData, $annotateData) = @_;
2636+
my ($self, $lineData, $annotateData, $filename, $lineNo) = @_;
26372637

2638-
my @params = ('select', JsonSupport::encode($lineData));
2639-
push(@params, JsonSupport::encode($annotateData))
2640-
if defined($annotateData);
2638+
my @params = (
2639+
'select',
2640+
JsonSupport::encode($lineData),
2641+
defined($annotateData) ? JsonSupport::encode($annotateData) : '',
2642+
$filename, $lineNo);
26412643
return $self->call(@params);
26422644
}
26432645

man/lcovrc.5

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2312,6 +2312,21 @@ The resolve script is called as:
23122312
[callback_args]
23132313
.I " file_name"
23142314
.PP
2315+
2316+
or
2317+
.IP
2318+
.I $resolve_callback =
2319+
.B resolve_module
2320+
.I ->new([callback_args])
2321+
.PP
2322+
to initialize the callback, then
2323+
.IP
2324+
.I $resolve_callback->
2325+
.B resolve
2326+
.I (file_name)
2327+
.PP
2328+
to find the actual file location.
2329+
23152330
If necessary, the callback can check the suffix of the filename to determine
23162331
whether it should look for either a source or data file.
23172332
.PP
@@ -2337,29 +2352,56 @@ Lines which are not selected but fall within
23372352
.I num_context_lines
23382353
of a selected line are also included in the report. See below.
23392354

2355+
Note that selection is fundamentally intended to show regions of code with soem surrounding context. It might not do what you expect if there is no code - e.g., if the region of interest has been compiled out via compiler or exclusion directives.
2356+
For example: when selecting based on SHA or changelist ID, an inserted comment will not be selected unless it is
2357+
.I num_context_lines
2358+
of an inserted or changed line of code.
2359+
23402360
The select script is called as:
23412361

23422362
.B " select_script"
23432363
[callback_args]
2344-
.I lineDataJson [annotateDataJson]
2364+
.I lineDataJson annotateDataJson filenName lineNumber
23452365

23462366
or as:
23472367

2348-
.B " select_module"
2349-
[callback_args]
2350-
.I lineDataRef [annotateDataRef]
2368+
.I " $selectCallback ="
2369+
.B select_module
2370+
.I ->new([callback_args])
2371+
2372+
to initialize the callback object, then as
2373+
2374+
.I " " $selectCallback
2375+
.B select
2376+
.I (lineDataRef annotateDataRef fileName lineNumber)
23512377

2378+
.RS
2379+
to determine selection,
23522380
where
2381+
.IP \- 3
2382+
.I fileName
2383+
is the name of the source file and
2384+
.PP
2385+
.IP \- 3
2386+
.I lineNumber
2387+
is the source file line number, indexed from zero,
2388+
.PP
2389+
.IP \- 3
23532390
.I lineDataJson
2354-
is a json-encoded LineData structure (see the lcovutil.pm source code) and
2355-
.I annoateDataJson
2391+
is a json-encoded LineData structure (see the lcovutil.pm source code), and
2392+
.PP
2393+
.IP \- 3
2394+
.I annotateDataJson
23562395
is the json-encoded data returned by your
23572396
.I annotate\-script
23582397
(see the
23592398
.I \-\-annotate\-script
23602399
parameter in man
23612400
.B genhtml(1).
2401+
), or the empty string if there are no annotations for this file.
2402+
.PP
23622403
The module callback is similar except that is is passed objects rather than JSON encodings of the objects.
2404+
.RE
23632405

23642406
The script should return "1" or "0".
23652407

0 commit comments

Comments
 (0)