9
9
// / \file
10
10
// / Replace Java Nondet expressions
11
11
12
- #include " goto-programs/replace_java_nondet.h"
13
- #include " goto-programs/goto_convert.h"
14
- #include " goto-programs/goto_model.h"
15
- #include " goto-programs/remove_skip.h"
16
-
17
- #include " util/irep_ids.h"
12
+ #include " replace_java_nondet.h"
18
13
19
14
#include < algorithm>
20
15
#include < regex>
21
16
17
+ #include < goto-programs/goto_convert.h>
18
+ #include < goto-programs/goto_model.h>
19
+ #include < goto-programs/remove_skip.h>
20
+
21
+ #include < util/irep_ids.h>
22
+
22
23
// / Holds information about any discovered nondet methods, with extreme type-
23
24
// / safety.
24
25
class nondet_instruction_infot final
25
26
{
26
27
public:
27
- enum class is_nondett :bool { FALSE , TRUE };
28
- enum class is_nullablet :bool { FALSE , TRUE };
28
+ enum class is_nondett : bool
29
+ {
30
+ FALSE ,
31
+ TRUE
32
+ };
33
+ enum class is_nullablet : bool
34
+ {
35
+ FALSE ,
36
+ TRUE
37
+ };
29
38
30
- nondet_instruction_infot ():
31
- is_nondet (is_nondett::FALSE ),
32
- is_nullable (is_nullablet::FALSE )
39
+ nondet_instruction_infot ()
40
+ : is_nondet(is_nondett::FALSE ), is_nullable(is_nullablet::FALSE )
33
41
{
34
42
}
35
43
36
- explicit nondet_instruction_infot (is_nullablet is_nullable):
37
- is_nondet(is_nondett::TRUE ),
38
- is_nullable(is_nullable)
44
+ explicit nondet_instruction_infot (is_nullablet is_nullable)
45
+ : is_nondet(is_nondett::TRUE ), is_nullable(is_nullable)
39
46
{
40
47
}
41
48
42
- is_nondett get_instruction_type () const { return is_nondet; }
43
- is_nullablet get_nullable_type () const { return is_nullable; }
49
+ is_nondett get_instruction_type () const
50
+ {
51
+ return is_nondet;
52
+ }
53
+ is_nullablet get_nullable_type () const
54
+ {
55
+ return is_nullable;
56
+ }
44
57
45
58
private:
46
59
is_nondett is_nondet;
@@ -52,11 +65,11 @@ class nondet_instruction_infot final
52
65
// / \return A structure detailing whether the function call appears to be one of
53
66
// / our nondet library methods, and if so, whether or not it allows null
54
67
// / results.
55
- static nondet_instruction_infot is_nondet_returning_object (
56
- const code_function_callt &function_call)
68
+ static nondet_instruction_infot
69
+ is_nondet_returning_object ( const code_function_callt &function_call)
57
70
{
58
- const auto &function_symbol= to_symbol_expr (function_call.function ());
59
- const auto function_name= id2string (function_symbol.get_identifier ());
71
+ const auto &function_symbol = to_symbol_expr (function_call.function ());
72
+ const auto function_name = id2string (function_symbol.get_identifier ());
60
73
const std::regex reg (
61
74
R"( .*org\.cprover\.CProver\.nondet)"
62
75
R"( (?:Boolean|Byte|Char|Short|Int|Long|Float|Double|With(out)?Null.*))" );
@@ -74,51 +87,51 @@ static nondet_instruction_infot is_nondet_returning_object(
74
87
// / recognised nondet library methods, and return some information about it.
75
88
// / \param instr: A goto-program instruction to check.
76
89
// / \return A structure detailing the properties of the nondet method.
77
- static nondet_instruction_infot get_nondet_instruction_info (
78
- const goto_programt::const_targett &instr)
90
+ static nondet_instruction_infot
91
+ get_nondet_instruction_info ( const goto_programt::const_targett &instr)
79
92
{
80
- if (!(instr->is_function_call () && instr->code .id ()== ID_code))
93
+ if (!(instr->is_function_call () && instr->code .id () == ID_code))
81
94
{
82
95
return nondet_instruction_infot ();
83
96
}
84
- const auto &code= to_code (instr->code );
85
- if (code.get_statement ()!= ID_function_call)
97
+ const auto &code = to_code (instr->code );
98
+ if (code.get_statement () != ID_function_call)
86
99
{
87
100
return nondet_instruction_infot ();
88
101
}
89
- const auto &function_call= to_code_function_call (code);
102
+ const auto &function_call = to_code_function_call (code);
90
103
return is_nondet_returning_object (function_call);
91
104
}
92
105
93
106
// / Return whether the expression is a symbol with the specified identifier.
94
107
// / \param expr: The expression which may be a symbol.
95
108
// / \param identifier: Some identifier.
96
109
// / \return True if the expression is a symbol with the specified identifier.
97
- static bool is_symbol_with_id (const exprt& expr, const irep_idt& identifier)
110
+ static bool is_symbol_with_id (const exprt & expr, const irep_idt & identifier)
98
111
{
99
- return expr.id ()== ID_symbol &&
100
- to_symbol_expr (expr).get_identifier ()== identifier;
112
+ return expr.id () == ID_symbol &&
113
+ to_symbol_expr (expr).get_identifier () == identifier;
101
114
}
102
115
103
116
// / Return whether the expression is a typecast with the specified identifier.
104
117
// / \param expr: The expression which may be a typecast.
105
118
// / \param identifier: Some identifier.
106
119
// / \return True if the expression is a typecast with one operand, and the
107
120
// / typecast's identifier matches the specified identifier.
108
- static bool is_typecast_with_id (const exprt& expr, const irep_idt& identifier)
121
+ static bool is_typecast_with_id (const exprt & expr, const irep_idt & identifier)
109
122
{
110
- if (!(expr.id ()== ID_typecast && expr.operands ().size ()== 1 ))
123
+ if (!(expr.id () == ID_typecast && expr.operands ().size () == 1 ))
111
124
{
112
125
return false ;
113
126
}
114
- const auto &typecast= to_typecast_expr (expr);
115
- if (!(typecast.op ().id ()== ID_symbol && !typecast.op ().has_operands ()))
127
+ const auto &typecast = to_typecast_expr (expr);
128
+ if (!(typecast.op ().id () == ID_symbol && !typecast.op ().has_operands ()))
116
129
{
117
130
return false ;
118
131
}
119
- const auto &op_symbol= to_symbol_expr (typecast.op ());
132
+ const auto &op_symbol = to_symbol_expr (typecast.op ());
120
133
// Return whether the typecast has the expected operand
121
- return op_symbol.get_identifier ()== identifier;
134
+ return op_symbol.get_identifier () == identifier;
122
135
}
123
136
124
137
// / Return whether the instruction is an assignment, and the rhs is a symbol or
@@ -136,26 +149,14 @@ static bool is_assignment_from(
136
149
{
137
150
return false ;
138
151
}
139
- const auto &rhs= to_code_assign (instr.code ).rhs ();
152
+ const auto &rhs = to_code_assign (instr.code ).rhs ();
140
153
return is_symbol_with_id (rhs, identifier) ||
141
154
is_typecast_with_id (rhs, identifier);
142
155
}
143
156
144
157
// / Given an iterator into a list of instructions, modify the list to replace
145
158
// / 'nondet' library functions with CBMC-native nondet expressions, and return
146
- // / an iterator to the next instruction to check. It's important to note that
147
- // / this method also deals with the fact that in the GOTO program it assigns
148
- // / function return values to temporary variables, performs validation and then
149
- // / assigns the value into the actual variable.
150
- // /
151
- // / Example:
152
- // /
153
- // / return_tmp0=org.cprover.CProver.nondetWithoutNull:()Ljava/lang/Object;();
154
- // / ... Various validations of type and value here.
155
- // / obj = (<type-of-obj>)return_tmp0;
156
- // /
157
- // / We're going to replace all of these lines with
158
- // / return_tmp0 = NONDET(<type-of-obj>)
159
+ // / an iterator to the next instruction to check.
159
160
// / \param goto_program: The goto program to modify.
160
161
// / \param target: A single step of the goto program which may be erased and
161
162
// / replaced.
@@ -165,94 +166,67 @@ static goto_programt::targett check_and_replace_target(
165
166
const goto_programt::targett &target)
166
167
{
167
168
// Check whether this is a nondet library method, and return if not
168
- const auto instr_info=get_nondet_instruction_info (target);
169
- const auto next_instr=std::next (target);
170
- if (instr_info.get_instruction_type ()==
171
- nondet_instruction_infot::is_nondett::FALSE )
169
+ const auto instr_info = get_nondet_instruction_info (target);
170
+ const auto next_instr = std::next (target);
171
+ if (
172
+ instr_info.get_instruction_type () ==
173
+ nondet_instruction_infot::is_nondett::FALSE )
172
174
{
173
175
return next_instr;
174
176
}
175
177
176
- // If we haven't removed returns yet, our function call will have a variable
177
- // on its left hand side.
178
- const bool remove_returns_not_run =
179
- to_code_function_call (target ->code ).lhs (). is_not_nil ();
180
-
181
- irep_idt return_identifier;
182
- if (remove_returns_not_run )
178
+ // Look at the next instruction, ensure that it is an assignment
179
+ assert (next_instr-> is_assign ());
180
+ // Get the name of the LHS of the assignment
181
+ const auto &next_instr_assign_lhs = to_code_assign (next_instr ->code ).lhs ();
182
+ if (
183
+ !(next_instr_assign_lhs. id () == ID_symbol &&
184
+ !next_instr_assign_lhs. has_operands ()) )
183
185
{
184
- return_identifier =
185
- to_symbol_expr (to_code_function_call (target->code ).lhs ())
186
- .get_identifier ();
187
- }
188
- else
189
- {
190
- // If not, we need to look at the next line instead.
191
- DATA_INVARIANT (
192
- next_instr->is_assign (),
193
- " the code_function_callt for a nondet-returning library function should "
194
- " either have a variable for the return value in its lhs() or the next "
195
- " instruction should be an assignment of the return value to a temporary "
196
- " variable" );
197
- const exprt &return_value_assignment =
198
- to_code_assign (next_instr->code ).lhs ();
199
-
200
- // If the assignment is null, return.
201
- if (
202
- !(return_value_assignment.id () == ID_symbol &&
203
- !return_value_assignment.has_operands ()))
204
- {
205
- return next_instr;
206
- }
207
-
208
- // Otherwise it's the temporary variable.
209
- return_identifier =
210
- to_symbol_expr (return_value_assignment).get_identifier ();
186
+ return next_instr;
211
187
}
188
+ const auto return_identifier =
189
+ to_symbol_expr (next_instr_assign_lhs).get_identifier ();
190
+
191
+ auto &instructions = goto_program.instructions ;
192
+ const auto end = instructions.end ();
212
193
213
- // Look for the assignment of the temporary return variable into our target
214
- // variable.
215
- const auto end = goto_program.instructions .end ();
216
- auto assignment_instruction = std::find_if (
194
+ // Look for an instruction where this name is on the RHS of an assignment
195
+ const auto matching_assignment = std::find_if (
217
196
next_instr,
218
197
end,
219
- [&return_identifier](const goto_programt::instructiont &instr) {
198
+ [&return_identifier](
199
+ const goto_programt::instructiont &instr) { // NOLINT (*)
220
200
return is_assignment_from (instr, return_identifier);
221
201
});
222
202
223
- INVARIANT (
224
- assignment_instruction != end,
225
- " failed to find assignment of the temporary return variable into our "
226
- " target variable" );
203
+ assert (matching_assignment != end);
227
204
228
205
// Assume that the LHS of *this* assignment is the actual nondet variable
229
- const auto &code_assign = to_code_assign (assignment_instruction ->code );
230
- const auto nondet_var= code_assign.lhs ();
231
- const auto source_loc= target->source_location ;
206
+ const auto &code_assign = to_code_assign (matching_assignment ->code );
207
+ const auto nondet_var = code_assign.lhs ();
208
+ const auto source_loc = target->source_location ;
232
209
233
210
// Erase from the nondet function call to the assignment
234
- const auto after_matching_assignment = std::next (assignment_instruction);
235
- INVARIANT (
236
- after_matching_assignment != end,
237
- " goto_program missing END_FUNCTION instruction" );
211
+ const auto after_matching_assignment = std::next (matching_assignment);
212
+ assert (after_matching_assignment != end);
238
213
239
214
std::for_each (
240
215
target,
241
216
after_matching_assignment,
242
- [](goto_programt::instructiont &instr)
243
- {
217
+ [](goto_programt::instructiont &instr) { // NOLINT (*)
244
218
instr.make_skip ();
245
219
});
246
220
247
- const auto inserted= goto_program.insert_before (after_matching_assignment);
221
+ const auto inserted = goto_program.insert_before (after_matching_assignment);
248
222
inserted->make_assignment ();
249
223
side_effect_expr_nondett inserted_expr (nondet_var.type ());
250
224
inserted_expr.set_nullable (
251
- instr_info.get_nullable_type ()==
225
+ instr_info.get_nullable_type () ==
252
226
nondet_instruction_infot::is_nullablet::TRUE );
253
- inserted->code = code_assignt (nondet_var, inserted_expr);
254
- inserted->code .add_source_location ()= source_loc;
255
- inserted->source_location = source_loc;
227
+ inserted->code = code_assignt (nondet_var, inserted_expr);
228
+ inserted->code .add_source_location () = source_loc;
229
+ inserted->source_location = source_loc;
256
230
257
231
goto_program.update ();
258
232
@@ -265,13 +239,12 @@ static goto_programt::targett check_and_replace_target(
265
239
// / \param goto_program: The goto program to modify.
266
240
static void replace_java_nondet (goto_programt &goto_program)
267
241
{
268
- for (auto instruction_iterator= goto_program.instructions .begin (),
269
- end= goto_program.instructions .end ();
270
- instruction_iterator!= end;)
242
+ for (auto instruction_iterator = goto_program.instructions .begin (),
243
+ end = goto_program.instructions .end ();
244
+ instruction_iterator != end;)
271
245
{
272
- instruction_iterator=check_and_replace_target (
273
- goto_program,
274
- instruction_iterator);
246
+ instruction_iterator =
247
+ check_and_replace_target (goto_program, instruction_iterator);
275
248
}
276
249
}
277
250
0 commit comments