Skip to content

Commit 0ecd008

Browse files
authored
Merge pull request diffblue#2701 from antlechner/antonia/enum-constants
Nondet-initialize enums to be equal to a constant of the same type
2 parents 159bf15 + 5ca6cd2 commit 0ecd008

14 files changed

+357
-106
lines changed
800 Bytes
Binary file not shown.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public enum Color {
2+
RED,
3+
GREEN,
4+
BLUE
5+
}
Binary file not shown.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
public class NondetEnumArg {
2+
3+
public static void canChooseSomeConstant(Color c) {
4+
if (c == null)
5+
return;
6+
assert c != null;
7+
boolean isRed = c.name().startsWith("RED") && c.name().length() == 3
8+
&& c.ordinal() == 0;
9+
boolean isGreen = c.name().startsWith("GREEN") && c.name().length() == 5
10+
&& c.ordinal() == 1;
11+
boolean isBlue = c.name().startsWith("BLUE") && c.name().length() == 4
12+
&& c.ordinal() == 2;
13+
assert (isRed || isGreen || isBlue);
14+
}
15+
16+
public static void canChooseRed(Color c) {
17+
if (c == null)
18+
return;
19+
boolean isGreen = c.name().startsWith("GREEN") && c.name().length() == 5
20+
&& c.ordinal() == 1;
21+
boolean isBlue = c.name().startsWith("BLUE") && c.name().length() == 4
22+
&& c.ordinal() == 2;
23+
assert (isGreen || isBlue);
24+
}
25+
26+
public static void canChooseGreen(Color c) {
27+
if (c == null)
28+
return;
29+
boolean isRed = c.name().startsWith("RED") && c.name().length() == 3
30+
&& c.ordinal() == 0;
31+
boolean isBlue = c.name().startsWith("BLUE") && c.name().length() == 4
32+
&& c.ordinal() == 2;
33+
assert (isRed || isBlue);
34+
}
35+
36+
public static void canChooseBlue(Color c) {
37+
if (c == null)
38+
return;
39+
boolean isRed = c.name().startsWith("RED") && c.name().length() == 3
40+
&& c.ordinal() == 0;
41+
boolean isGreen = c.name().startsWith("GREEN") && c.name().length() == 5
42+
&& c.ordinal() == 1;
43+
assert (isRed || isGreen);
44+
}
45+
46+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
NondetEnumArg.class
3+
--function NondetEnumArg.canChooseSomeConstant --cp `../../../../scripts/format_classpath.sh . ../../../src/java_bytecode/library/core-models.jar`
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
--
9+
The test checks that the name and ordinal fields of nondet-initialized enums
10+
correspond to those of an enum constant of the same type.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
NondetEnumArg.class
3+
--function NondetEnumArg.canChooseRed --cp `../../../../scripts/format_classpath.sh . ../../../src/java_bytecode/library/core-models.jar`
4+
^VERIFICATION FAILED$
5+
--
6+
--
7+
Test 1 of 3 to check that any of the enum constants can be chosen.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
NondetEnumArg.class
3+
--function NondetEnumArg.canChooseGreen --cp `../../../../scripts/format_classpath.sh . ../../../src/java_bytecode/library/core-models.jar`
4+
^VERIFICATION FAILED$
5+
--
6+
--
7+
Test 2 of 3 to check that any of the enum constants can be chosen.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
NondetEnumArg.class
3+
--function NondetEnumArg.canChooseBlue --cp `../../../../scripts/format_classpath.sh . ../../../src/java_bytecode/library/core-models.jar`
4+
^VERIFICATION FAILED$
5+
--
6+
--
7+
Test 3 of 3 to check that any of the enum constants can be chosen.

jbmc/src/java_bytecode/ci_lazy_methods.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,17 @@ void ci_lazy_methodst::initialize_instantiated_classes(
381381
{
382382
if(param.type().id()==ID_pointer)
383383
{
384-
const pointer_typet &original_pointer=to_pointer_type(param.type());
384+
const pointer_typet &original_pointer = to_pointer_type(param.type());
385+
const auto &original_type = ns.follow(original_pointer.subtype());
386+
// Special case for enums. We may want to generalise this, see TG-4689
387+
// and the comment in java_object_factoryt::gen_nondet_pointer_init.
388+
if(
389+
can_cast_type<java_class_typet>(original_type) &&
390+
to_java_class_type(original_type).get_base("java::java.lang.Enum"))
391+
{
392+
add_clinit_call_for_pointer_type(
393+
original_pointer, ns.get_symbol_table(), needed_lazy_methods);
394+
}
385395
needed_lazy_methods.add_all_needed_classes(original_pointer);
386396
}
387397
}
@@ -399,6 +409,29 @@ void ci_lazy_methodst::initialize_instantiated_classes(
399409
needed_lazy_methods.add_needed_class("java::" + id2string(id));
400410
}
401411

412+
/// Helper function for `initialize_instantiated_classes`.
413+
/// For a given pointer_typet that is being noted as needed in
414+
/// `needed_lazy_methods`, notes that its static initializer is also needed.
415+
/// This applies the same logic to the class of `pointer_type` that
416+
/// `java_bytecode_convert_methodt::get_clinit_call` applies e.g. to classes
417+
/// whose constructor we call in a method body. This duplication is unavoidable
418+
/// due to the fact that ci_lazy_methods essentially has to go through the same
419+
/// logic as __CPROVER_start in its initial setup.
420+
/// \param pointer_type: The given pointer_typet
421+
/// \param symbol_table: Used to look up occurrences of static initializers
422+
/// \param [out] needed_lazy_methods: Gets notified of any static initializers
423+
/// that need to be loaded
424+
void ci_lazy_methodst::add_clinit_call_for_pointer_type(
425+
const pointer_typet &pointer_type,
426+
const symbol_tablet &symbol_table,
427+
ci_lazy_methods_neededt &needed_lazy_methods)
428+
{
429+
const irep_idt &pointer_id =
430+
to_symbol_type(pointer_type.subtype()).get_identifier();
431+
const irep_idt &clinit_wrapper = clinit_wrapper_name(pointer_id);
432+
if(symbol_table.symbols.count(clinit_wrapper))
433+
needed_lazy_methods.add_needed_method(clinit_wrapper);
434+
}
402435

403436
/// Get places where virtual functions are called.
404437
/// \param e: expression tree to search

jbmc/src/java_bytecode/ci_lazy_methods.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@ class ci_lazy_methodst:public messaget
120120
const namespacet &ns,
121121
ci_lazy_methods_neededt &needed_lazy_methods);
122122

123+
void add_clinit_call_for_pointer_type(
124+
const pointer_typet &pointer_type,
125+
const symbol_tablet &symbol_table,
126+
ci_lazy_methods_neededt &needed_lazy_methods);
127+
123128
void gather_virtual_callsites(
124129
const exprt &e,
125130
std::unordered_set<exprt, irep_hash> &result);

0 commit comments

Comments
 (0)