|
| 1 | +/******************************************************************\ |
| 2 | +
|
| 3 | +Module: harness generator for functions |
| 4 | +
|
| 5 | +Author: Diffblue Ltd. |
| 6 | +
|
| 7 | +\******************************************************************/ |
| 8 | + |
| 9 | +#include "function_call_harness_generator.h" |
| 10 | + |
| 11 | +#include <goto-programs/goto_convert.h> |
| 12 | +#include <goto-programs/goto_model.h> |
| 13 | +#include <util/allocate_objects.h> |
| 14 | +#include <util/exception_utils.h> |
| 15 | +#include <util/std_code.h> |
| 16 | +#include <util/std_expr.h> |
| 17 | +#include <util/ui_message.h> |
| 18 | + |
| 19 | +#include "function_harness_generator_options.h" |
| 20 | +#include "goto_harness_parse_options.h" |
| 21 | + |
| 22 | +struct function_call_harness_generatort::implt |
| 23 | +{ |
| 24 | + ui_message_handlert *message_handler; |
| 25 | + irep_idt function; |
| 26 | +}; |
| 27 | + |
| 28 | +function_call_harness_generatort::function_call_harness_generatort( |
| 29 | + ui_message_handlert &message_handler) |
| 30 | + : goto_harness_generatort{}, p_impl(util_make_unique<implt>()) |
| 31 | +{ |
| 32 | + p_impl->message_handler = &message_handler; |
| 33 | +} |
| 34 | + |
| 35 | +function_call_harness_generatort::~function_call_harness_generatort() = default; |
| 36 | + |
| 37 | +void function_call_harness_generatort::handle_option( |
| 38 | + const std::string &option, |
| 39 | + const std::list<std::string> &values) |
| 40 | +{ |
| 41 | + if(option == FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT) |
| 42 | + { |
| 43 | + p_impl->function = require_exactly_one_value(option, values); |
| 44 | + } |
| 45 | + else |
| 46 | + { |
| 47 | + throw invalid_command_line_argument_exceptiont{ |
| 48 | + "function harness generator cannot handle this option", "--" + option}; |
| 49 | + } |
| 50 | +} |
| 51 | + |
| 52 | +void function_call_harness_generatort::generate( |
| 53 | + goto_modelt &goto_model, |
| 54 | + const irep_idt &harness_function_name) |
| 55 | +{ |
| 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); |
| 60 | + |
| 61 | + if(function_found == nullptr) |
| 62 | + { |
| 63 | + throw invalid_command_line_argument_exceptiont{ |
| 64 | + "function that should be harnessed is not found " + id2string(function), |
| 65 | + "--" FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT}; |
| 66 | + } |
| 67 | + |
| 68 | + if(harness_function_found != nullptr) |
| 69 | + { |
| 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}; |
| 74 | + } |
| 75 | + |
| 76 | + auto allocate_objects = allocate_objectst{function_found->mode, |
| 77 | + function_found->location, |
| 78 | + "__goto_harness", |
| 79 | + symbol_table}; |
| 80 | + |
| 81 | + // create body for the function |
| 82 | + code_blockt function_body{}; |
| 83 | + |
| 84 | + const auto &function_type = to_code_type(function_found->type); |
| 85 | + const auto ¶meters = function_type.parameters(); |
| 86 | + |
| 87 | + code_function_callt::operandst arguments{}; |
| 88 | + arguments.reserve(parameters.size()); |
| 89 | + |
| 90 | + for(const auto ¶meter : parameters) |
| 91 | + { |
| 92 | + auto argument = allocate_objects.allocate_automatic_local_object( |
| 93 | + parameter.type(), parameter.get_base_name()); |
| 94 | + arguments.push_back(std::move(argument)); |
| 95 | + } |
| 96 | + |
| 97 | + code_function_callt function_call{function_found->symbol_expr(), |
| 98 | + std::move(arguments)}; |
| 99 | + function_call.add_source_location() = function_found->location; |
| 100 | + |
| 101 | + function_body.add(std::move(function_call)); |
| 102 | + |
| 103 | + // create the function symbol |
| 104 | + symbolt harness_function_symbol{}; |
| 105 | + harness_function_symbol.name = harness_function_symbol.base_name = |
| 106 | + harness_function_symbol.pretty_name = harness_function_name; |
| 107 | + |
| 108 | + harness_function_symbol.is_lvalue = true; |
| 109 | + harness_function_symbol.mode = function_found->mode; |
| 110 | + harness_function_symbol.type = code_typet{{}, empty_typet{}}; |
| 111 | + harness_function_symbol.value = function_body; |
| 112 | + |
| 113 | + symbol_table.insert(harness_function_symbol); |
| 114 | + |
| 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; |
| 119 | + goto_convert( |
| 120 | + static_cast<const codet &>(harness_function_symbol.value), |
| 121 | + goto_model.symbol_table, |
| 122 | + body, |
| 123 | + *p_impl->message_handler, |
| 124 | + function_found->mode); |
| 125 | + body.add(goto_programt::make_end_function()); |
| 126 | +} |
| 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 | +} |
0 commit comments