Skip to content

Commit 318474f

Browse files
Merge pull request diffblue#2678 from romainbrenguier/feature/extend-builtin-functions-part3
Eval function for string_to_lower/upper_case builtin functions
2 parents d9f9dd9 + a44468b commit 318474f

16 files changed

+385
-98
lines changed
Binary file not shown.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
public class Test {
2+
public String det()
3+
{
4+
StringBuilder builder = new StringBuilder();
5+
builder.append("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toLowerCase());
6+
builder.append("abcdeghijklmnopfrstuqwxyzABCDvFGHIJKLMENOPQRSTUVWXYZ".toLowerCase());
7+
builder.append("abcdeghijlmnopqrstvwxyzABCDEFGHIJuKLMNOPQRSfkTUVWXYZ".toLowerCase());
8+
builder.append("acdefghijklmnopqrsuvwxyzABCDEFbGHIJKLMNOPtQRSTUVWXYZ".toLowerCase());
9+
builder.append("abcdfghijklmnopqrstuvwxyzABCDEFGHIJeKLMNOPQRSTUVWXYZ".toLowerCase());
10+
return builder.toString();
11+
}
12+
13+
public String nonDet(String s)
14+
{
15+
if(s.length() < 20)
16+
return "Short string";
17+
if(!s.startsWith("A"))
18+
return "String not starting with A";
19+
20+
StringBuilder builder = new StringBuilder();
21+
builder.append(s.toLowerCase());
22+
builder.append(s.toLowerCase());
23+
builder.append(":");
24+
builder.append(s);
25+
builder.append(":");
26+
builder.append(s.toLowerCase());
27+
builder.append(s.toLowerCase());
28+
return builder.toString();
29+
}
30+
31+
public String withDependency(String s, boolean b)
32+
{
33+
// Filter
34+
if(s == null || s.length() < 20)
35+
return "Short string";
36+
if(!s.endsWith("A"))
37+
return "String not ending with A";
38+
39+
// Act
40+
String result = s + s.toLowerCase();
41+
42+
// Assert
43+
if(b) {
44+
assert(result.endsWith("a"));
45+
} else {
46+
assert(!result.endsWith("a"));
47+
}
48+
return result;
49+
}
50+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
Test.class
3+
--function Test.withDependency --verbosity 10 --max-nondet-string-length 10000
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
assertion at file Test.java line 44 .*: SUCCESS
7+
assertion at file Test.java line 46 .*: FAILURE
8+
--
9+
--
10+
Check that when there are dependencies, axioms are adde correctly.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
Test.class
3+
--function Test.det --verbosity 10 --cover location
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
coverage.* file Test.java line 9 .*: SATISFIED
7+
--
8+
adding lemma .*nondet_infinite_array
9+
--
10+
Check that using the string dependence informations, no lemma involving arrays is added
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
Test.class
3+
--function Test.nonDet --verbosity 10 --cover location --max-nondet-string-length 1000
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
coverage.* file Test.java line 27 .*: SATISFIED
7+
--
8+
adding lemma .*nondet_infinite_array
9+
--
10+
Check that using the string dependence informations, no lemma involving arrays is added
Binary file not shown.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
public class Test {
2+
public String det()
3+
{
4+
StringBuilder builder = new StringBuilder();
5+
builder.append("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toLowerCase());
6+
builder.append("abcdeghijklmnopfrstuqwxyzABCDvFGHIJKLMENOPQRSTUVWXYZ".toUpperCase());
7+
builder.append("abcdeghijlmnopqrstvwxyzABCDEFGHIJuKLMNOPQRSfkTUVWXYZ".toUpperCase());
8+
builder.append("acdefghijklmnopqrsuvwxyzABCDEFbGHIJKLMNOPtQRSTUVWXYZ".toUpperCase());
9+
builder.append("abcdfghijklmnopqrstuvwxyzABCDEFGHIJeKLMNOPQRSTUVWXYZ".toUpperCase());
10+
return builder.toString();
11+
}
12+
13+
public String nonDet(String s)
14+
{
15+
if(s.length() < 20)
16+
return "Short string";
17+
if(!s.startsWith("a"))
18+
return "String not starting with a";
19+
20+
StringBuilder builder = new StringBuilder();
21+
builder.append(s.toUpperCase());
22+
builder.append(s.toUpperCase());
23+
builder.append(":");
24+
builder.append(s);
25+
builder.append(":");
26+
builder.append(s.toUpperCase());
27+
builder.append(s.toUpperCase());
28+
return builder.toString();
29+
}
30+
31+
public String withDependency(String s, boolean b)
32+
{
33+
// Filter
34+
if(s == null || s.length() < 20)
35+
return "Short string";
36+
if(!s.endsWith("a"))
37+
return "String not ending with a";
38+
39+
// Act
40+
String result = s + s.toUpperCase();
41+
42+
// Assert
43+
if(b) {
44+
assert(result.endsWith("A"));
45+
} else {
46+
assert(!result.endsWith("A"));
47+
}
48+
return result;
49+
}
50+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
Test.class
3+
--function Test.withDependency --verbosity 10 --max-nondet-string-length 10000
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
assertion at file Test.java line 44 .*: SUCCESS
7+
assertion at file Test.java line 46 .*: FAILURE
8+
--
9+
--
10+
Check that when there are dependencies, axioms are added correctly.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
Test.class
3+
--function Test.det --verbosity 10 --cover location
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
coverage.* file Test.java line 9 .*: SATISFIED
7+
--
8+
adding lemma .*nondet_infinite_array
9+
--
10+
Check that using the string dependence informations, no lemma involving arrays is added
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
Test.class
3+
--function Test.nonDet --verbosity 10 --cover location --max-nondet-string-length 1000
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
coverage.* file Test.java line 27 .*: SATISFIED
7+
--
8+
adding lemma .*nondet_infinite_array
9+
--
10+
Check that using the string dependence informations, no lemma involving arrays is added

src/solvers/refinement/string_builtin_function.cpp

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
#include "string_constraint_generator.h"
1010

11-
/// Get the valuation of the string, given a valuation
11+
/// Given a function `get_value` which gives a valuation to expressions, attempt
12+
/// to find the current value of the array `a`. If the valuation of some
13+
/// characters are missing, then return an empty optional.
1214
static optionalt<std::vector<mp_integer>> eval_string(
1315
const array_string_exprt &a,
1416
const std::function<exprt(const exprt &)> &get_value);
@@ -187,6 +189,51 @@ exprt string_set_char_builtin_functiont::length_constraint() const
187189
equal_exprt(return_code, return_value));
188190
}
189191

192+
static bool eval_is_upper_case(const mp_integer &c)
193+
{
194+
// Characters between 'A' and 'Z' are upper-case
195+
// Characters between 0xc0 (latin capital A with grave)
196+
// and 0xd6 (latin capital O with diaeresis) are upper-case
197+
// Characters between 0xd8 (latin capital O with stroke)
198+
// and 0xde (latin capital thorn) are upper-case
199+
return ('A' <= c && c <= 'Z') || (0xc0 <= c && c <= 0xd6) ||
200+
(0xd8 <= c && c <= 0xde);
201+
}
202+
203+
optionalt<exprt> string_to_lower_case_builtin_functiont::eval(
204+
const std::function<exprt(const exprt &)> &get_value) const
205+
{
206+
auto input_opt = eval_string(input, get_value);
207+
if(!input_opt)
208+
return {};
209+
for(mp_integer &c : input_opt.value())
210+
{
211+
if(eval_is_upper_case(c))
212+
c += 0x20;
213+
}
214+
const auto length =
215+
from_integer(input_opt.value().size(), result.length().type());
216+
const array_typet type(result.type().subtype(), length);
217+
return make_string(input_opt.value(), type);
218+
}
219+
220+
optionalt<exprt> string_to_upper_case_builtin_functiont::eval(
221+
const std::function<exprt(const exprt &)> &get_value) const
222+
{
223+
auto input_opt = eval_string(input, get_value);
224+
if(!input_opt)
225+
return {};
226+
for(mp_integer &c : input_opt.value())
227+
{
228+
if(eval_is_upper_case(c - 0x20))
229+
c -= 0x20;
230+
}
231+
const auto length =
232+
from_integer(input_opt.value().size(), result.length().type());
233+
const array_typet type(result.type().subtype(), length);
234+
return make_string(input_opt.value(), type);
235+
}
236+
190237
std::vector<mp_integer> string_insertion_builtin_functiont::eval(
191238
const std::vector<mp_integer> &input1_value,
192239
const std::vector<mp_integer> &input2_value,

src/solvers/refinement/string_builtin_function.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ class string_builtin_functiont
3030
return {};
3131
}
3232

33+
/// Given a function `get_value` which gives a valuation to expressions,
34+
/// attempt to find the result of the builtin function.
35+
/// If not enough information can be gathered from `get_value`, return an
36+
/// empty optional.
3337
virtual optionalt<exprt>
3438
eval(const std::function<exprt(const exprt &)> &get_value) const = 0;
3539

@@ -177,6 +181,72 @@ class string_set_char_builtin_functiont
177181
exprt length_constraint() const override;
178182
};
179183

184+
/// Converting each uppercase character of Basic Latin and Latin-1 supplement
185+
/// to the corresponding lowercase character.
186+
class string_to_lower_case_builtin_functiont
187+
: public string_transformation_builtin_functiont
188+
{
189+
public:
190+
string_to_lower_case_builtin_functiont(
191+
const exprt &return_code,
192+
const std::vector<exprt> &fun_args,
193+
array_poolt &array_pool)
194+
: string_transformation_builtin_functiont(return_code, fun_args, array_pool)
195+
{
196+
}
197+
198+
optionalt<exprt>
199+
eval(const std::function<exprt(const exprt &)> &get_value) const override;
200+
201+
std::string name() const override
202+
{
203+
return "to_lower_case";
204+
}
205+
206+
exprt add_constraints(string_constraint_generatort &generator) const override
207+
{
208+
return generator.add_axioms_for_to_lower_case(result, input);
209+
};
210+
211+
exprt length_constraint() const override
212+
{
213+
return equal_exprt(result.length(), input.length());
214+
};
215+
};
216+
217+
/// Converting each lowercase character of Basic Latin and Latin-1 supplement
218+
/// to the corresponding uppercase character.
219+
class string_to_upper_case_builtin_functiont
220+
: public string_transformation_builtin_functiont
221+
{
222+
public:
223+
string_to_upper_case_builtin_functiont(
224+
const exprt &return_code,
225+
const std::vector<exprt> &fun_args,
226+
array_poolt &array_pool)
227+
: string_transformation_builtin_functiont(return_code, fun_args, array_pool)
228+
{
229+
}
230+
231+
optionalt<exprt>
232+
eval(const std::function<exprt(const exprt &)> &get_value) const override;
233+
234+
std::string name() const override
235+
{
236+
return "to_upper_case";
237+
}
238+
239+
exprt add_constraints(string_constraint_generatort &generator) const override
240+
{
241+
return generator.add_axioms_for_to_upper_case(result, input);
242+
};
243+
244+
exprt length_constraint() const override
245+
{
246+
return equal_exprt(result.length(), input.length());
247+
};
248+
};
249+
180250
/// String inserting a string into another one
181251
class string_insertion_builtin_functiont : public string_builtin_functiont
182252
{

src/solvers/refinement/string_constraint_generator.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@ class string_constraint_generatort final
175175
const array_string_exprt &str,
176176
const exprt &position,
177177
const exprt &character);
178+
exprt add_axioms_for_to_lower_case(
179+
const array_string_exprt &res,
180+
const array_string_exprt &str);
181+
exprt add_axioms_for_to_upper_case(
182+
const array_string_exprt &res,
183+
const array_string_exprt &expr);
178184

179185
private:
180186
symbol_exprt fresh_boolean(const irep_idt &prefix);
@@ -335,9 +341,6 @@ class string_constraint_generatort final
335341
exprt add_axioms_for_substring(const function_application_exprt &f);
336342
exprt add_axioms_for_to_lower_case(const function_application_exprt &f);
337343
exprt add_axioms_for_to_upper_case(const function_application_exprt &f);
338-
exprt add_axioms_for_to_upper_case(
339-
const array_string_exprt &res,
340-
const array_string_exprt &expr);
341344
exprt add_axioms_for_trim(const function_application_exprt &f);
342345

343346
exprt add_axioms_for_code_point(

src/solvers/refinement/string_constraint_generator_main.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -456,10 +456,6 @@ exprt string_constraint_generatort::add_axioms_for_function_application(
456456
res=add_axioms_for_compare_to(expr);
457457
else if(id==ID_cprover_string_literal_func)
458458
res=add_axioms_from_literal(expr);
459-
else if(id==ID_cprover_string_concat_func)
460-
res=add_axioms_for_concat(expr);
461-
else if(id==ID_cprover_string_concat_char_func)
462-
res=add_axioms_for_concat_char(expr);
463459
else if(id==ID_cprover_string_concat_code_point_func)
464460
res=add_axioms_for_concat_code_point(expr);
465461
else if(id==ID_cprover_string_insert_func)
@@ -480,18 +476,10 @@ exprt string_constraint_generatort::add_axioms_for_function_application(
480476
res=add_axioms_for_substring(expr);
481477
else if(id==ID_cprover_string_trim_func)
482478
res=add_axioms_for_trim(expr);
483-
else if(id==ID_cprover_string_to_lower_case_func)
484-
res=add_axioms_for_to_lower_case(expr);
485-
else if(id==ID_cprover_string_to_upper_case_func)
486-
res=add_axioms_for_to_upper_case(expr);
487-
else if(id==ID_cprover_string_char_set_func)
488-
res=add_axioms_for_char_set(expr);
489479
else if(id==ID_cprover_string_empty_string_func)
490480
res=add_axioms_for_empty_string(expr);
491481
else if(id==ID_cprover_string_copy_func)
492482
res=add_axioms_for_copy(expr);
493-
else if(id==ID_cprover_string_of_int_func)
494-
res=add_axioms_from_int(expr);
495483
else if(id==ID_cprover_string_of_int_hex_func)
496484
res=add_axioms_from_int_hex(expr);
497485
else if(id==ID_cprover_string_of_float_func)

0 commit comments

Comments
 (0)