Skip to content

Commit 6cc190d

Browse files
Refactor function call harness generator
Important refactoring to make implementation of later features easier. Co-authored-by: Fotis Koutoulakis <[email protected]> Co-authored-by: Hannes Steffenhagen <[email protected]>
1 parent c7b962f commit 6cc190d

File tree

2 files changed

+118
-51
lines changed

2 files changed

+118
-51
lines changed

src/goto-harness/function_call_harness_generator.cpp

Lines changed: 112 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Author: Diffblue Ltd.
1111
#include <goto-programs/goto_convert.h>
1212
#include <goto-programs/goto_model.h>
1313
#include <util/allocate_objects.h>
14+
#include <util/arith_tools.h>
1415
#include <util/exception_utils.h>
1516
#include <util/std_code.h>
1617
#include <util/std_expr.h>
@@ -19,10 +20,30 @@ Author: Diffblue Ltd.
1920
#include "function_harness_generator_options.h"
2021
#include "goto_harness_parse_options.h"
2122

23+
/// This contains implementation details of
24+
/// function call harness generator to avoid
25+
/// leaking them out into the header.
2226
struct function_call_harness_generatort::implt
2327
{
2428
ui_message_handlert *message_handler;
2529
irep_idt function;
30+
irep_idt harness_function_name;
31+
symbol_tablet *symbol_table;
32+
goto_functionst *goto_functions;
33+
34+
/// \see goto_harness_generatort::generate
35+
void generate(goto_modelt &goto_model, const irep_idt &harness_function_name);
36+
/// Non-deterministically initialise the parameters of the entry function
37+
/// and insert function call to the passed code block.
38+
void setup_parameters_and_call_entry_function(code_blockt &function_body);
39+
/// Return a reference to the entry function or throw if it doesn't exist.
40+
const symbolt &lookup_function_to_call();
41+
/// Generate initialisation code for one lvalue inside block.
42+
void generate_initialisation_code_for(code_blockt &block, const exprt &lhs);
43+
/// Throw if the harness function already exists in the symbol table.
44+
void ensure_harness_does_not_already_exist();
45+
/// Update the goto-model with the new harness function.
46+
void add_harness_function_to_goto_model(code_blockt function_body);
2647
};
2748

2849
function_call_harness_generatort::function_call_harness_generatort(
@@ -53,82 +74,124 @@ void function_call_harness_generatort::generate(
5374
goto_modelt &goto_model,
5475
const irep_idt &harness_function_name)
5576
{
56-
auto const &function = p_impl->function;
57-
auto &symbol_table = goto_model.symbol_table;
58-
auto function_found = symbol_table.lookup(function);
59-
auto harness_function_found = symbol_table.lookup(harness_function_name);
77+
p_impl->generate(goto_model, harness_function_name);
78+
}
6079

61-
if(function_found == nullptr)
80+
void function_call_harness_generatort::implt::
81+
setup_parameters_and_call_entry_function(code_blockt &function_body)
82+
{
83+
const auto &function_to_call = lookup_function_to_call();
84+
const auto &function_type = to_code_type(function_to_call.type);
85+
const auto &parameters = function_type.parameters();
86+
87+
code_function_callt::operandst arguments{};
88+
89+
auto allocate_objects = allocate_objectst{function_to_call.mode,
90+
function_to_call.location,
91+
"__goto_harness",
92+
*symbol_table};
93+
for(const auto &parameter : parameters)
6294
{
63-
throw invalid_command_line_argument_exceptiont{
64-
"function that should be harnessed is not found " + id2string(function),
65-
"--" FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT};
95+
auto argument = allocate_objects.allocate_automatic_local_object(
96+
parameter.type(), parameter.get_base_name());
97+
arguments.push_back(argument);
6698
}
67-
68-
if(harness_function_found != nullptr)
99+
allocate_objects.declare_created_symbols(function_body);
100+
for(auto const &argument : arguments)
69101
{
70-
throw invalid_command_line_argument_exceptiont{
71-
"harness function already in the symbol table " +
72-
id2string(harness_function_name),
73-
"--" GOTO_HARNESS_GENERATOR_HARNESS_FUNCTION_NAME_OPT};
102+
generate_initialisation_code_for(function_body, argument);
74103
}
104+
code_function_callt function_call{function_to_call.symbol_expr(),
105+
std::move(arguments)};
106+
function_call.add_source_location() = function_to_call.location;
75107

76-
auto allocate_objects = allocate_objectst{function_found->mode,
77-
function_found->location,
78-
"__goto_harness",
79-
symbol_table};
108+
function_body.add(std::move(function_call));
109+
}
110+
111+
void function_call_harness_generatort::implt::generate(
112+
goto_modelt &goto_model,
113+
const irep_idt &harness_function_name)
114+
{
115+
symbol_table = &goto_model.symbol_table;
116+
goto_functions = &goto_model.goto_functions;
117+
this->harness_function_name = harness_function_name;
118+
ensure_harness_does_not_already_exist();
80119

81120
// create body for the function
82121
code_blockt function_body{};
83122

84-
const auto &function_type = to_code_type(function_found->type);
85-
const auto &parameters = function_type.parameters();
123+
setup_parameters_and_call_entry_function(function_body);
124+
add_harness_function_to_goto_model(std::move(function_body));
125+
}
86126

87-
code_function_callt::operandst arguments{};
88-
arguments.reserve(parameters.size());
127+
void function_call_harness_generatort::implt::generate_initialisation_code_for(
128+
code_blockt &block,
129+
const exprt &lhs)
130+
{
131+
block.add(code_assignt{lhs, side_effect_expr_nondett{lhs.type()}});
132+
}
89133

90-
for(const auto &parameter : parameters)
134+
void function_call_harness_generatort::validate_options()
135+
{
136+
if(p_impl->function == ID_empty)
137+
throw invalid_command_line_argument_exceptiont{
138+
"required parameter entry function not set",
139+
"--" FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT};
140+
}
141+
142+
const symbolt &
143+
function_call_harness_generatort::implt::lookup_function_to_call()
144+
{
145+
auto function_found = symbol_table->lookup(function);
146+
147+
if(function_found == nullptr)
91148
{
92-
auto argument = allocate_objects.allocate_automatic_local_object(
93-
parameter.type(), parameter.get_base_name());
94-
arguments.push_back(std::move(argument));
149+
throw invalid_command_line_argument_exceptiont{
150+
"function that should be harnessed is not found " + id2string(function),
151+
"--" FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT};
95152
}
96153

97-
code_function_callt function_call{function_found->symbol_expr(),
98-
std::move(arguments)};
99-
function_call.add_source_location() = function_found->location;
154+
return *function_found;
155+
}
100156

101-
function_body.add(std::move(function_call));
157+
void function_call_harness_generatort::implt::
158+
ensure_harness_does_not_already_exist()
159+
{
160+
if(symbol_table->lookup(harness_function_name))
161+
{
162+
throw invalid_command_line_argument_exceptiont{
163+
"harness function already exists in the symbol table",
164+
"--" GOTO_HARNESS_GENERATOR_HARNESS_FUNCTION_NAME_OPT};
165+
}
166+
}
167+
168+
void function_call_harness_generatort::implt::
169+
add_harness_function_to_goto_model(code_blockt function_body)
170+
{
171+
const auto &function_to_call = symbol_table->lookup_ref(function);
102172

103173
// create the function symbol
104174
symbolt harness_function_symbol{};
105175
harness_function_symbol.name = harness_function_symbol.base_name =
106176
harness_function_symbol.pretty_name = harness_function_name;
107177

108178
harness_function_symbol.is_lvalue = true;
109-
harness_function_symbol.mode = function_found->mode;
179+
harness_function_symbol.mode = function_to_call.mode;
110180
harness_function_symbol.type = code_typet{{}, empty_typet{}};
111-
harness_function_symbol.value = function_body;
181+
harness_function_symbol.value = std::move(function_body);
112182

113-
symbol_table.insert(harness_function_symbol);
183+
symbol_table->insert(harness_function_symbol);
114184

115-
goto_model.goto_functions.function_map[harness_function_name].type =
116-
to_code_type(harness_function_symbol.type);
117-
auto &body =
118-
goto_model.goto_functions.function_map[harness_function_name].body;
185+
auto const &generated_harness =
186+
symbol_table->lookup_ref(harness_function_name);
187+
goto_functions->function_map[harness_function_name].type =
188+
to_code_type(generated_harness.type);
189+
auto &body = goto_functions->function_map[harness_function_name].body;
119190
goto_convert(
120-
static_cast<const codet &>(harness_function_symbol.value),
121-
goto_model.symbol_table,
191+
static_cast<const codet &>(generated_harness.value),
192+
*symbol_table,
122193
body,
123-
*p_impl->message_handler,
124-
function_found->mode);
194+
*message_handler,
195+
function_to_call.mode);
125196
body.add(goto_programt::make_end_function());
126197
}
127-
128-
void function_call_harness_generatort::validate_options()
129-
{
130-
if(p_impl->function == ID_empty)
131-
throw invalid_command_line_argument_exceptiont{
132-
"required parameter entry function not set",
133-
"--" FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT};
134-
}

src/goto-harness/function_harness_generator_options.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,20 @@ Author: Diffblue Ltd.
1010
#define CPROVER_GOTO_HARNESS_FUNCTION_HARNESS_GENERATOR_OPTIONS_H
1111

1212
#define FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT "function"
13+
14+
// clang-format off
1315
#define FUNCTION_HARNESS_GENERATOR_OPTIONS \
14-
"(" FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT "):"
15-
// FUNCTION_HARNESS_GENERATOR_OPTIONS
16+
"(" FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT "):" \
17+
18+
// clang-format on
1619

1720
// clang-format off
1821
#define FUNCTION_HARNESS_GENERATOR_HELP \
1922
"function harness generator (--harness-type call-function)\n\n" \
2023
"--" FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT \
2124
" the function the harness should call\n" \
2225
// FUNCTION_HARNESS_GENERATOR_HELP
26+
2327
// clang-format on
2428

2529
#endif // CPROVER_GOTO_HARNESS_FUNCTION_HARNESS_GENERATOR_OPTIONS_H

0 commit comments

Comments
 (0)