|
8 | 8 |
|
9 | 9 | #include <algorithm>
|
10 | 10 | #include <numeric>
|
| 11 | +#include <functional> |
| 12 | +#include <iostream> |
11 | 13 | #include <util/arith_tools.h>
|
| 14 | +#include <util/ssa_expr.h> |
12 | 15 | #include <util/std_expr.h>
|
13 | 16 | #include <util/expr_iterator.h>
|
| 17 | +#include <util/graph.h> |
14 | 18 | #include "string_refinement_util.h"
|
15 | 19 |
|
16 | 20 | bool is_char_type(const typet &type)
|
@@ -169,3 +173,242 @@ equation_symbol_mappingt::find_equations(const exprt &expr)
|
169 | 173 | {
|
170 | 174 | return equations_containing[expr];
|
171 | 175 | }
|
| 176 | + |
| 177 | +string_insertion_builtin_functiont::string_insertion_builtin_functiont( |
| 178 | + const std::vector<exprt> &fun_args, |
| 179 | + array_poolt &array_pool) |
| 180 | +{ |
| 181 | + PRECONDITION(fun_args.size() > 3); |
| 182 | + const auto arg1 = expr_checked_cast<struct_exprt>(fun_args[2]); |
| 183 | + input1 = array_pool.find(arg1.op1(), arg1.op0()); |
| 184 | + const auto arg2 = expr_checked_cast<struct_exprt>(fun_args[3]); |
| 185 | + input2 = array_pool.find(arg2.op1(), arg2.op0()); |
| 186 | + result = array_pool.find(fun_args[1], fun_args[0]); |
| 187 | + args.insert(args.end(), fun_args.begin() + 4, fun_args.end()); |
| 188 | +} |
| 189 | + |
| 190 | +/// Construct a string_builtin_functiont object from a function application |
| 191 | +/// \return a unique pointer to the created object, this unique pointer is empty |
| 192 | +/// if the function does not correspond to one of the supported |
| 193 | +/// builtin_functions. |
| 194 | +static std::unique_ptr<string_builtin_functiont> to_string_builtin_function( |
| 195 | + const function_application_exprt &fun_app, |
| 196 | + array_poolt &array_pool) |
| 197 | +{ |
| 198 | + const auto name = expr_checked_cast<symbol_exprt>(fun_app.function()); |
| 199 | + const irep_idt &id = is_ssa_expr(name) ? to_ssa_expr(name).get_object_name() |
| 200 | + : name.get_identifier(); |
| 201 | + |
| 202 | + if(id == ID_cprover_string_insert_func) |
| 203 | + return std::unique_ptr<string_builtin_functiont>( |
| 204 | + new string_insertion_builtin_functiont(fun_app.arguments(), array_pool)); |
| 205 | + |
| 206 | + if(id == ID_cprover_string_concat_func) |
| 207 | + return std::unique_ptr<string_builtin_functiont>( |
| 208 | + new string_insertion_builtin_functiont(fun_app.arguments(), array_pool)); |
| 209 | + |
| 210 | + return {}; |
| 211 | +} |
| 212 | + |
| 213 | +string_dependencest::string_nodet & |
| 214 | +string_dependencest::get_node(const array_string_exprt &e) |
| 215 | +{ |
| 216 | + auto entry_inserted = node_index_pool.emplace(e, string_nodes.size()); |
| 217 | + if(!entry_inserted.second) |
| 218 | + return string_nodes[entry_inserted.first->second]; |
| 219 | + |
| 220 | + string_nodes.emplace_back(); |
| 221 | + return string_nodes.back(); |
| 222 | +} |
| 223 | + |
| 224 | +string_dependencest::builtin_function_nodet string_dependencest::make_node( |
| 225 | + std::unique_ptr<string_builtin_functiont> &builtin_function) |
| 226 | +{ |
| 227 | + const builtin_function_nodet builtin_function_node( |
| 228 | + builtin_function_nodes.size()); |
| 229 | + builtin_function_nodes.emplace_back(); |
| 230 | + builtin_function_nodes.back().swap(builtin_function); |
| 231 | + return builtin_function_node; |
| 232 | +} |
| 233 | + |
| 234 | +const string_builtin_functiont &string_dependencest::get_builtin_function( |
| 235 | + const builtin_function_nodet &node) const |
| 236 | +{ |
| 237 | + return *(builtin_function_nodes[node.index]); |
| 238 | +} |
| 239 | + |
| 240 | +const std::vector<string_dependencest::builtin_function_nodet> & |
| 241 | +string_dependencest::dependencies( |
| 242 | + const string_dependencest::string_nodet &node) const |
| 243 | +{ |
| 244 | + return node.dependencies; |
| 245 | +} |
| 246 | + |
| 247 | +void string_dependencest::add_dependency( |
| 248 | + const array_string_exprt &e, |
| 249 | + const builtin_function_nodet &builtin_function_node) |
| 250 | +{ |
| 251 | + string_nodet &string_node = get_node(e); |
| 252 | + string_node.dependencies.push_back(builtin_function_node); |
| 253 | +} |
| 254 | + |
| 255 | +void string_dependencest::add_unknown_dependency(const array_string_exprt &e) |
| 256 | +{ |
| 257 | + string_nodet &string_node = get_node(e); |
| 258 | + string_node.depends_on_unknown_builtin_function = true; |
| 259 | +} |
| 260 | + |
| 261 | +static void add_unknown_dependency_to_string_subexprs( |
| 262 | + string_dependencest &dependencies, |
| 263 | + const function_application_exprt &fun_app, |
| 264 | + array_poolt &array_pool) |
| 265 | +{ |
| 266 | + for(const auto &expr : fun_app.arguments()) |
| 267 | + { |
| 268 | + std::for_each( |
| 269 | + expr.depth_begin(), expr.depth_end(), [&](const exprt &e) { // NOLINT |
| 270 | + if(const auto &string = get_char_array_of_argument(e)) |
| 271 | + dependencies.add_unknown_dependency(array_pool.find(*string)); |
| 272 | + }); |
| 273 | + } |
| 274 | +} |
| 275 | + |
| 276 | +static void add_dependency_to_string_subexprs( |
| 277 | + string_dependencest &dependencies, |
| 278 | + const function_application_exprt &fun_app, |
| 279 | + const string_dependencest::builtin_function_nodet &builtin_function_node, |
| 280 | + array_poolt &array_pool) |
| 281 | +{ |
| 282 | + PRECONDITION(fun_app.arguments()[0].type().id() != ID_pointer); |
| 283 | + if( |
| 284 | + fun_app.arguments().size() > 1 && |
| 285 | + fun_app.arguments()[1].type().id() == ID_pointer) |
| 286 | + { |
| 287 | + // Case where the result is given as a pointer argument |
| 288 | + const array_string_exprt string = |
| 289 | + array_pool.find(fun_app.arguments()[1], fun_app.arguments()[0]); |
| 290 | + dependencies.add_dependency(string, builtin_function_node); |
| 291 | + } |
| 292 | + |
| 293 | + for(const auto &expr : fun_app.arguments()) |
| 294 | + { |
| 295 | + std::for_each( |
| 296 | + expr.depth_begin(), |
| 297 | + expr.depth_end(), |
| 298 | + [&](const exprt &e) { // NOLINT |
| 299 | + if(const auto structure = expr_try_dynamic_cast<struct_exprt>(e)) |
| 300 | + { |
| 301 | + const array_string_exprt string = array_pool.of_argument(*structure); |
| 302 | + dependencies.add_dependency(string, builtin_function_node); |
| 303 | + } |
| 304 | + }); |
| 305 | + } |
| 306 | +} |
| 307 | + |
| 308 | +string_dependencest::node_indext string_dependencest::size() const |
| 309 | +{ |
| 310 | + return builtin_function_nodes.size() + string_nodes.size(); |
| 311 | +} |
| 312 | + |
| 313 | +string_dependencest::node_indext |
| 314 | +string_dependencest::node_index(const builtin_function_nodet &n) const |
| 315 | +{ |
| 316 | + return 2 * n.index; |
| 317 | +} |
| 318 | + |
| 319 | +string_dependencest::node_indext |
| 320 | +string_dependencest::node_index(const array_string_exprt &s) const |
| 321 | +{ |
| 322 | + return 2 * node_index_pool.at(s) + 1; |
| 323 | +} |
| 324 | + |
| 325 | +optionalt<string_dependencest::builtin_function_nodet> |
| 326 | +string_dependencest::get_builtin_function_node(node_indext i) const |
| 327 | +{ |
| 328 | + if(i % 2 == 0) |
| 329 | + return builtin_function_nodet(i / 2); |
| 330 | + return {}; |
| 331 | +} |
| 332 | + |
| 333 | +optionalt<string_dependencest::string_nodet> |
| 334 | +string_dependencest::get_string_node(node_indext i) const |
| 335 | +{ |
| 336 | + if(i % 2 == 1 && i / 2 < string_nodes.size()) |
| 337 | + return string_nodes[i / 2]; |
| 338 | + return {}; |
| 339 | +} |
| 340 | + |
| 341 | +bool add_node( |
| 342 | + string_dependencest &dependencies, |
| 343 | + const equal_exprt &equation, |
| 344 | + array_poolt &array_pool) |
| 345 | +{ |
| 346 | + const auto fun_app = |
| 347 | + expr_try_dynamic_cast<function_application_exprt>(equation.rhs()); |
| 348 | + if(!fun_app) |
| 349 | + return false; |
| 350 | + |
| 351 | + auto builtin_function = to_string_builtin_function(*fun_app, array_pool); |
| 352 | + |
| 353 | + if(!builtin_function) |
| 354 | + { |
| 355 | + add_unknown_dependency_to_string_subexprs( |
| 356 | + dependencies, *fun_app, array_pool); |
| 357 | + return true; |
| 358 | + } |
| 359 | + |
| 360 | + const auto &builtin_function_node = dependencies.make_node(builtin_function); |
| 361 | + // Warning: `builtin_function` has been emptied and should not be used anymore |
| 362 | + |
| 363 | + if( |
| 364 | + const auto &string_result = |
| 365 | + dependencies.get_builtin_function(builtin_function_node).string_result()) |
| 366 | + dependencies.add_dependency(*string_result, builtin_function_node); |
| 367 | + else |
| 368 | + add_dependency_to_string_subexprs( |
| 369 | + dependencies, *fun_app, builtin_function_node, array_pool); |
| 370 | + |
| 371 | + return true; |
| 372 | +} |
| 373 | + |
| 374 | +void string_dependencest::for_each_successor( |
| 375 | + const std::size_t &i, |
| 376 | + const std::function<void(const std::size_t &)> &f) const |
| 377 | +{ |
| 378 | + if(const auto &builtin_function_node = get_builtin_function_node(i)) |
| 379 | + { |
| 380 | + const string_builtin_functiont &p = |
| 381 | + get_builtin_function(*builtin_function_node); |
| 382 | + std::for_each( |
| 383 | + p.string_arguments().begin(), |
| 384 | + p.string_arguments().end(), |
| 385 | + [&](const array_string_exprt &s) { f(node_index(s)); }); |
| 386 | + } |
| 387 | + else if(const auto &s = get_string_node(i)) |
| 388 | + { |
| 389 | + std::for_each( |
| 390 | + s->dependencies.begin(), |
| 391 | + s->dependencies.end(), |
| 392 | + [&](const builtin_function_nodet &p) { f(node_index(p)); }); |
| 393 | + } |
| 394 | + else |
| 395 | + UNREACHABLE; |
| 396 | +} |
| 397 | + |
| 398 | +void string_dependencest::output_dot( |
| 399 | + std::ostream &stream, |
| 400 | + std::function<std::string(const exprt &)> to_string) const |
| 401 | +{ |
| 402 | + stream << "digraph dependencies {\n"; |
| 403 | + |
| 404 | + output_dot_generic<std::size_t>( |
| 405 | + stream, |
| 406 | + (std::size_t)size(), |
| 407 | + [&]( |
| 408 | + const std::size_t &i, |
| 409 | + const std::function<void(const std::size_t &)> &f) { // NOLINT |
| 410 | + for_each_successor(i, f); |
| 411 | + }); |
| 412 | + |
| 413 | + stream << '}' << std::endl; |
| 414 | +} |
0 commit comments