@@ -58,26 +58,37 @@ class goto_program_coverage_recordt:public coverage_recordt
58
58
protected:
59
59
irep_idt file_name;
60
60
61
- struct line_coverage_recordt
61
+ struct coverage_conditiont
62
62
{
63
- line_coverage_recordt ():
64
- hits (0 ), is_branch(false ), branch_covered(false )
63
+ coverage_conditiont ():
64
+ false_taken (false ), true_taken(false )
65
+ {
66
+ }
67
+
68
+ bool false_taken;
69
+ bool true_taken;
70
+ };
71
+
72
+ struct coverage_linet
73
+ {
74
+ coverage_linet ():
75
+ hits (0 )
65
76
{
66
77
}
67
78
68
79
unsigned hits;
69
- bool is_branch;
70
- bool branch_covered ;
80
+ std::map<goto_programt::const_targett, coverage_conditiont>
81
+ conditions ;
71
82
};
72
83
73
- typedef std::map<unsigned , line_coverage_recordt >
74
- line_coverage_mapt ;
84
+ typedef std::map<unsigned , coverage_linet >
85
+ coverage_lines_mapt ;
75
86
76
- void compute_line_coverage (
87
+ void compute_coverage_lines (
77
88
const goto_programt &goto_program,
78
89
const irep_idt &file_name,
79
90
const symex_coveraget::coveraget &coverage,
80
- line_coverage_mapt &dest);
91
+ coverage_lines_mapt &dest);
81
92
};
82
93
83
94
/* ******************************************************************\
@@ -92,17 +103,26 @@ Function: rate
92
103
93
104
\*******************************************************************/
94
105
95
- static std::string rate (std::size_t covered, std::size_t total)
106
+ static std::string rate (
107
+ std::size_t covered,
108
+ std::size_t total,
109
+ bool per_cent=false )
96
110
{
111
+ std::ostringstream oss;
112
+
97
113
#if 1
98
- if (total==0 )
99
- return " 1.0" ;
114
+ float fraction;
100
115
101
- std::ostringstream oss;
116
+ if (total==0 )
117
+ fraction=1.0 ;
118
+ else
119
+ fraction=static_cast <float >(covered)/static_cast <float >(total);
102
120
103
- oss << static_cast <float >(covered)/static_cast <float >(total);
121
+ if (per_cent)
122
+ oss << fraction*100.0 << ' %' ;
123
+ else
124
+ oss << fraction;
104
125
#else
105
- std::ostringstream oss;
106
126
oss << covered << " of " << total;
107
127
#endif
108
128
@@ -138,12 +158,12 @@ goto_program_coverage_recordt::goto_program_coverage_recordt(
138
158
assert (!file_name.empty ());
139
159
140
160
// compute the maximum coverage of individual source-code lines
141
- line_coverage_mapt line_coverage_map ;
142
- compute_line_coverage (
161
+ coverage_lines_mapt coverage_lines_map ;
162
+ compute_coverage_lines (
143
163
gf_it->second .body ,
144
164
file_name,
145
165
coverage,
146
- line_coverage_map );
166
+ coverage_lines_map );
147
167
148
168
// <method name="foo" signature="int(int)" line-rate="1.0" branch-rate="1.0">
149
169
// <lines>
@@ -173,28 +193,43 @@ goto_program_coverage_recordt::goto_program_coverage_recordt(
173
193
174
194
xmlt &lines=xml.new_element (" lines" );
175
195
176
- for (line_coverage_mapt::const_iterator
177
- it=line_coverage_map.begin ();
178
- it!=line_coverage_map.end ();
179
- ++it)
196
+ for (const auto &cov_line : coverage_lines_map)
180
197
{
181
198
xmlt &line=lines.new_element (" line" );
182
199
183
- line.set_attribute (" number" , std::to_string (it-> first ));
184
- line.set_attribute (" hits" , std::to_string (it-> second .hits ));
185
- if (!it-> second .is_branch )
200
+ line.set_attribute (" number" , std::to_string (cov_line. first ));
201
+ line.set_attribute (" hits" , std::to_string (cov_line. second .hits ));
202
+ if (cov_line. second .conditions . empty () )
186
203
line.set_attribute (" branch" , " false" );
187
204
else
188
205
{
189
- // TODO: conditions
190
206
line.set_attribute (" branch" , " true" );
207
+
208
+ xmlt &conditions=line.new_element (" conditions" );
209
+
210
+ std::size_t number=0 , total_taken=0 ;
211
+ for (const auto &c : cov_line.second .conditions )
212
+ {
213
+ // <condition number="0" type="jump" coverage="50%"/>
214
+ xmlt &condition=conditions.new_element (" condition" );
215
+ condition.set_attribute (" number" , std::to_string (number++));
216
+ condition.set_attribute (" type" , " jump" );
217
+ unsigned taken=c.second .false_taken +c.second .true_taken ;
218
+ total_taken+=taken;
219
+ condition.set_attribute (" coverage" , rate (taken, 2 , true ));
220
+ }
221
+
222
+ std::ostringstream oss;
223
+ oss << rate (total_taken, number*2 , true )
224
+ << " (" << total_taken << ' /' << number*2 << ' )' ;
225
+ line.set_attribute (" condition-coverage" , oss.str ());
191
226
}
192
227
}
193
228
}
194
229
195
230
/* ******************************************************************\
196
231
197
- Function: goto_program_coverage_recordt::compute_line_coverage
232
+ Function: goto_program_coverage_recordt::compute_coverage_lines
198
233
199
234
Inputs:
200
235
@@ -204,58 +239,83 @@ Function: goto_program_coverage_recordt::compute_line_coverage
204
239
205
240
\*******************************************************************/
206
241
207
- void goto_program_coverage_recordt::compute_line_coverage (
242
+ void goto_program_coverage_recordt::compute_coverage_lines (
208
243
const goto_programt &goto_program,
209
244
const irep_idt &file_name,
210
245
const symex_coveraget::coveraget &coverage,
211
- line_coverage_mapt &dest)
246
+ coverage_lines_mapt &dest)
212
247
{
213
248
forall_goto_program_instructions (it, goto_program)
214
249
{
215
250
if (it->source_location .is_nil () ||
216
- it->source_location .get_file ()!=file_name)
251
+ it->source_location .get_file ()!=file_name ||
252
+ it->is_dead () ||
253
+ it->is_end_function ())
217
254
continue ;
218
255
219
256
const bool is_branch=it->is_goto () && !it->guard .is_constant ();
220
257
221
258
unsigned l=
222
259
safe_string2unsigned (id2string (it->source_location .get_line ()));
223
- std::pair<line_coverage_mapt ::iterator, bool > entry=
224
- dest.insert (std::make_pair (l, line_coverage_recordt ()));
260
+ std::pair<coverage_lines_mapt ::iterator, bool > entry=
261
+ dest.insert (std::make_pair (l, coverage_linet ()));
225
262
226
263
if (entry.second )
227
- {
228
264
++lines_total;
229
- if (is_branch)
230
- ++branches_total;
231
- }
232
265
233
266
// mark as branch if any instruction in this source code line is
234
267
// a branching instruction
235
- if (is_branch &&
236
- !entry.first ->second .is_branch )
268
+ if (is_branch)
237
269
{
238
- ++branches_total;
239
- entry.first ->second .is_branch =true ;
270
+ branches_total+=2 ;
271
+ if (!entry.first ->second .conditions .insert (
272
+ {it, coverage_conditiont ()}).second )
273
+ assert (false );
240
274
}
241
275
242
276
symex_coveraget::coveraget::const_iterator c_entry=
243
277
coverage.find (it);
244
- if (c_entry!=coverage.end () &&
245
- c_entry->second .num_executions >0 )
278
+ if (c_entry!=coverage.end ())
246
279
{
247
- // maximum over all instructions in this source code line
248
- if (c_entry->second .num_executions >entry.first ->second .hits )
280
+ if (!(c_entry->second .size ()==1 || is_branch))
249
281
{
250
- if (entry. first -> second . hits == 0 )
251
- ++lines_covered;
252
- entry. first -> second .hits =c_entry-> second . num_executions ;
282
+ std::cerr << it-> location_number << std::endl;
283
+ for ( const auto &cov : c_entry-> second )
284
+ std::cerr << cov. second .succ -> location_number << std::endl ;
253
285
}
286
+ assert (c_entry->second .size ()==1 || is_branch);
254
287
255
- if (is_branch && !entry. first ->second . branch_covered )
288
+ for ( const auto &cov : c_entry ->second )
256
289
{
257
- ++branches_covered;
258
- entry.first ->second .branch_covered =true ;
290
+ assert (cov.second .num_executions >0 );
291
+
292
+ if (entry.first ->second .hits ==0 )
293
+ ++lines_covered;
294
+
295
+ entry.first ->second .hits +=cov.second .num_executions ;
296
+
297
+ if (is_branch)
298
+ {
299
+ auto cond_entry=entry.first ->second .conditions .find (it);
300
+ assert (cond_entry!=entry.first ->second .conditions .end ());
301
+
302
+ if (it->get_target ()==cov.second .succ )
303
+ {
304
+ if (!cond_entry->second .false_taken )
305
+ {
306
+ cond_entry->second .false_taken =true ;
307
+ ++branches_covered;
308
+ }
309
+ }
310
+ else
311
+ {
312
+ if (!cond_entry->second .true_taken )
313
+ {
314
+ cond_entry->second .true_taken =true ;
315
+ ++branches_covered;
316
+ }
317
+ }
318
+ }
259
319
}
260
320
}
261
321
}
0 commit comments