diff --git a/src/solvers/refinement/string_refinement.cpp b/src/solvers/refinement/string_refinement.cpp index 19e3e90c0d1..c2685dc6202 100644 --- a/src/solvers/refinement/string_refinement.cpp +++ b/src/solvers/refinement/string_refinement.cpp @@ -23,6 +23,7 @@ Author: Alberto Griggio, alberto.griggio@gmail.com #include #include #include +#include #include #include #include @@ -340,8 +341,8 @@ static union_find_replacet generate_symbol_resolution_from_equations( // function applications can be ignored because they will be replaced // in the convert_function_application step of dec_solve } - else if(lhs.type().id() != ID_pointer && - has_char_pointer_subtype(lhs.type())) + else if( + lhs.type().id() != ID_pointer && has_char_pointer_subtype(lhs.type(), ns)) { if(rhs.type().id() == ID_struct) { @@ -432,7 +433,7 @@ static void add_string_equation_to_symbol_resolution( { symbol_resolve.make_union(eq.lhs(), eq.rhs()); } - else if(has_string_subtype(eq.lhs().type())) + else if(has_subtype(eq.lhs().type(), ID_string, ns)) { if(eq.rhs().type().id() == ID_struct) { @@ -484,8 +485,9 @@ union_find_replacet string_identifiers_resolution_from_equations( for(const auto &expr : rhs_strings) equation_map.add(i, expr); } - else if(eq.lhs().type().id() != ID_pointer && - has_string_subtype(eq.lhs().type())) + else if( + eq.lhs().type().id() != ID_pointer && + has_subtype(eq.lhs().type(), ID_string, ns)) { std::vector lhs_strings = extract_strings_from_lhs(eq.lhs()); diff --git a/src/solvers/refinement/string_refinement_util.cpp b/src/solvers/refinement/string_refinement_util.cpp index 7c8b4679b32..a93df7b75ef 100644 --- a/src/solvers/refinement/string_refinement_util.cpp +++ b/src/solvers/refinement/string_refinement_util.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -45,49 +46,15 @@ bool is_char_pointer_type(const typet &type) return type.id() == ID_pointer && is_char_type(type.subtype()); } -bool has_subtype( - const typet &type, - const std::function &pred) +bool has_char_pointer_subtype(const typet &type, const namespacet &ns) { - if(pred(type)) - return true; - - if(type.id() == ID_struct || type.id() == ID_union) - { - const struct_union_typet &struct_type = to_struct_union_type(type); - return std::any_of( - struct_type.components().begin(), - struct_type.components().end(), // NOLINTNEXTLINE - [&](const struct_union_typet::componentt &comp) { - return has_subtype(comp.type(), pred); - }); - } - - return std::any_of( // NOLINTNEXTLINE - type.subtypes().begin(), type.subtypes().end(), [&](const typet &t) { - return has_subtype(t, pred); - }); -} - -bool has_char_pointer_subtype(const typet &type) -{ - return has_subtype(type, is_char_pointer_type); -} - -bool has_string_subtype(const typet &type) -{ - // NOLINTNEXTLINE - return has_subtype( - type, [](const typet &subtype) { return subtype == string_typet(); }); + return has_subtype(type, is_char_pointer_type, ns); } bool has_char_array_subexpr(const exprt &expr, const namespacet &ns) { - const auto it = std::find_if( - expr.depth_begin(), expr.depth_end(), [&](const exprt &e) { // NOLINT - return is_char_array_type(e.type(), ns); - }); - return it != expr.depth_end(); + return has_subexpr( + expr, [&](const exprt &e) { return is_char_array_type(e.type(), ns); }); } sparse_arrayt::sparse_arrayt(const with_exprt &expr) diff --git a/src/solvers/refinement/string_refinement_util.h b/src/solvers/refinement/string_refinement_util.h index e7dab142c68..b228f147662 100644 --- a/src/solvers/refinement/string_refinement_util.h +++ b/src/solvers/refinement/string_refinement_util.h @@ -35,34 +35,13 @@ bool is_char_array_type(const typet &type, const namespacet &ns); bool is_char_pointer_type(const typet &type); /// \param type: a type -/// \param pred: a predicate -/// \return true if one of the subtype of `type` satisfies predicate `pred`. -/// The meaning of "subtype" is in the algebraic datatype sense: -/// for example, the subtypes of a struct are the types of its -/// components, the subtype of a pointer is the type it points to, -/// etc... -/// For instance in the type `t` defined by -/// `{ int a; char[] b; double * c; { bool d} e}`, `int`, `char`, -/// `double` and `bool` are subtypes of `t`. -bool has_subtype( - const typet &type, - const std::function &pred); - -/// \param type: a type +/// \param ns: namespace /// \return true if a subtype of `type` is an pointer of characters. /// The meaning of "subtype" is in the algebraic datatype sense: /// for example, the subtypes of a struct are the types of its /// components, the subtype of a pointer is the type it points to, /// etc... -bool has_char_pointer_subtype(const typet &type); - -/// \param type: a type -/// \return true if a subtype of `type` is string_typet. -/// The meaning of "subtype" is in the algebraic datatype sense: -/// for example, the subtypes of a struct are the types of its -/// components, the subtype of a pointer is the type it points to, -/// etc... -bool has_string_subtype(const typet &type); +bool has_char_pointer_subtype(const typet &type, const namespacet &ns); /// \param expr: an expression /// \param ns: namespace diff --git a/src/util/expr_util.cpp b/src/util/expr_util.cpp index 2ce8c19f086..70b429fca93 100644 --- a/src/util/expr_util.cpp +++ b/src/util/expr_util.cpp @@ -10,6 +10,7 @@ Author: Daniel Kroening, kroening@kroening.com #include "expr_util.h" #include "expr.h" +#include "expr_iterator.h" #include "fixedbv.h" #include "ieee_float.h" #include "std_expr.h" @@ -120,18 +121,58 @@ exprt boolean_negate(const exprt &src) return not_exprt(src); } +bool has_subexpr( + const exprt &expr, + const std::function &pred) +{ + const auto it = std::find_if(expr.depth_begin(), expr.depth_end(), pred); + return it != expr.depth_end(); +} + bool has_subexpr(const exprt &src, const irep_idt &id) { - if(src.id()==id) + return has_subexpr( + src, [&](const exprt &subexpr) { return subexpr.id() == id; }); +} + +bool has_subtype( + const typet &type, + const std::function &pred, + const namespacet &ns) +{ + if(pred(type)) return true; + else if(type.id() == ID_symbol) + return has_subtype(ns.follow(type), pred, ns); + else if(type.id() == ID_c_enum_tag) + return has_subtype(ns.follow_tag(to_c_enum_tag_type(type)), pred, ns); + else if(type.id() == ID_struct || type.id() == ID_union) + { + const struct_union_typet &struct_union_type = to_struct_union_type(type); - forall_operands(it, src) - if(has_subexpr(*it, id)) - return true; + for(const auto &comp : struct_union_type.components()) + if(has_subtype(comp.type(), pred, ns)) + return true; + } + // do not look into pointer subtypes as this could cause unbounded recursion + else if(type.id() == ID_array || type.id() == ID_vector) + return has_subtype(type.subtype(), pred, ns); + else if(type.has_subtypes()) + { + for(const auto &subtype : type.subtypes()) + if(has_subtype(subtype, pred, ns)) + return true; + } return false; } +bool has_subtype(const typet &type, const irep_idt &id, const namespacet &ns) +{ + return has_subtype( + type, [&](const typet &subtype) { return subtype.id() == id; }, ns); +} + if_exprt lift_if(const exprt &src, std::size_t operand_number) { PRECONDITION(operand_number + class exprt; class symbol_exprt; class update_exprt; @@ -41,9 +43,32 @@ exprt is_not_zero(const exprt &, const namespacet &ns); /// and swapping false and true exprt boolean_negate(const exprt &); +/// returns true if the expression has a subexpression that satisfies pred +bool has_subexpr(const exprt &, const std::function &pred); + /// returns true if the expression has a subexpression with given ID bool has_subexpr(const exprt &, const irep_idt &); +/// returns true if any of the contained types satisfies pred +/// \param type: a type +/// \param pred: a predicate +/// \param ns: namespace for symbol type lookups +/// \return true if one of the subtype of `type` satisfies predicate `pred`. +/// The meaning of "subtype" is in the algebraic datatype sense: +/// for example, the subtypes of a struct are the types of its +/// components, the subtype of a pointer is the type it points to, +/// etc... +/// For instance in the type `t` defined by +/// `{ int a; char[] b; double * c; { bool d} e}`, `int`, `char`, +/// `double` and `bool` are subtypes of `t`. +bool has_subtype( + const typet &type, + const std::function &pred, + const namespacet &ns); + +/// returns true if any of the contained types is id +bool has_subtype(const typet &, const irep_idt &id, const namespacet &); + /// lift up an if_exprt one level if_exprt lift_if(const exprt &, std::size_t operand_number); diff --git a/unit/Makefile b/unit/Makefile index 11468e5cf2f..c71f00bb57d 100644 --- a/unit/Makefile +++ b/unit/Makefile @@ -38,13 +38,13 @@ SRC += unit_tests.cpp \ solvers/refinement/string_constraint_instantiation/instantiate_not_contains.cpp \ solvers/refinement/string_refinement/concretize_array.cpp \ solvers/refinement/string_refinement/dependency_graph.cpp \ - solvers/refinement/string_refinement/has_subtype.cpp \ solvers/refinement/string_refinement/substitute_array_list.cpp \ solvers/refinement/string_refinement/string_symbol_resolution.cpp \ solvers/refinement/string_refinement/sparse_array.cpp \ solvers/refinement/string_refinement/union_find_replace.cpp \ util/expr_cast/expr_cast.cpp \ util/expr_iterator.cpp \ + util/has_subtype.cpp \ util/irep.cpp \ util/irep_sharing.cpp \ util/message.cpp \ diff --git a/unit/solvers/refinement/string_refinement/has_subtype.cpp b/unit/util/has_subtype.cpp similarity index 64% rename from unit/solvers/refinement/string_refinement/has_subtype.cpp rename to unit/util/has_subtype.cpp index b69a057e018..0867720a63e 100644 --- a/unit/solvers/refinement/string_refinement/has_subtype.cpp +++ b/unit/util/has_subtype.cpp @@ -1,7 +1,6 @@ /*******************************************************************\ - Module: Unit tests for has_subtype in - solvers/refinement/string_refinement.cpp + Module: Unit tests for has_subtype in expr_util.cpp Author: Diffblue Ltd. @@ -10,7 +9,10 @@ #include #include -#include +#include +#include +#include + #include // Curryfied version of type comparison. @@ -23,12 +25,15 @@ static std::function is_type(const typet &t1) SCENARIO("has_subtype", "[core][solvers][refinement][string_refinement]") { + const symbol_tablet symbol_table; + const namespacet ns(symbol_table); + const typet char_type = java_char_type(); const typet int_type = java_int_type(); const typet bool_type = java_boolean_type(); - REQUIRE(has_subtype(char_type, is_type(char_type))); - REQUIRE_FALSE(has_subtype(char_type, is_type(int_type))); + REQUIRE(has_subtype(char_type, is_type(char_type), ns)); + REQUIRE_FALSE(has_subtype(char_type, is_type(int_type), ns)); GIVEN("a struct with char and int fields") { @@ -37,12 +42,12 @@ SCENARIO("has_subtype", "[core][solvers][refinement][string_refinement]") struct_type.components().emplace_back("int_field", int_type); THEN("char and int are subtypes") { - REQUIRE(has_subtype(struct_type, is_type(char_type))); - REQUIRE(has_subtype(struct_type, is_type(int_type))); + REQUIRE(has_subtype(struct_type, is_type(char_type), ns)); + REQUIRE(has_subtype(struct_type, is_type(int_type), ns)); } THEN("bool is not a subtype") { - REQUIRE_FALSE(has_subtype(struct_type, is_type(bool_type))); + REQUIRE_FALSE(has_subtype(struct_type, is_type(bool_type), ns)); } } @@ -51,11 +56,11 @@ SCENARIO("has_subtype", "[core][solvers][refinement][string_refinement]") pointer_typet ptr_type = pointer_type(char_type); THEN("char is a subtype") { - REQUIRE(has_subtype(ptr_type, is_type(char_type))); + REQUIRE(has_subtype(ptr_type, is_type(char_type), ns)); } THEN("int is not a subtype") { - REQUIRE_FALSE(has_subtype(ptr_type, is_type(int_type))); + REQUIRE_FALSE(has_subtype(ptr_type, is_type(int_type), ns)); } } }