Skip to content

Commit d0128f9

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 d0128f9

File tree

6 files changed

+710
-85
lines changed

6 files changed

+710
-85
lines changed

bin/llvm2lcov

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

0 commit comments

Comments
 (0)