Skip to content

Commit c062292

Browse files
committed
Enhance 'function' filter to be persistent (stored in .info file).
This causes a change to the .info file format. The change is forward compatible but not backward compatible: newer lcov vesions can read data generated by older versions but old versions likely cannot read data generated by the new version. Signed-off-by: Henry Cox <[email protected]>
1 parent 8800a12 commit c062292

File tree

17 files changed

+218
-103
lines changed

17 files changed

+218
-103
lines changed

bin/genhtml

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4483,8 +4483,6 @@ sub _countFunctionTlaData
44834483
my %foundFunctionTlas;
44844484
my ($src_age, $developer, $srcLine);
44854485

4486-
my $merged =
4487-
defined($lcovutil::cov_filter[$lcovutil::FILTER_FUNCTION_ALIAS]);
44884486
my $h = $func->hit();
44894487
my $mergedTla = $h->[1];
44904488
# LCOV_EXCL_START
@@ -4514,7 +4512,7 @@ sub _countFunctionTlaData
45144512
}
45154513
}
45164514

4517-
if ($merged) {
4515+
if ($main::merge_function_aliases) {
45184516
_accountFunction($fileSummary, $mergedTla, $src_age);
45194517
} else {
45204518
my $aliases = $func->aliases();
@@ -5165,15 +5163,14 @@ sub new
51655163
# $covtype: 'line' or 'branch'
51665164
my ($class, $testcaseCounts, $fileDetails, $covtype) = @_;
51675165

5168-
my $merged =
5169-
defined($lcovutil::cov_filter[$lcovutil::FILTER_FUNCTION_ALIAS]);
51705166
my %tlaData;
51715167
if ($covtype != SummaryInfo::FUNCTION_DATA) {
51725168
$tlaData{found} = $testcaseCounts->found();
51735169
$tlaData{hit} = $testcaseCounts->hit();
51745170
} else {
5175-
$tlaData{found} = $testcaseCounts->numFunc($merged);
5176-
$tlaData{hit} = $testcaseCounts->numHit($merged);
5171+
$tlaData{found} =
5172+
$testcaseCounts->numFunc($main::merge_function_aliases);
5173+
$tlaData{hit} = $testcaseCounts->numHit($main::merge_function_aliases);
51775174
}
51785175
if ($main::show_tla &&
51795176
defined($fileDetails)) {
@@ -5219,7 +5216,7 @@ sub new
52195216
my $lineData = $fileDetails->line($line);
52205217
my $differential = $lineData->functionElem();
52215218
my @data;
5222-
if ($merged) {
5219+
if ($main::merge_function_aliases) {
52235220
push(@data, $differential->hit());
52245221
} else {
52255222
my $aliases = $differential->aliases();
@@ -6174,6 +6171,7 @@ our $frames; # If set, use frames for source code view
61746171
our $keep_descriptions; # If set, do not remove unused test case descriptions
61756172
our $suppress_function_aliases; # if set, don't show list of collapsed
61766173
# function aliases
6174+
our $merge_function_aliases;
61776175
our $no_sourceview; # If set, do not create a source code view for each file
61786176
our $legend; # If set, include legend in output
61796177
our $tab_size = 8; # Number of spaces to use in place of tab
@@ -6192,7 +6190,7 @@ our @fileview_prefixes = ("");
61926190
our @funcview_sortlist;
61936191
our @rate_name = ("Lo", "Med", "Hi");
61946192
our @rate_png = ("ruby.png", "amber.png", "emerald.png");
6195-
our $rc_desc_html = 0; # lcovrc: genhtml_desc_html
6193+
our $rc_desc_html = 0; # lcovrc: genhtml_desc_html
61966194
our $deprecated_highlight; # ignored former option
61976195

61986196
our $cwd = cwd(); # Current working directory
@@ -6248,6 +6246,8 @@ my %genhtml_rc_opts = (
62486246
"genhtml_sort" => \$sort,
62496247
"genhtml_charset" => \$charset,
62506248
"genhtml_desc_html" => \$rc_desc_html,
6249+
'merge_function_aliases' => \$merge_function_aliases,
6250+
'suppress_function_aliases' => \$suppress_function_aliases,
62516251
"genhtml_missed" => \$opt_missed,
62526252
"genhtml_dark_mode" => \$dark_mode,
62536253
"genhtml_hierarchical" => \$hierarchical,
@@ -6318,13 +6318,18 @@ my %genhtml_options = ("output-directory|o=s" => \$output_directory,
63186318
"dark-mode" => \$dark_mode,
63196319
"show-navigation" => \$show_tla,
63206320
"show-proportion" => \$show_functionProportions,
6321+
"merge-aliases" => \$merge_function_aliases,
63216322
"suppress-aliases" => \$suppress_function_aliases,);
63226323
# Parse command line options
63236324
if (!lcovutil::parseOptions(\%genhtml_rc_opts, \%genhtml_options)) {
63246325
print(STDERR "Use $tool_name --help to get usage information\n");
63256326
exit(1);
63266327
}
63276328

6329+
$merge_function_aliases = 1
6330+
if ($suppress_function_aliases ||
6331+
defined($lcovutil::cov_filter[$lcovutil::FILTER_FUNCTION_ALIAS]));
6332+
63286333
lcovutil::ignorable_error($lcovutil::ERROR_DEPRECATED,
63296334
"option '--highlight' has been removed.")
63306335
if ($deprecated_highlight);
@@ -12131,9 +12136,8 @@ sub write_function_table(*$$$$$$$$$$)
1213112136
</tr>
1213212137
END_OF_HTML
1213312138

12134-
my $merged =
12135-
defined($lcovutil::cov_filter[$lcovutil::FILTER_FUNCTION_ALIAS]);
12136-
foreach my $func (funcview_get_sorted($funcData, $type, $merged)) {
12139+
foreach my $func (
12140+
funcview_get_sorted($funcData, $type, $main::merge_function_aliases)) {
1213712141

1213812142
my $funcEntry = $differentialMap->{$func};
1213912143
my ($count, $tla) = @{$funcEntry->hit()};

bin/geninfo

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,17 +1001,8 @@ package main;
10011001
# TN:<test name>
10021002
#
10031003
# For each source file name referenced in the data file, there is a section
1004-
# containing source code and coverage data:
1005-
#
1006-
# SF:<absolute path to the source file>
1007-
# FN:<line number of function start>,<function name> for each function
1008-
# DA:<line number>,<execution count> for each instrumented line
1009-
# LH:<number of lines with an execution count> greater than 0
1010-
# LF:<number of instrumented lines>
1011-
#
1012-
# Sections are separated by:
1013-
#
1014-
# end_of_record
1004+
# containing source code and coverage data. See geninfo(1) man page for
1005+
# more details.
10151006
#
10161007
# In addition to the main source code file there are sections for each
10171008
# #included file containing executable code. Note that the absolute path

bin/xml2lcovutil.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,11 +450,14 @@ def buildFunction(functions, objStack, currentObj, lastLine):
450450
break
451451

452452
# print the LCOV function data
453+
idx = 0
453454
for f in functions:
454455
totals['function'][0] += 1
456+
f['idx'] = idx
457+
idx += 1
455458
if f['hit']:
456459
totals['function'][1] += 1
457-
self._outf.write("FN:%(start)d,%(end)d,%(name)s\nFNDA:%(hit)d,%(name)s\n" % f)
460+
self._outf.write("FNL:%(idx)d,%(start)d,%(end)d\nFNA:%(idx)d,%(hit)d,%(name)s\n" % f)
458461
# print the LCOV line data.
459462
for lineNo in sorted(lineData.keys()):
460463
checksum = ''

lcovrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ genhtml_desc_html=0
201201
# Show missed counts instead of hit counts
202202
#genhtml_missed=1
203203

204+
# group function aliases in report - see '--merge' section in man(1) genhtml
205+
#merge_function_aliasess = 1
206+
204207
# If set, suppress list of aliases in function detail table
205208
#suppress_function_aliases = 1
206209

lib/lcovutil.pm

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7161,6 +7161,7 @@ sub _read_info
71617161
my $functionMap;
71627162
my %excludedFunction;
71637163
my $skipCurrentFile = 0;
7164+
my %fnIdxMap;
71647165
while (<$infoHdl>) {
71657166
chomp($_);
71667167
my $line = $_;
@@ -7191,6 +7192,7 @@ sub _read_info
71917192
# Retrieve data for new entry
71927193
%nextBranchId = ();
71937194
%excludedFunction = ();
7195+
%fnIdxMap = ();
71947196

71957197
if ($verify_checksum) {
71967198
# unconditionally 'close' the current file - in case we don't
@@ -7364,6 +7366,32 @@ sub _read_info
73647366
last;
73657367
};
73667368

7369+
# new format...
7370+
/^FNL:(\d+),(\d+)(,(\d+))?$/ && do {
7371+
last if (!$lcovutil::func_coverage);
7372+
my $fnIndex = $1;
7373+
my $lineNo = $2;
7374+
my $end_line = $4;
7375+
die("unexpected duplicate index $fnIndex")
7376+
if exists($fnIdxMap{$fnIndex});
7377+
$fnIdxMap{$fnIndex} = [$lineNo, $end_line];
7378+
last;
7379+
};
7380+
7381+
/^FNA:(\d+),([^,]+),(.+)$/ && do {
7382+
last if (!$lcovutil::func_coverage);
7383+
my $fnIndex = $1;
7384+
my $hit = $2;
7385+
my $alias = $3;
7386+
die("unknown index $fnIndex")
7387+
unless exists($fnIdxMap{$fnIndex});
7388+
my ($lineNo, $end_line) = @{$fnIdxMap{$fnIndex}};
7389+
my $fn =
7390+
$functionMap->define_function($alias, $lineNo, $end_line);
7391+
$fn->addAlias($alias, $hit);
7392+
last;
7393+
};
7394+
73677395
/^BRDA:(\d+),(e?)(\d+),(.+)$/ && do {
73687396
last if (!$lcovutil::br_coverage);
73697397

@@ -7594,15 +7622,14 @@ sub write_info($$$)
75947622
cmp $functionMap->findKey($b)->line() or
75957623
$a cmp $b } $functionMap->keylist());
75967624

7625+
my $fnIndex = -1;
7626+
my $f_found = 0;
7627+
my $f_hit = 0;
75977628
foreach my $key (@functionOrder) {
7598-
my $data = $functionMap->findKey($key);
7599-
my $line = $data->line();
7600-
7629+
my $data = $functionMap->findKey($key);
76017630
my $aliases = $data->aliases();
7602-
my $endLine =
7603-
defined($data->end_line()) ?
7604-
',' . $data->end_line() :
7605-
'';
7631+
my $line = $data->line();
7632+
76067633
if ($line <= 0) {
76077634
my $alias = (sort keys %$aliases)[0];
76087635
lcovutil::ignorable_error(
@@ -7611,22 +7638,21 @@ sub write_info($$$)
76117638
);
76127639
next;
76137640
}
7614-
foreach my $alias (sort keys %$aliases) {
7615-
print(INFO_HANDLE "FN:$line$endLine,$alias\n");
7616-
}
7617-
}
7618-
my $f_found = 0;
7619-
my $f_hit = 0;
7620-
foreach my $key (@functionOrder) {
7621-
my $data = $functionMap->findKey($key);
7622-
my $line = $data->line();
7623-
next unless $line > 0;
7624-
my $aliases = $data->aliases();
7641+
++$fnIndex;
7642+
my $endLine =
7643+
defined($data->end_line()) ?
7644+
',' . $data->end_line() :
7645+
'';
7646+
# print function leader
7647+
print(INFO_HANDLE "FNL:$fnIndex,$line$endLine\n");
7648+
++$f_found;
7649+
my $counted = 0;
76257650
foreach my $alias (sort keys %$aliases) {
76267651
my $hit = $aliases->{$alias};
7627-
++$f_found;
7628-
++$f_hit if $hit > 0;
7629-
print(INFO_HANDLE "FNDA:$hit,$alias\n");
7652+
++$f_hit if $hit > 0 && !$counted;
7653+
$counted ||= $hit > 0;
7654+
# print the alias
7655+
print(INFO_HANDLE "FNA:$fnIndex,$hit,$alias\n");
76307656
}
76317657
}
76327658
print(INFO_HANDLE "FNF:$f_found\n");

man/genhtml.1

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ genhtml \- Generate HTML view from LCOV coverage data files
9797
.IR num ]
9898
.RB [ \-\-missed ]
9999
.br
100+
.RB [ \-\-merge\-aliases ]
101+
.br
100102
.RB [ \-\-suppress\-aliases ]
101103
.br
102104
.RB [ \-\-forget\-test\-names ]
@@ -2187,7 +2189,7 @@ whose body is empty/do not contain any statements. Commonly, these include comp
21872189

21882190
Note that the
21892191
.I trivial
2190-
filter requires function end line information - and so requires that you use a compiler veraion which is new enough to support begin/end line reports
2192+
filter requires function end line information - and so requires that you use a compiler version which is new enough to support begin/end line reports
21912193
(
21922194
.I e.g.,
21932195
gcc/9 or newer) or that you enable lcov/genhtml/geninfo to derive the information:
@@ -2923,6 +2925,28 @@ option
29232925
.IR genhtml_precision .
29242926
.RE
29252927

2928+
.B \-\-merge\-aliases
2929+
.RS
2930+
Functions whose file/line is the same are considered to be aliases;
2931+
.B genthml
2932+
uses the shortest name in the list of aliases (fewest characters) as the leader.
2933+
.br
2934+
This option counts each alias group as a single object - so the 'function'
2935+
count will be the number of distinct function groups rather than the total number
2936+
of aliases of all functions - and displays them as groups in the 'function detail
2937+
table.
2938+
.br
2939+
Note that this option has an effect only if
2940+
.B "\-\-filter function"
2941+
has been applied to the coverage DB.
2942+
.br
2943+
2944+
This parameter an be configured via the configuration file
2945+
.IR merge_function_aliases
2946+
option. See
2947+
.B man(5) lcovrc.
2948+
2949+
29262950
.B \-\-suppress\-aliases
29272951
.RS
29282952
Suppress list of aliases in function detail table.
@@ -2935,14 +2959,14 @@ uses the shortest name in the list of aliases (fewest characters) as the leader.
29352959

29362960
The number of aliases can be large, for example due to instantiated templates - which can make function coverage results difficult to read. This option removes the list of aliases, making it easier to focus on the overall function coverage number, which is likely more interesting.
29372961

2938-
Note that this option has an effect only when
2939-
.B \-\-filter
2940-
function is applied.
2962+
Note that this option has an effect only if
2963+
.B "\-\-filter function"
2964+
has been applied to the coverage DB.
29412965

2942-
This option can also be configured permanently using the configuration file
2943-
option
2944-
.IR suppress_function_aliases .
2945-
.RE
2966+
This parameter an be configured via the configuration file
2967+
.IR merge_function_aliases
2968+
option. See
2969+
.B man(5) lcovrc.
29462970

29472971

29482972
.B \-\-forget\-test\-names

man/geninfo.1

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,8 +1332,32 @@ See the
13321332
.BI "\-\-version\-script " callback_script
13331333
documentation and the sample usage in the lcov regression test examples.
13341334

1335-
Following is a list of line numbers for each function name found in the
1336-
source file:
1335+
Function converage data follows.
1336+
Note that the format of the function coverage data has changed from LCOV 2.2 onward.
1337+
The tool continues to be able to read the old format but now writes only the
1338+
new format.
1339+
This change was made so that
1340+
.B function
1341+
filter outcome is persistent in the generated tracefile.
1342+
1343+
Functions and their aliases are recorded contiguously:
1344+
1345+
First, the leader:
1346+
1347+
.RS
1348+
FNL:<index>,<line number of function start>[,line number of function end>]
1349+
.RE
1350+
1351+
Then the aliases of the function; there will be at least one alias. All aliases of a particular function share the same index.
1352+
1353+
.RS
1354+
FNA:<index>,<execution count>,<name>
1355+
.RE
1356+
1357+
1358+
The now-obsolete function data format is:
1359+
1360+
.RS
13371361

13381362
.RS
13391363
FN:<line number of function start>,[<line number of function end>,]<function name>
@@ -1352,6 +1376,7 @@ Next, there is a list of execution counts for each instrumented function:
13521376
.RS
13531377
FNDA:<execution count>,<function name>
13541378
.RE
1379+
.RE
13551380

13561381
This list is followed by two lines containing the number of functions found
13571382
and hit:
@@ -1362,6 +1387,8 @@ FNF:<number of functions found>
13621387
FNH:<number of function hit>
13631388
.RE
13641389

1390+
Note that, as of LCOV 2.2, these numbers count function groups - not the individual aliases.
1391+
13651392
Branch coverage information is stored which one line per branch:
13661393

13671394
.RS

0 commit comments

Comments
 (0)