Skip to content

Commit c58a5e1

Browse files
author
Daniel Kroening
committed
decision and condition coverage
1 parent 0114f7e commit c58a5e1

File tree

1 file changed

+212
-19
lines changed

1 file changed

+212
-19
lines changed

src/goto-instrument/cover.cpp

Lines changed: 212 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,65 @@ const char *as_string(coverage_criteriont c)
7979

8080
/*******************************************************************\
8181
82+
Function: collect_conditions_rec
83+
84+
Inputs:
85+
86+
Outputs:
87+
88+
Purpose:
89+
90+
\*******************************************************************/
91+
92+
void collect_conditions_rec(const exprt &src, std::set<exprt> &dest)
93+
{
94+
if(src.id()==ID_address_of)
95+
{
96+
return;
97+
}
98+
99+
for(const auto & op : src.operands())
100+
collect_conditions_rec(op, dest);
101+
102+
if(src.type().id()==ID_bool)
103+
{
104+
if(src.id()==ID_and || src.id()==ID_or ||
105+
src.id()==ID_not || src.id()==ID_implies)
106+
{
107+
// ignore me
108+
}
109+
else if(src.is_constant())
110+
{
111+
// ignore me
112+
}
113+
else
114+
{
115+
dest.insert(src);
116+
}
117+
}
118+
}
119+
120+
/*******************************************************************\
121+
122+
Function: collect_conditions
123+
124+
Inputs:
125+
126+
Outputs:
127+
128+
Purpose:
129+
130+
\*******************************************************************/
131+
132+
std::set<exprt> collect_conditions(const exprt &src)
133+
{
134+
std::set<exprt> result;
135+
collect_conditions_rec(src, result);
136+
return result;
137+
}
138+
139+
/*******************************************************************\
140+
82141
Function: collect_conditions
83142
84143
Inputs:
@@ -89,21 +148,114 @@ Function: collect_conditions
89148
90149
\*******************************************************************/
91150

92-
void collect_conditions(const exprt &src, std::set<exprt> &dest)
151+
std::set<exprt> collect_conditions(const goto_programt::const_targett t)
93152
{
94-
if(src.id()==ID_and || src.id()==ID_or ||
95-
src.id()==ID_not || src.id()==ID_implies)
153+
switch(t->type)
96154
{
97-
forall_operands(it, src)
98-
collect_conditions(*it, dest);
155+
case GOTO:
156+
case ASSUME:
157+
case ASSERT:
158+
return collect_conditions(t->guard);
159+
160+
case ASSIGN:
161+
case FUNCTION_CALL:
162+
return collect_conditions(t->code);
163+
164+
default:;
99165
}
100-
else if(src.is_true())
166+
167+
return std::set<exprt>();
168+
}
169+
170+
/*******************************************************************\
171+
172+
Function: collect_decisions_rec
173+
174+
Inputs:
175+
176+
Outputs:
177+
178+
Purpose:
179+
180+
\*******************************************************************/
181+
182+
void collect_decisions_rec(const exprt &src, std::set<exprt> &dest)
183+
{
184+
if(src.id()==ID_address_of)
101185
{
186+
return;
187+
}
188+
189+
if(src.type().id()==ID_bool)
190+
{
191+
if(src.is_constant())
192+
{
193+
// ignore me
194+
}
195+
else if(src.id()==ID_not)
196+
{
197+
collect_decisions_rec(src.op0(), dest);
198+
}
199+
else
200+
{
201+
dest.insert(src);
202+
}
102203
}
103204
else
104205
{
105-
dest.insert(src);
206+
for(const auto & op : src.operands())
207+
collect_decisions_rec(op, dest);
208+
}
209+
}
210+
211+
/*******************************************************************\
212+
213+
Function: collect_decisions
214+
215+
Inputs:
216+
217+
Outputs:
218+
219+
Purpose:
220+
221+
\*******************************************************************/
222+
223+
std::set<exprt> collect_decisions(const exprt &src)
224+
{
225+
std::set<exprt> result;
226+
collect_decisions_rec(src, result);
227+
return result;
228+
}
229+
230+
/*******************************************************************\
231+
232+
Function: collect_decisions
233+
234+
Inputs:
235+
236+
Outputs:
237+
238+
Purpose:
239+
240+
\*******************************************************************/
241+
242+
std::set<exprt> collect_decisions(const goto_programt::const_targett t)
243+
{
244+
switch(t->type)
245+
{
246+
case GOTO:
247+
case ASSUME:
248+
case ASSERT:
249+
return collect_decisions(t->guard);
250+
251+
case ASSIGN:
252+
case FUNCTION_CALL:
253+
return collect_decisions(t->code);
254+
255+
default:;
106256
}
257+
258+
return std::set<exprt>();
107259
}
108260

109261
/*******************************************************************\
@@ -190,32 +342,73 @@ void instrument_cover_goals(
190342
break;
191343

192344
case coverage_criteriont::CONDITION:
193-
if(i_it->is_goto())
345+
// Conditions are all atomic predicates in the programs.
194346
{
195-
std::set<exprt> conditions;
347+
std::set<exprt> conditions=
348+
collect_conditions(i_it);
349+
350+
source_locationt source_location=i_it->source_location;
196351

197-
collect_conditions(i_it->guard, conditions);
198-
unsigned i=0;
352+
for(const auto & c : conditions)
353+
{
354+
std::string comment_t="condition "+from_expr(ns, "", c)+" true";
355+
goto_program.insert_before_swap(i_it);
356+
i_it->make_assertion(c);
357+
i_it->source_location=source_location;
358+
i_it->source_location.set_comment(comment_t);
359+
360+
std::string comment_f="condition "+from_expr(ns, "", c)+" false";
361+
goto_program.insert_before_swap(i_it);
362+
i_it->make_assertion(not_exprt(c));
363+
i_it->source_location=source_location;
364+
i_it->source_location.set_comment(comment_f);
365+
}
366+
367+
for(unsigned i=0; i<conditions.size()*2; i++)
368+
i_it++;
369+
}
370+
break;
371+
372+
case coverage_criteriont::DECISION:
373+
// Decisions are maximal Boolean combinations of conditions.
374+
{
375+
std::set<exprt> decisions=
376+
collect_decisions(i_it);
199377

200-
exprt guard=i_it->guard;
201378
source_locationt source_location=i_it->source_location;
202379

203-
for(std::set<exprt>::const_iterator it=conditions.begin();
204-
it!=conditions.end();
205-
it++, i++)
380+
for(const auto & d : decisions)
206381
{
207-
std::string comment="condition "+from_expr(ns, "", *it);
382+
std::string comment_t="decision "+from_expr(ns, "", d)+" true";
208383
goto_program.insert_before_swap(i_it);
209-
i_it->make_assertion(*it);
384+
i_it->make_assertion(d);
210385
i_it->source_location=source_location;
211-
i_it->source_location.set_comment(comment);
386+
i_it->source_location.set_comment(comment_t);
387+
388+
std::string comment_f="decision "+from_expr(ns, "", d)+" false";
389+
goto_program.insert_before_swap(i_it);
390+
i_it->make_assertion(not_exprt(d));
391+
i_it->source_location=source_location;
392+
i_it->source_location.set_comment(comment_f);
212393
}
213394

214-
for(unsigned i=0; i<conditions.size(); i++)
395+
for(unsigned i=0; i<decisions.size()*2; i++)
215396
i_it++;
216397
}
217398
break;
218399

400+
401+
case coverage_criteriont::MCDC:
402+
// 1. Each entry and exit point is invoked
403+
// 2. Each decision takes every possible outcome
404+
// 3. Each condition in a decision takes every possible outcome
405+
// 4. Each condition in a decision is shown to independently
406+
// affect the outcome of the decision.
407+
break;
408+
409+
case coverage_criteriont::PATH:
410+
break;
411+
219412
default:;
220413
}
221414
}

0 commit comments

Comments
 (0)