Skip to content

Commit 16e9599

Browse files
authored
Merge pull request diffblue#2063 from tautschnig/has-subtype
Make has_subtype and has_subexpr(expr, pred) globally available
2 parents 950f58b + 4625cc5 commit 16e9599

File tree

7 files changed

+100
-81
lines changed

7 files changed

+100
-81
lines changed

src/solvers/refinement/string_refinement.cpp

+7-5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Author: Alberto Griggio, [email protected]
2323
#include <numeric>
2424
#include <stack>
2525
#include <util/expr_iterator.h>
26+
#include <util/expr_util.h>
2627
#include <util/simplify_expr.h>
2728
#include <solvers/sat/satcheck.h>
2829
#include <solvers/refinement/string_constraint_instantiation.h>
@@ -340,8 +341,8 @@ static union_find_replacet generate_symbol_resolution_from_equations(
340341
// function applications can be ignored because they will be replaced
341342
// in the convert_function_application step of dec_solve
342343
}
343-
else if(lhs.type().id() != ID_pointer &&
344-
has_char_pointer_subtype(lhs.type()))
344+
else if(
345+
lhs.type().id() != ID_pointer && has_char_pointer_subtype(lhs.type(), ns))
345346
{
346347
if(rhs.type().id() == ID_struct)
347348
{
@@ -432,7 +433,7 @@ static void add_string_equation_to_symbol_resolution(
432433
{
433434
symbol_resolve.make_union(eq.lhs(), eq.rhs());
434435
}
435-
else if(has_string_subtype(eq.lhs().type()))
436+
else if(has_subtype(eq.lhs().type(), ID_string, ns))
436437
{
437438
if(eq.rhs().type().id() == ID_struct)
438439
{
@@ -484,8 +485,9 @@ union_find_replacet string_identifiers_resolution_from_equations(
484485
for(const auto &expr : rhs_strings)
485486
equation_map.add(i, expr);
486487
}
487-
else if(eq.lhs().type().id() != ID_pointer &&
488-
has_string_subtype(eq.lhs().type()))
488+
else if(
489+
eq.lhs().type().id() != ID_pointer &&
490+
has_subtype(eq.lhs().type(), ID_string, ns))
489491
{
490492
std::vector<exprt> lhs_strings = extract_strings_from_lhs(eq.lhs());
491493

src/solvers/refinement/string_refinement_util.cpp

+5-38
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <functional>
1212
#include <iostream>
1313
#include <util/arith_tools.h>
14+
#include <util/expr_util.h>
1415
#include <util/ssa_expr.h>
1516
#include <util/std_expr.h>
1617
#include <util/expr_iterator.h>
@@ -45,49 +46,15 @@ bool is_char_pointer_type(const typet &type)
4546
return type.id() == ID_pointer && is_char_type(type.subtype());
4647
}
4748

48-
bool has_subtype(
49-
const typet &type,
50-
const std::function<bool(const typet &)> &pred)
49+
bool has_char_pointer_subtype(const typet &type, const namespacet &ns)
5150
{
52-
if(pred(type))
53-
return true;
54-
55-
if(type.id() == ID_struct || type.id() == ID_union)
56-
{
57-
const struct_union_typet &struct_type = to_struct_union_type(type);
58-
return std::any_of(
59-
struct_type.components().begin(),
60-
struct_type.components().end(), // NOLINTNEXTLINE
61-
[&](const struct_union_typet::componentt &comp) {
62-
return has_subtype(comp.type(), pred);
63-
});
64-
}
65-
66-
return std::any_of( // NOLINTNEXTLINE
67-
type.subtypes().begin(), type.subtypes().end(), [&](const typet &t) {
68-
return has_subtype(t, pred);
69-
});
70-
}
71-
72-
bool has_char_pointer_subtype(const typet &type)
73-
{
74-
return has_subtype(type, is_char_pointer_type);
75-
}
76-
77-
bool has_string_subtype(const typet &type)
78-
{
79-
// NOLINTNEXTLINE
80-
return has_subtype(
81-
type, [](const typet &subtype) { return subtype == string_typet(); });
51+
return has_subtype(type, is_char_pointer_type, ns);
8252
}
8353

8454
bool has_char_array_subexpr(const exprt &expr, const namespacet &ns)
8555
{
86-
const auto it = std::find_if(
87-
expr.depth_begin(), expr.depth_end(), [&](const exprt &e) { // NOLINT
88-
return is_char_array_type(e.type(), ns);
89-
});
90-
return it != expr.depth_end();
56+
return has_subexpr(
57+
expr, [&](const exprt &e) { return is_char_array_type(e.type(), ns); });
9158
}
9259

9360
sparse_arrayt::sparse_arrayt(const with_exprt &expr)

src/solvers/refinement/string_refinement_util.h

+2-23
Original file line numberDiff line numberDiff line change
@@ -35,34 +35,13 @@ bool is_char_array_type(const typet &type, const namespacet &ns);
3535
bool is_char_pointer_type(const typet &type);
3636

3737
/// \param type: a type
38-
/// \param pred: a predicate
39-
/// \return true if one of the subtype of `type` satisfies predicate `pred`.
40-
/// The meaning of "subtype" is in the algebraic datatype sense:
41-
/// for example, the subtypes of a struct are the types of its
42-
/// components, the subtype of a pointer is the type it points to,
43-
/// etc...
44-
/// For instance in the type `t` defined by
45-
/// `{ int a; char[] b; double * c; { bool d} e}`, `int`, `char`,
46-
/// `double` and `bool` are subtypes of `t`.
47-
bool has_subtype(
48-
const typet &type,
49-
const std::function<bool(const typet &)> &pred);
50-
51-
/// \param type: a type
38+
/// \param ns: namespace
5239
/// \return true if a subtype of `type` is an pointer of characters.
5340
/// The meaning of "subtype" is in the algebraic datatype sense:
5441
/// for example, the subtypes of a struct are the types of its
5542
/// components, the subtype of a pointer is the type it points to,
5643
/// etc...
57-
bool has_char_pointer_subtype(const typet &type);
58-
59-
/// \param type: a type
60-
/// \return true if a subtype of `type` is string_typet.
61-
/// The meaning of "subtype" is in the algebraic datatype sense:
62-
/// for example, the subtypes of a struct are the types of its
63-
/// components, the subtype of a pointer is the type it points to,
64-
/// etc...
65-
bool has_string_subtype(const typet &type);
44+
bool has_char_pointer_subtype(const typet &type, const namespacet &ns);
6645

6746
/// \param expr: an expression
6847
/// \param ns: namespace

src/util/expr_util.cpp

+45-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Author: Daniel Kroening, [email protected]
1010
#include "expr_util.h"
1111

1212
#include "expr.h"
13+
#include "expr_iterator.h"
1314
#include "fixedbv.h"
1415
#include "ieee_float.h"
1516
#include "std_expr.h"
@@ -120,18 +121,58 @@ exprt boolean_negate(const exprt &src)
120121
return not_exprt(src);
121122
}
122123

124+
bool has_subexpr(
125+
const exprt &expr,
126+
const std::function<bool(const exprt &)> &pred)
127+
{
128+
const auto it = std::find_if(expr.depth_begin(), expr.depth_end(), pred);
129+
return it != expr.depth_end();
130+
}
131+
123132
bool has_subexpr(const exprt &src, const irep_idt &id)
124133
{
125-
if(src.id()==id)
134+
return has_subexpr(
135+
src, [&](const exprt &subexpr) { return subexpr.id() == id; });
136+
}
137+
138+
bool has_subtype(
139+
const typet &type,
140+
const std::function<bool(const typet &)> &pred,
141+
const namespacet &ns)
142+
{
143+
if(pred(type))
126144
return true;
145+
else if(type.id() == ID_symbol)
146+
return has_subtype(ns.follow(type), pred, ns);
147+
else if(type.id() == ID_c_enum_tag)
148+
return has_subtype(ns.follow_tag(to_c_enum_tag_type(type)), pred, ns);
149+
else if(type.id() == ID_struct || type.id() == ID_union)
150+
{
151+
const struct_union_typet &struct_union_type = to_struct_union_type(type);
127152

128-
forall_operands(it, src)
129-
if(has_subexpr(*it, id))
130-
return true;
153+
for(const auto &comp : struct_union_type.components())
154+
if(has_subtype(comp.type(), pred, ns))
155+
return true;
156+
}
157+
// do not look into pointer subtypes as this could cause unbounded recursion
158+
else if(type.id() == ID_array || type.id() == ID_vector)
159+
return has_subtype(type.subtype(), pred, ns);
160+
else if(type.has_subtypes())
161+
{
162+
for(const auto &subtype : type.subtypes())
163+
if(has_subtype(subtype, pred, ns))
164+
return true;
165+
}
131166

132167
return false;
133168
}
134169

170+
bool has_subtype(const typet &type, const irep_idt &id, const namespacet &ns)
171+
{
172+
return has_subtype(
173+
type, [&](const typet &subtype) { return subtype.id() == id; }, ns);
174+
}
175+
135176
if_exprt lift_if(const exprt &src, std::size_t operand_number)
136177
{
137178
PRECONDITION(operand_number<src.operands().size());

src/util/expr_util.h

+25
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Author: Daniel Kroening, [email protected]
1919

2020
#include "irep.h"
2121

22+
#include <functional>
23+
2224
class exprt;
2325
class symbol_exprt;
2426
class update_exprt;
@@ -41,9 +43,32 @@ exprt is_not_zero(const exprt &, const namespacet &ns);
4143
/// and swapping false and true
4244
exprt boolean_negate(const exprt &);
4345

46+
/// returns true if the expression has a subexpression that satisfies pred
47+
bool has_subexpr(const exprt &, const std::function<bool(const exprt &)> &pred);
48+
4449
/// returns true if the expression has a subexpression with given ID
4550
bool has_subexpr(const exprt &, const irep_idt &);
4651

52+
/// returns true if any of the contained types satisfies pred
53+
/// \param type: a type
54+
/// \param pred: a predicate
55+
/// \param ns: namespace for symbol type lookups
56+
/// \return true if one of the subtype of `type` satisfies predicate `pred`.
57+
/// The meaning of "subtype" is in the algebraic datatype sense:
58+
/// for example, the subtypes of a struct are the types of its
59+
/// components, the subtype of a pointer is the type it points to,
60+
/// etc...
61+
/// For instance in the type `t` defined by
62+
/// `{ int a; char[] b; double * c; { bool d} e}`, `int`, `char`,
63+
/// `double` and `bool` are subtypes of `t`.
64+
bool has_subtype(
65+
const typet &type,
66+
const std::function<bool(const typet &)> &pred,
67+
const namespacet &ns);
68+
69+
/// returns true if any of the contained types is id
70+
bool has_subtype(const typet &, const irep_idt &id, const namespacet &);
71+
4772
/// lift up an if_exprt one level
4873
if_exprt lift_if(const exprt &, std::size_t operand_number);
4974

unit/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ SRC += unit_tests.cpp \
3838
solvers/refinement/string_constraint_instantiation/instantiate_not_contains.cpp \
3939
solvers/refinement/string_refinement/concretize_array.cpp \
4040
solvers/refinement/string_refinement/dependency_graph.cpp \
41-
solvers/refinement/string_refinement/has_subtype.cpp \
4241
solvers/refinement/string_refinement/substitute_array_list.cpp \
4342
solvers/refinement/string_refinement/string_symbol_resolution.cpp \
4443
solvers/refinement/string_refinement/sparse_array.cpp \
4544
solvers/refinement/string_refinement/union_find_replace.cpp \
4645
util/expr_cast/expr_cast.cpp \
4746
util/expr_iterator.cpp \
47+
util/has_subtype.cpp \
4848
util/irep.cpp \
4949
util/irep_sharing.cpp \
5050
util/message.cpp \
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/*******************************************************************\
22
3-
Module: Unit tests for has_subtype in
4-
solvers/refinement/string_refinement.cpp
3+
Module: Unit tests for has_subtype in expr_util.cpp
54
65
Author: Diffblue Ltd.
76
@@ -10,7 +9,10 @@
109
#include <testing-utils/catch.hpp>
1110

1211
#include <util/c_types.h>
13-
#include <solvers/refinement/string_refinement.h>
12+
#include <util/expr_util.h>
13+
#include <util/namespace.h>
14+
#include <util/symbol_table.h>
15+
1416
#include <java_bytecode/java_types.h>
1517

1618
// Curryfied version of type comparison.
@@ -23,12 +25,15 @@ static std::function<bool(const typet &)> is_type(const typet &t1)
2325

2426
SCENARIO("has_subtype", "[core][solvers][refinement][string_refinement]")
2527
{
28+
const symbol_tablet symbol_table;
29+
const namespacet ns(symbol_table);
30+
2631
const typet char_type = java_char_type();
2732
const typet int_type = java_int_type();
2833
const typet bool_type = java_boolean_type();
2934

30-
REQUIRE(has_subtype(char_type, is_type(char_type)));
31-
REQUIRE_FALSE(has_subtype(char_type, is_type(int_type)));
35+
REQUIRE(has_subtype(char_type, is_type(char_type), ns));
36+
REQUIRE_FALSE(has_subtype(char_type, is_type(int_type), ns));
3237

3338
GIVEN("a struct with char and int fields")
3439
{
@@ -37,12 +42,12 @@ SCENARIO("has_subtype", "[core][solvers][refinement][string_refinement]")
3742
struct_type.components().emplace_back("int_field", int_type);
3843
THEN("char and int are subtypes")
3944
{
40-
REQUIRE(has_subtype(struct_type, is_type(char_type)));
41-
REQUIRE(has_subtype(struct_type, is_type(int_type)));
45+
REQUIRE(has_subtype(struct_type, is_type(char_type), ns));
46+
REQUIRE(has_subtype(struct_type, is_type(int_type), ns));
4247
}
4348
THEN("bool is not a subtype")
4449
{
45-
REQUIRE_FALSE(has_subtype(struct_type, is_type(bool_type)));
50+
REQUIRE_FALSE(has_subtype(struct_type, is_type(bool_type), ns));
4651
}
4752
}
4853

@@ -51,11 +56,11 @@ SCENARIO("has_subtype", "[core][solvers][refinement][string_refinement]")
5156
pointer_typet ptr_type = pointer_type(char_type);
5257
THEN("char is a subtype")
5358
{
54-
REQUIRE(has_subtype(ptr_type, is_type(char_type)));
59+
REQUIRE(has_subtype(ptr_type, is_type(char_type), ns));
5560
}
5661
THEN("int is not a subtype")
5762
{
58-
REQUIRE_FALSE(has_subtype(ptr_type, is_type(int_type)));
63+
REQUIRE_FALSE(has_subtype(ptr_type, is_type(int_type), ns));
5964
}
6065
}
6166
}

0 commit comments

Comments
 (0)