12 #include <unordered_set>
27 const exprt &return_code,
30 const auto name = expr_checked_cast<symbol_exprt>(fun_app.
function());
33 const irep_idt &
id = name.get_identifier();
35 if(
id == ID_cprover_string_insert_func)
36 return std::make_unique<string_insertion_builtin_functiont>(
37 return_code, fun_app.
arguments(), array_pool);
39 if(
id == ID_cprover_string_concat_func)
40 return std::make_unique<string_concatenation_builtin_functiont>(
41 return_code, fun_app.
arguments(), array_pool);
43 if(
id == ID_cprover_string_concat_char_func)
44 return std::make_unique<string_concat_char_builtin_functiont>(
45 return_code, fun_app.
arguments(), array_pool);
47 if(
id == ID_cprover_string_format_func)
48 return std::make_unique<string_format_builtin_functiont>(
49 return_code, fun_app.
arguments(), array_pool);
51 if(
id == ID_cprover_string_of_int_func)
52 return std::make_unique<string_of_int_builtin_functiont>(
53 return_code, fun_app.
arguments(), array_pool);
55 if(
id == ID_cprover_string_char_set_func)
56 return std::make_unique<string_set_char_builtin_functiont>(
57 return_code, fun_app.
arguments(), array_pool);
59 if(
id == ID_cprover_string_to_lower_case_func)
60 return std::make_unique<string_to_lower_case_builtin_functiont>(
61 return_code, fun_app.
arguments(), array_pool);
63 if(
id == ID_cprover_string_to_upper_case_func)
64 return std::make_unique<string_to_upper_case_builtin_functiont>(
65 return_code, fun_app.
arguments(), array_pool);
67 return std::make_unique<string_builtin_function_with_no_evalt>(
68 return_code, fun_app, array_pool);
75 if(!entry_inserted.second)
78 string_nodes.emplace_back(e, entry_inserted.first->second);
82 std::unique_ptr<const string_dependenciest::string_nodet>
87 return std::make_unique<const string_nodet>(
string_nodes.at(it->second));
92 std::unique_ptr<string_builtin_functiont> builtin_function)
144 fun_app.
arguments()[1].type().id() == ID_pointer)
152 for(
const auto &expr : fun_app.
arguments())
157 [&](
const exprt &e) {
158 if(is_refined_string_type(e.type()))
160 const auto string_struct = expr_checked_cast<struct_exprt>(e);
161 const auto string = of_argument(array_pool, string_struct);
162 dependencies.add_dependency(string, builtin_function_node);
170 const std::function<
exprt(
const exprt &)> &get_value)
const
180 const auto &f = node.result_from;
181 if(f && node.dependencies.size() == 1)
203 const auto fun_app = expr_try_dynamic_cast<function_application_exprt>(expr);
207 bool copy_differs_from_expr =
false;
208 for(std::size_t i = 0; i < expr.
operands().size(); ++i)
215 copy_differs_from_expr =
true;
218 if(copy_differs_from_expr)
223 const exprt return_code = fresh_symbol(
"string_builtin_return", expr.
type());
224 auto builtin_function =
228 const auto &builtin_function_node =
229 dependencies.
make_node(std::move(builtin_function));
232 const auto &string_result =
235 dependencies.
add_dependency(*string_result, builtin_function_node);
236 auto &node = dependencies.
get_node(*string_result);
240 for(
const auto &arg : builtin_function_node.data->string_arguments())
244 (void)dependencies.
get_node(atomic);
250 dependencies, *fun_app, builtin_function_node, array_pool);
257 const std::function<
void(
const string_nodet &)> &f)
const
259 for(
const auto &s : node.
data->string_arguments())
261 std::vector<std::reference_wrapper<const exprt>> stack({s});
262 while(!stack.empty())
264 const auto current = stack.back();
266 if(
const auto if_expr = expr_try_dynamic_cast<if_exprt>(current.get()))
268 stack.emplace_back(if_expr->true_case());
269 stack.emplace_back(if_expr->false_case());
276 "dependencies of the node should have been added to the graph at "
278 current.get().pretty());
295 const std::function<
void(
const nodet &)> &f)
const
314 const std::function<
void(
const nodet &)> &f)
const
317 f(
nodet(string_node));
324 const auto for_each =
325 [&](
const std::function<void(
const nodet &)> &f) {
328 const auto for_each_succ =
329 [&](
const nodet &n,
const std::function<void(
const nodet &)> &f) {
332 const auto node_to_string = [&](
const nodet &n) {
333 std::stringstream ostream;
339 return ostream.str();
341 stream <<
"digraph dependencies {\n";
342 output_dot_generic<nodet>(
343 stream, for_each, for_each_succ, node_to_string, node_to_string);
344 stream <<
'}' << std::endl;
351 std::unordered_set<nodet, node_hash> test_dependencies;
354 if(builtin.data->maybe_testing_function())
355 test_dependencies.insert(
nodet(builtin));
362 const std::function<
void(
const nodet &)> &f) {
369 if(test_dependencies.count(
nodet(node)))
372 merge(constraints, builtin.data->constraints(generator, message_handler));
375 constraints.existential.push_back(node.data->length_constraint());
Correspondance between arrays and pointers string representations.
array_string_exprt find(const exprt &pointer, const exprt &length)
Creates a new array if the pointer is not pointing to an array.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Base class for all expressions.
typet & type()
Return the type of the expression.
Application of (mathematical) function.
const irep_idt & id() const
Base class for string functions that are built in the solver.
virtual std::optional< array_string_exprt > string_result() const
A builtin function node contains a builtin function call.
std::unique_ptr< string_builtin_functiont > data
enum string_dependenciest::nodet::@6 kind
A string node points to builtin_function on which it depends.
std::optional< std::size_t > result_from
std::vector< std::size_t > dependencies
Keep track of dependencies between strings.
std::unique_ptr< const string_nodet > node_at(const array_string_exprt &e) const
std::vector< std::optional< exprt > > eval_string_cache
void for_each_node(const std::function< void(const nodet &)> &f) const
Applies f on all nodes.
builtin_function_nodet & make_node(std::unique_ptr< string_builtin_functiont > builtin_function)
void output_dot(std::ostream &stream) const
void clean_cache()
Clean the cache used by eval
std::vector< builtin_function_nodet > builtin_function_nodes
Set of nodes representing builtin_functions.
std::optional< exprt > eval(const array_string_exprt &s, const std::function< exprt(const exprt &)> &get_value) const
Attempt to evaluate the given string from the dependencies and valuation of strings on which it depen...
void clear()
Clear the content of the dependency graph.
const string_builtin_functiont & get_builtin_function(const builtin_function_nodet &node) const
std::unordered_map< array_string_exprt, std::size_t, irep_hash > node_index_pool
Nodes describing dependencies of a string: values of the map correspond to indexes in the vector stri...
std::vector< string_nodet > string_nodes
Set of nodes representing strings.
void for_each_dependency(const string_nodet &node, const std::function< void(const builtin_function_nodet &)> &f) const
Applies f to each node on which node depends.
string_constraintst add_constraints(string_constraint_generatort &generatort, message_handlert &message_handler)
For all builtin call on which a test (or an unsupported buitin) result depends, add the corresponding...
void for_each_successor(const nodet &i, const std::function< void(const nodet &)> &f) const
Applies f on all successors of the node n.
void add_dependency(const array_string_exprt &e, const builtin_function_nodet &builtin_function)
Add edge from node for e to node for builtin_function if e is a simple array expression.
string_nodet & get_node(const array_string_exprt &e)
Generation of fresh symbols of a given type.
Forward depth-first search iterators These iterators' copy operations are expensive,...
A Template Class for Graphs.
void get_reachable(Container &set, const std::function< void(const typename Container::value_type &, const std::function< void(const typename Container::value_type &)> &)> &for_each_successor)
Add to set, nodes that are reachable from set.
#define CHECK_RETURN(CONDITION)
#define PRECONDITION(CONDITION)
bool is_ssa_expr(const exprt &expr)
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Builtin functions for string concatenations.
void merge(string_constraintst &result, string_constraintst other)
Merge two sets of constraints by appending to the first one.
static std::unique_ptr< string_builtin_functiont > to_string_builtin_function(const function_application_exprt &fun_app, const exprt &return_code, array_poolt &array_pool)
Construct a string_builtin_functiont object from a function application.
std::optional< exprt > add_node(string_dependenciest &dependencies, const exprt &expr, array_poolt &array_pool, symbol_generatort &fresh_symbol)
When a sub-expression of expr is a builtin_function, add a "string_builtin_function" node to the grap...
static void for_each_atomic_string(const array_string_exprt &e, const std::function< void(const array_string_exprt &)> f)
Applies f on all strings contained in e that are not if-expressions.
static void add_dependency_to_string_subexprs(string_dependenciest &dependencies, const function_application_exprt &fun_app, const string_dependenciest::builtin_function_nodet &builtin_function_node, array_poolt &array_pool)
Keeps track of dependencies between strings.
array_string_exprt & to_array_string_expr(exprt &expr)
Collection of constraints of different types: existential formulas, universal formulas,...