Skip to content

Commit 505b85b

Browse files
committed
Refactor 'llvm2lcov' utility
- Improve the algorithm for collecting line coverage data using segments: previously, only segment start lines were used for instrumentation, but lines between these start lines were not. - Add separate 'True' and 'False' branches as it is done for gcov. - Add branches defined in expansions (like macros). The entries were placed to expansions call sites. - Fixed some problems with MC/DC branch expressions. - Add branch expressions for multiline MC/DC entries. - Add support for JSON data format version '3.0.1', which adds 'fileId' to MC/DC entries. This allows using branches from expansions for placing MC/DC from expansions to the expansions call sites. It also helps to add correct expressions for some MC/DC branches belonging to groups that contain branches from expansions. Signed-off-by: Roman Beliaev <[email protected]>
1 parent cfce43e commit 505b85b

File tree

6 files changed

+687
-78
lines changed

6 files changed

+687
-78
lines changed

bin/llvm2lcov

Lines changed: 277 additions & 77 deletions
Large diffs are not rendered by default.

tests/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ all: check report
1212

1313
include common.mak
1414

15-
TESTS := genhtml lcov gendiffcov py2lcov perl2lcov xml2lcov
15+
TESTS := genhtml lcov gendiffcov llvm2lcov py2lcov perl2lcov xml2lcov
1616

1717
# there may or may not be some .info files generated for exported
1818
# tools - py2lcov, perl2lcov, etc. We want them included in the

tests/llvm2lcov/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 := llvm2lcov.sh
4+
5+
clean:
6+
$(shell ./llvm2lcov.sh --clean)

tests/llvm2lcov/llvm2lcov.sh

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
#!/bin/bash
2+
set +x
3+
4+
if [[ "x" == ${LCOV_HOME}x ]] ; then
5+
if [ -f ../../bin/lcov ] ; then
6+
LCOV_HOME=../..
7+
fi
8+
fi
9+
10+
source ../common.tst
11+
12+
rm -rf test *.profraw *.profdata *.json *.info report
13+
14+
clean_cover
15+
16+
if [[ 1 == $CLEAN_ONLY ]] ; then
17+
exit 0
18+
fi
19+
20+
LCOV_OPTS="--branch-coverage $PARALLEL $PROFILE"
21+
22+
clang++ -fprofile-instr-generate -fcoverage-mapping -fcoverage-mcdc -o test main.cpp
23+
if [ $? != 0 ] ; then
24+
echo "clang++ exec failed"
25+
exit 1
26+
fi
27+
./test
28+
llvm-profdata merge --sparse *.profraw -o test.profdata
29+
if [ $? != 0 ] ; then
30+
echo "llvm-profdata failed"
31+
exit 1
32+
fi
33+
llvm-cov export -format=text -instr-profile=test.profdata ./test > test.json
34+
if [ $? != 0 ] ; then
35+
echo "llvm-cov failed"
36+
exit 1
37+
fi
38+
39+
$COVER $LLVM2LCOV_TOOL --branch --mcdc -o test.info test.json
40+
if [ $? != 0 ] ; then
41+
echo "llvm2lcov failed"
42+
exit 1
43+
fi
44+
45+
# run again, excluding 'main.cpp'
46+
$COVER $LLVM2LCOV_TOOL --branch --mcdc -o test.excl.info test.json --exclude '*/main.cpp'
47+
if [ $? != 0 ] ; then
48+
echo "llvm2lcov --exclude failed"
49+
exit 1
50+
fi
51+
52+
# should be 3 functions
53+
N=`grep -c "FNA:" test.info`
54+
if [ 3 != "$N" ] ; then
55+
echo "wrong number of functions"
56+
exit 1
57+
fi
58+
59+
# look for expected location and function hit counts:
60+
for d in \
61+
'FNL:[0-9],18,23' \
62+
'FNA:[0-9],2,_Z3fooc' \
63+
'FNL:[0-9],25,69' \
64+
'FNA:[0-9],1,main' \
65+
'FNL:[0-9],2,4' \
66+
'FNA:[0-9],1,main.cpp:_ZL3barv' \
67+
; do
68+
grep -E $d test.info
69+
if [ 0 != $? ] ; then
70+
echo "did not find expected function data $d"
71+
if [ 0 == $KEEP_GOING ] ; then
72+
exit 1
73+
fi
74+
fi
75+
done
76+
77+
# lines main.cpp:(29-41) should be hit
78+
for line in $(seq 29 39) ; \
79+
do \
80+
grep -E "DA:$line,1" test.info
81+
if [ 0 != $? ] ; then
82+
echo "did not find expected hit on function line $line"
83+
if [ 0 == $KEEP_GOING ] ; then
84+
exit 1
85+
fi
86+
fi
87+
done
88+
89+
# lines main.cpp:14, 42-45 should be 'not hit
90+
for line in 14 42 43 44 45 ; do
91+
grep "DA:$line,0" test.info
92+
if [ 0 != $? ] ; then
93+
echo "did not find expected zero hit on function line $line"
94+
if [ 0 == $KEEP_GOING ] ; then
95+
exit 1
96+
fi
97+
fi
98+
done
99+
100+
# lines main.cpp:28, 40, 48, 62 should be 'not instrumented
101+
for line in 28 40 48 62 ; do
102+
grep "DA:$line" test.info
103+
if [ 0 == $? ] ; then
104+
echo "find unexpected instrumented line $line"
105+
if [ 0 == $KEEP_GOING ] ; then
106+
exit 1
107+
fi
108+
fi
109+
done
110+
111+
# check lines total number
112+
grep -E "LF:53$" test.info
113+
if [ $? != 0 ] ; then
114+
echo "unexpected total number of lines"
115+
if [ 0 == $KEEP_GOING ] ; then
116+
exit 1
117+
fi
118+
fi
119+
# check lines hit number
120+
grep -E "LH:48$" test.info
121+
if [ $? != 0 ] ; then
122+
echo "unexpected hit number of lines"
123+
if [ 0 == $KEEP_GOING ] ; then
124+
exit 1
125+
fi
126+
fi
127+
128+
# check that branches have right <branch> expressions
129+
N=`grep -c "BRDA:38," test.info`
130+
if [ 2 != "$N" ] ; then
131+
echo "did not find expected branches on line 38"
132+
if [ 0 == $KEEP_GOING ] ; then
133+
exit 1
134+
fi
135+
fi
136+
grep "BRDA:38,0,(i <= 0) == True,1" test.info
137+
if [ 0 != $? ] ; then
138+
echo "did not find expected 'BRDA' entry on line 38"
139+
if [ 0 == $KEEP_GOING ] ; then
140+
exit 1
141+
fi
142+
fi
143+
grep "BRDA:38,0,(i <= 0) == False,0" test.info
144+
if [ 0 != $? ] ; then
145+
echo "did not find expected 'BRDA' entry on line 38"
146+
if [ 0 == $KEEP_GOING ] ; then
147+
exit 1
148+
fi
149+
fi
150+
151+
# check that branches defined inside macros are instrumented right
152+
# lines main.cpp:30, 31, 34, 36 should contain branches defined inside macros
153+
for line in 30 31 34 36 ; do
154+
grep -E "BRDA:$line," test.info
155+
if [ 0 != $? ] ; then
156+
echo "did not find expected branches on line $line"
157+
if [ 0 == $KEEP_GOING ] ; then
158+
exit 1
159+
fi
160+
fi
161+
done
162+
163+
# check branches total number
164+
grep -E "BRF:52$" test.info
165+
if [ $? != 0 ] ; then
166+
echo "unexpected total number of branches"
167+
if [ 0 == $KEEP_GOING ] ; then
168+
exit 1
169+
fi
170+
fi
171+
# check branches hit number
172+
grep -E "BRH:33$" test.info
173+
if [ $? != 0 ] ; then
174+
echo "unexpected hit number of branches"
175+
if [ 0 == $KEEP_GOING ] ; then
176+
exit 1
177+
fi
178+
fi
179+
180+
JSON_VERSION=`grep -oE "[0-9]+\.[0-9]+\.[0-9]+" test.json`
181+
JSON_MAJOR_VERSION=`expr match "$JSON_VERSION" "\([0-9]*\)"`
182+
if [ $JSON_MAJOR_VERSION -ge 3 ]; then
183+
# line main.cpp:67 should contain 2 groups of MC/DC entries
184+
line=67
185+
MCDC_1=`grep -c "MCDC:$line,2," test.info`
186+
MCDC_2=`grep -c "MCDC:$line,3," test.info`
187+
if [ 4 != "$MCDC_1" ] || [ 6 != "$MCDC_2" ] ; then
188+
echo "did not find expected MC/DC entries on line $line"
189+
if [ 0 == $KEEP_GOING ] ; then
190+
exit 1
191+
fi
192+
fi
193+
# check that MC/DC entries have right <expressions>
194+
N=`grep -c "MCDC:37,2,[tf],0,1,'i <= 0' in 'BOOL(i > 0) || i <= 0)'" test.info`
195+
if [ 2 != "$N" ] ; then
196+
echo "did not find expected MC/DC entries on line 37"
197+
if [ 0 == $KEEP_GOING ] ; then
198+
exit 1
199+
fi
200+
fi
201+
# check MC/DC defined in macros
202+
grep -E "MCDC:" test.excl.info
203+
if [ 0 == $? ] ; then
204+
echo "find unexpected MC/DC"
205+
if [ 0 == $KEEP_GOING ] ; then
206+
exit 1
207+
fi
208+
fi
209+
for line in 31 34 36 ; do
210+
grep -E "MCDC:$line,2,[tf]" test.info
211+
if [ 0 != $? ] ; then
212+
echo "did not find expected MC/DC on line $line"
213+
if [ 0 == $KEEP_GOING ] ; then
214+
exit 1
215+
fi
216+
fi
217+
done
218+
# check MC/DC total number
219+
grep -E "MCF:38$" test.info
220+
if [ $? != 0 ] ; then
221+
echo "unexpected total number of MC/DC entries"
222+
if [ 0 == $KEEP_GOING ] ; then
223+
exit 1
224+
fi
225+
fi
226+
# check MC/DC hit number
227+
grep -E "MCH:10$" test.info
228+
if [ $? != 0 ] ; then
229+
echo "unexpected hit number of MC/DC entries"
230+
if [ 0 == $KEEP_GOING ] ; then
231+
exit 1
232+
fi
233+
fi
234+
else
235+
# line main.cpp:67 should contain 2 groups of MC/DC entries
236+
line=67
237+
MCDC_1=`grep -c "MCDC:$line,2," test.info`
238+
MCDC_2=`grep -c "MCDC:$line,3," test.info`
239+
if [ 4 != "$MCDC_1" ] || [ 6 != "$MCDC_2" ] ; then
240+
echo "did not find expected MC/DC entries on line $line"
241+
if [ 0 == $KEEP_GOING ] ; then
242+
exit 1
243+
fi
244+
fi
245+
# check that MC/DC entries have right <expressions>
246+
N=`grep -c "MCDC:60,2,[tf],1,1,'i < 1' in 'a\[i\] && i < 1'" test.info`
247+
if [ 2 != "$N" ] ; then
248+
echo "did not find expected MC/DC entries on line 60"
249+
if [ 0 == $KEEP_GOING ] ; then
250+
exit 1
251+
fi
252+
fi
253+
# check MC/DC defined in macros
254+
grep -E "MCDC:6,2,[tf]" test.excl.info
255+
if [ 0 != $? ] ; then
256+
echo "did not find expected MC/DC"
257+
if [ 0 == $KEEP_GOING ] ; then
258+
exit 1
259+
fi
260+
fi
261+
for m in \
262+
"MCDC:6,2,[tf]" \
263+
"MCDC:15,2,[tf]" \
264+
; do
265+
grep -E $m test.info
266+
if [ 0 != $? ] ; then
267+
echo "did not find expected MC/DC"
268+
if [ 0 == $KEEP_GOING ] ; then
269+
exit 1
270+
fi
271+
fi
272+
done
273+
# check MC/DC total number
274+
grep -E "MCF:34$" test.info
275+
if [ $? != 0 ] ; then
276+
echo "unexpected total number of MC/DC entries"
277+
if [ 0 == $KEEP_GOING ] ; then
278+
exit 1
279+
fi
280+
fi
281+
# check MC/DC hit number
282+
grep -E "MCH:10$" test.info
283+
if [ $? != 0 ] ; then
284+
echo "unexpected hit number of MC/DC entries"
285+
if [ 0 == $KEEP_GOING ] ; then
286+
exit 1
287+
fi
288+
fi
289+
fi
290+
291+
# should be valid data to generate HTML
292+
$COVER $GENHTML_TOOL --flat --branch --mcdc -o report test.info
293+
if [ $? != 0 ] ; then
294+
echo "genhtml failed"
295+
if [ 0 == $KEEP_GOING ] ; then
296+
exit 1
297+
fi
298+
fi
299+
300+
# generate help message
301+
$COVER ${EXEC_COVER} $LLVM2LCOV_TOOL --help
302+
if [ 0 != $? ] ; then
303+
echo "llvm2lcov help failed"
304+
if [ 0 == $KEEP_GOING ] ; then
305+
exit 1
306+
fi
307+
fi
308+
309+
# incorrect option
310+
$COVER ${EXEC_COVER} $LLVM2LCOV_TOOL --unsupported
311+
$COVER $LLVM2LCOV_TOOL --unsupported -o test.info test.json
312+
if [ 0 == $? ] ; then
313+
echo "did not see incorrect option"
314+
if [ 0 == $KEEP_GOING ] ; then
315+
exit 1
316+
fi
317+
fi
318+
319+
echo "Tests passed"
320+
321+
if [ "x$COVER" != "x" ] && [ $LOCAL_COVERAGE == 1 ]; then
322+
echo "Tests passed"
323+
cover
324+
$PERL2LCOV_TOOL -o ${COVER_DB}/perlcov.info ${COVER_DB}
325+
$GENHTML_TOOL -o ${COVER_DB}/report ${COVER_DB}/perlcov.info --flat --show-navigation --branch
326+
fi

0 commit comments

Comments
 (0)