Skip to content

Commit c2fd3ab

Browse files
committed
Bugfix: ignore lambdas during function end line derivation -
they would need to be found syntactically. Recommend user to upgrade to newer compiler. Signed-off-by: Henry Cox <[email protected]>
1 parent cbe14e8 commit c2fd3ab

File tree

7 files changed

+262
-6
lines changed

7 files changed

+262
-6
lines changed

lib/lcovutil.pm

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3441,12 +3441,25 @@ sub name
34413441
return $self->[NAME];
34423442
}
34433443

3444+
sub filename
3445+
{
3446+
my $self = shift;
3447+
return $self->[FILE];
3448+
}
3449+
34443450
sub hit
34453451
{
34463452
my $self = shift;
34473453
return $self->[COUNT];
34483454
}
34493455

3456+
sub isLambda
3457+
{
3458+
my $self = shift;
3459+
return (TraceFile::is_c_file($self->filename()) &&
3460+
$self->name() =~ /{lambda\(/);
3461+
}
3462+
34503463
sub count
34513464
{
34523465
my ($self, $alias, $merged) = @_;
@@ -6168,8 +6181,10 @@ sub applyFilters
61686181
is_c_file($source_file)) {
61696182
my @lines = sort { $a <=> $b } $traceInfo->sum()->keylist();
61706183
# sort functions by start line number
6184+
# ignore lambdas - which we don't process correctly at the moment
6185+
# (would need to do syntactic search for the end line)
61716186
my @functions = sort { $a->line() <=> $b->line() }
6172-
$traceInfo->func()->valuelist();
6187+
grep({ !$_->isLambda() } $traceInfo->func()->valuelist());
61736188

61746189
my $currentLine = @lines ? shift(@lines) : 0;
61756190
my $funcData = $traceInfo->testfnc();
@@ -6235,6 +6250,9 @@ sub applyFilters
62356250
$func->name() . "\n");
62366251
$func->set_end_line($currentLine);
62376252
}
6253+
die('failed to set end line for ' .
6254+
$func->name() . ' in file ' . $func->filename())
6255+
unless defined($func->end_line());
62386256
# now look for this function in each testcase -
62396257
# set the same endline (if not already set)
62406258
my $key = $func->file() . ':' . $first;

man/genhtml.1

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,7 +1748,7 @@ In the 'function coverage detail' table, also show the percentage of lines and b
17481748
This feature enables developers to focus attention on functions which have the largest effect on overall code coverage.
17491749

17501750
This feature is disabled by default.
1751-
Note that this option requires that you use a gcc version which is new enough to support function begin/end line reports or that you configure the tool to derive the required dta - see the
1751+
Note that this option requires that you use a compiler version which is new enough to support function begin/end line reports or that you configure the tool to derive the required data - see the
17521752
.BI derive_function_end_line
17531753
discussion in man
17541754
.B lcovrc(5).
@@ -1784,7 +1784,7 @@ Exclude coverage data from lines which fall within a function whose name matches
17841784
.B \-\-demangle\-cpp
17851785
option is used or not.
17861786

1787-
Note that this option requires that you use a gcc version which is new enough to support function begin/end line reports or that you configure the tool to derive the required dta - see the
1787+
Note that this option requires that you use a compiler version which is new enough to support function begin/end line reports or that you configure the tool to derive the required data - see the
17881788
.BI derive_function_end_line
17891789
discussion in man
17901790
.B lcovrc(5).
@@ -2280,8 +2280,10 @@ a link to a page which lists all functions found in that file plus the
22802280
respective call count for those functions.
22812281
The function coverage page groups the data for every alias of each function, sorted by name or execution count. The representative name of the group of functions is the shorted (i.e., containing the fewest characters).
22822282

2283-
If using differential coverage and a sufficiently recent gcc version which report both begin and end line of functions (gcc/9 and newer), functions are considered 'new' if any of their source lines have changed.
2284-
With older gcc versions, functions are considered 'new' if the function signature has changed or if the entire function is new.
2283+
If using differential coverage and a sufficiently recent compiler version which report both begin and end line of functions (
2284+
.I e.g.,
2285+
gcc/9 and newer), functions are considered 'new' if any of their source lines have changed.
2286+
With older compiler versions, functions are considered 'new' if the function signature has changed or if the entire function is new.
22852287

22862288
.RE
22872289
.B \-\-branch\-coverage

man/lcovrc.5

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,12 @@ Note that end lines are derived only for C/C++ files; see the
13091309
.I c_file_extensions
13101310
setting, above, for the list of extensions used to identify these files.
13111311
.br
1312+
Lambda functions are ignored during end line computation. Note that lambdas
1313+
are identified via function name matching - so you must enable demangling
1314+
if your toolchain is too old to report demangled names in the GCOV output.
1315+
See the
1316+
.I demangle_cpp
1317+
setting, above.
13121318

13131319
Default is 1.
13141320
.PP

tests/genhtml/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
include ../common.mak
22

3-
TESTS := full.sh part1.sh part2.sh target.sh zero.sh demangle.sh relative/
3+
TESTS := full.sh part1.sh part2.sh target.sh zero.sh demangle.sh relative lambda
44

55
clean:
66
rm -rf *.log out_* *.tmp

tests/genhtml/lambda/Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
include ../../common.mak
2+
3+
TESTS := lambda.sh
4+
5+
clean:
6+
$(shell ./lambda.sh --clean)

tests/genhtml/lambda/lambda.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// borrowed from https://en.cppreference.com/w/cpp/utility/functional/bind
2+
#include <functional>
3+
#include <iostream>
4+
#include <memory>
5+
#include <random>
6+
7+
void f(int n1, int n2, int n3, const int& n4, int n5)
8+
{
9+
std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
10+
}
11+
12+
int g(int n1)
13+
{
14+
return n1;
15+
}
16+
17+
struct Foo
18+
{
19+
void print_sum(int n1, int n2)
20+
{
21+
std::cout << n1 + n2 << '\n';
22+
}
23+
24+
int data = 10;
25+
};
26+
27+
int main()
28+
{
29+
using namespace std::placeholders; // for _1, _2, _3...
30+
31+
std::cout << "1) argument reordering and pass-by-reference: ";
32+
int n = 7;
33+
// (_1 and _2 are from std::placeholders, and represent future
34+
// arguments that will be passed to f1)
35+
auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
36+
n = 10;
37+
f1(1, 2, 1001); // 1 is bound by _1, 2 is bound by _2, 1001 is unused
38+
// makes a call to f(2, 42, 1, n, 7)
39+
40+
std::cout << "2) achieving the same effect using a lambda: ";
41+
n = 7;
42+
auto lambda = [&ncref = n, n](auto a, auto b, auto /*unused*/)
43+
{
44+
f(b, 42, a, ncref, n);
45+
};
46+
n = 10;
47+
lambda(1, 2, 1001); // same as a call to f1(1, 2, 1001)
48+
49+
std::cout << "3) nested bind subexpressions share the placeholders: ";
50+
auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
51+
f2(10, 11, 12); // makes a call to f(12, g(12), 12, 4, 5);
52+
53+
std::cout << "4) bind a RNG with a distribution: ";
54+
std::default_random_engine e;
55+
std::uniform_int_distribution<> d(0, 10);
56+
auto rnd = std::bind(d, e); // a copy of e is stored in rnd
57+
for (int n = 0; n < 10; ++n)
58+
std::cout << rnd() << ' ';
59+
std::cout << '\n';
60+
61+
std::cout << "5) bind to a pointer to member function: ";
62+
Foo foo;
63+
auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
64+
f3(5);
65+
66+
std::cout << "6) bind to a mem_fn that is a pointer to member function: ";
67+
auto ptr_to_print_sum = std::mem_fn(&Foo::print_sum);
68+
auto f4 = std::bind(ptr_to_print_sum, &foo, 95, _1);
69+
f4(5);
70+
71+
std::cout << "7) bind to a pointer to data member: ";
72+
auto f5 = std::bind(&Foo::data, _1);
73+
std::cout << f5(foo) << '\n';
74+
75+
std::cout << "8) bind to a mem_fn that is a pointer to data member: ";
76+
auto ptr_to_data = std::mem_fn(&Foo::data);
77+
auto f6 = std::bind(ptr_to_data, _1);
78+
std::cout << f6(foo) << '\n';
79+
80+
std::cout << "9) use smart pointers to call members of the referenced objects: ";
81+
std::cout << f6(std::make_shared<Foo>(foo)) << ' '
82+
<< f6(std::make_unique<Foo>(foo)) << '\n';
83+
}

tests/genhtml/lambda/lambda.sh

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#!/bin/bash
2+
3+
# lambda funciton extents
4+
set +x
5+
6+
CLEAN_ONLY=0
7+
COVER=
8+
9+
PARALLEL='--parallel 0'
10+
PROFILE="--profile"
11+
COVER_DB='cover_db'
12+
LOCAL_COVERAGE=1
13+
KEEP_GOING=0
14+
while [ $# -gt 0 ] ; do
15+
16+
OPT=$1
17+
shift
18+
case $OPT in
19+
20+
--clean | clean )
21+
CLEAN_ONLY=1
22+
;;
23+
24+
-v | --verbose | verbose )
25+
set -x
26+
;;
27+
28+
--keep-going )
29+
KEEP_GOING=1
30+
;;
31+
32+
--coverage )
33+
#COVER="perl -MDevel::Cover "
34+
if [[ "$1"x != 'x' && $1 != "-"* ]] ; then
35+
COVER_DB=$1
36+
LOCAL_COVERAGE=0
37+
shift
38+
fi
39+
COVER="perl -MDevel::Cover=-db,$COVER_DB,-coverage,statement,branch,condition,subroutine "
40+
;;
41+
42+
--home | -home )
43+
LCOV_HOME=$1
44+
shift
45+
if [ ! -f $LCOV_HOME/bin/lcov ] ; then
46+
echo "LCOV_HOME '$LCOV_HOME' does not exist"
47+
exit 1
48+
fi
49+
;;
50+
51+
--no-parallel )
52+
PARALLEL=''
53+
;;
54+
55+
--no-profile )
56+
PROFILE=''
57+
;;
58+
59+
* )
60+
echo "Error: unexpected option '$OPT'"
61+
exit 1
62+
;;
63+
esac
64+
done
65+
66+
if [[ "x" == ${LCOV_HOME}x ]] ; then
67+
if [ -f ../../../bin/lcov ] ; then
68+
LCOV_HOME=../../..
69+
else
70+
LCOV_HOME=../../../../releng/coverage/lcov
71+
fi
72+
fi
73+
LCOV_HOME=`(cd ${LCOV_HOME} ; pwd)`
74+
75+
if [[ ! ( -d $LCOV_HOME/bin && -d $LCOV_HOME/lib && -x $LCOV_HOME/bin/genhtml && ( -f $LCOV_HOME/lib/lcovutil.pm || -f $LCOV_HOME/lib/lcov/lcovutil.pm ) ) ]] ; then
76+
echo "LCOV_HOME '$LCOV_HOME' seems not to be invalid"
77+
exit 1
78+
fi
79+
80+
export PATH=${LCOV_HOME}/bin:${LCOV_HOME}/share:${PATH}
81+
export MANPATH=${MANPATH}:${LCOV_HOME}/man
82+
83+
ROOT=`pwd`
84+
PARENT=`(cd .. ; pwd)`
85+
86+
LCOV_OPTS="--branch $PARALLEL $PROFILE"
87+
# gcc/4.8.5 (and possibly other old versions) generate inconsistent line/function data
88+
IFS='.' read -r -a VER <<< `gcc -dumpversion`
89+
if [ "${VER[0]}" -lt 5 ] ; then
90+
IGNORE="--ignore inconsistent"
91+
# and filter exception branches to avoid spurious differences for old compiler
92+
FILTER='--filter branch'
93+
fi
94+
95+
rm -rf *.txt* *.json dumper* report lambda *.gcda *.gcno *.info
96+
97+
if [ "x$COVER" != 'x' ] && [ 0 != $LOCAL_COVERAGE ] ; then
98+
cover -delete
99+
fi
100+
101+
if [[ 1 == $CLEAN_ONLY ]] ; then
102+
exit 0
103+
fi
104+
105+
if ! type g++ >/dev/null 2>&1 ; then
106+
echo "Missing tool: g++" >&2
107+
exit 2
108+
fi
109+
110+
g++ -o lambda --coverage lambda.cpp -std=c++1y
111+
112+
./lambda
113+
if [ 0 != $? ] ; then
114+
echo "Error: 'lambda' returned error code"
115+
if [ $KEEP_GOING == 0 ] ; then
116+
exit 1
117+
fi
118+
fi
119+
120+
$COVER $LCOV_HOME/bin/lcov $LCOV_OPTS -o lambda.info --capture -d . --demangle --rc derive_function_end_line=0
121+
if [ 0 != $? ] ; then
122+
echo "Error: unexpected error code from lcov"
123+
if [ $KEEP_GOING == 0 ] ; then
124+
exit 1
125+
fi
126+
fi
127+
128+
129+
$COVER $LCOV_HOME/bin/genhtml $LCOV_OPTS -o report lambda.info --show-proportion
130+
if [ 0 != $? ] ; then
131+
echo "Error: unexpected error code from genhtml"
132+
if [ $KEEP_GOING == 0 ] ; then
133+
exit 1
134+
fi
135+
fi
136+
137+
echo "Tests passed"
138+
139+
if [ "x$COVER" != "x" ] && [ $LOCAL_COVERAGE == 1 ]; then
140+
cover
141+
fi

0 commit comments

Comments
 (0)