Skip to content

Make has_subtype and has_subexpr(expr, pred) globally available #2063

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions src/solvers/refinement/string_refinement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Author: Alberto Griggio, alberto.griggio@gmail.com
#include <numeric>
#include <stack>
#include <util/expr_iterator.h>
#include <util/expr_util.h>
#include <util/simplify_expr.h>
#include <solvers/sat/satcheck.h>
#include <solvers/refinement/string_constraint_instantiation.h>
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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<exprt> lhs_strings = extract_strings_from_lhs(eq.lhs());

Expand Down
43 changes: 5 additions & 38 deletions src/solvers/refinement/string_refinement_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <functional>
#include <iostream>
#include <util/arith_tools.h>
#include <util/expr_util.h>
#include <util/ssa_expr.h>
#include <util/std_expr.h>
#include <util/expr_iterator.h>
Expand Down Expand Up @@ -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<bool(const typet &)> &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)
Expand Down
25 changes: 2 additions & 23 deletions src/solvers/refinement/string_refinement_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<bool(const typet &)> &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
Expand Down
49 changes: 45 additions & 4 deletions src/util/expr_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -120,18 +121,58 @@ exprt boolean_negate(const exprt &src)
return not_exprt(src);
}

bool has_subexpr(
const exprt &expr,
const std::function<bool(const exprt &)> &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<bool(const typet &)> &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<src.operands().size());
Expand Down
25 changes: 25 additions & 0 deletions src/util/expr_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Author: Daniel Kroening, kroening@kroening.com

#include "irep.h"

#include <functional>

class exprt;
class symbol_exprt;
class update_exprt;
Expand All @@ -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<bool(const exprt &)> &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<bool(const typet &)> &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);

Expand Down
2 changes: 1 addition & 1 deletion unit/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
Original file line number Diff line number Diff line change
@@ -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.

Expand All @@ -10,7 +9,10 @@
#include <testing-utils/catch.hpp>

#include <util/c_types.h>
#include <solvers/refinement/string_refinement.h>
#include <util/expr_util.h>
#include <util/namespace.h>
#include <util/symbol_table.h>

#include <java_bytecode/java_types.h>

// Curryfied version of type comparison.
Expand All @@ -23,12 +25,15 @@ static std::function<bool(const typet &)> 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")
{
Expand All @@ -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));
}
}

Expand All @@ -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));
}
}
}