Skip to content

Commit 7b17821

Browse files
committed
Add unit test verifying that java_object_factory doesn't strip tag types
Previously if asked to populate a pointer with tagged type (e.g. "Object *") then it would allocate a "struct Object { ... }", i.e. the struct_typet rather than the struct_tag_typet. This verifies that it now retains tag types.
1 parent 2ecdc0e commit 7b17821

19 files changed

+271
-0
lines changed

jbmc/unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ SRC += java_bytecode/ci_lazy_methods/lazy_load_lambdas.cpp \
4444
java_bytecode/java_bytecode_parser/parse_java_class.cpp \
4545
java_bytecode/java_bytecode_parser/parse_java_field.cpp \
4646
java_bytecode/java_object_factory/gen_nondet_string_init.cpp \
47+
java_bytecode/java_object_factory/struct_tag_types.cpp \
4748
java_bytecode/java_replace_nondet/replace_nondet.cpp \
4849
java_bytecode/java_string_library_preprocess/convert_exprt_to_string_exprt.cpp \
4950
java_bytecode/java_types/erase_type_arguments.cpp \
264 Bytes
Binary file not shown.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
public class A {
3+
4+
public B b;
5+
public C c;
6+
7+
}
8+
9+
class B { }
10+
11+
class C { }
228 Bytes
Binary file not shown.
228 Bytes
Binary file not shown.
235 Bytes
Binary file not shown.
849 Bytes
Binary file not shown.
Binary file not shown.
Binary file not shown.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
public class HasArray {
3+
4+
public D[] ds;
5+
6+
}
7+
8+
class D { }
Binary file not shown.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
public class HasEnum {
3+
4+
public E e;
5+
6+
}
7+
8+
enum E { x, y, z }
Binary file not shown.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
public class HasGeneric {
3+
4+
public Generic<String> s;
5+
public Generic<Integer> t;
6+
public OtherGeneric<String> u;
7+
8+
}
9+
10+
class Generic<T> {
11+
T t;
12+
}
13+
14+
class OtherGeneric<T> {
15+
Generic<T> gen;
16+
}
Binary file not shown.
Binary file not shown.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
public class Root {
3+
4+
// This one isn't used in the tests; it just references other classes
5+
// to get them loaded.
6+
7+
A a;
8+
HasArray ha;
9+
HasEnum he;
10+
HasGeneric hg;
11+
12+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
java_bytecode
22
java_object_factory
3+
java-testing-utils
34
langapi # should go away
45
testing-utils
56
util
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for Java-object-factory's treatment of tag types
4+
5+
Author: Diffblue Ltd.
6+
7+
\*******************************************************************/
8+
9+
#include <java-testing-utils/load_java_class.h>
10+
#include <java-testing-utils/require_goto_statements.h>
11+
#include <java_bytecode/java_bytecode_language.h>
12+
#include <java_bytecode/java_object_factory.h>
13+
#include <langapi/mode.h>
14+
#include <testing-utils/use_catch.h>
15+
#include <util/expr_iterator.h>
16+
17+
#include <algorithm>
18+
19+
static bool is_decl_with_struct_tag(const codet &code, const irep_idt &id)
20+
{
21+
if(code.get_statement() != ID_decl)
22+
return false;
23+
24+
const typet &decl_type = to_code_decl(code).symbol().type();
25+
return decl_type.id() == ID_struct_tag &&
26+
to_struct_tag_type(decl_type).get_identifier() == id;
27+
}
28+
29+
static bool is_decl_of_type(const codet &code, const typet &type)
30+
{
31+
return code.get_statement() == ID_decl &&
32+
to_code_decl(code).symbol().type() == type;
33+
}
34+
35+
static bool
36+
contains(const exprt &expr, std::function<bool(const exprt &)> predicate)
37+
{
38+
return std::any_of(expr.depth_begin(), expr.depth_end(), predicate);
39+
}
40+
41+
static bool
42+
contains(const codet &code, std::function<bool(const codet &)> predicate)
43+
{
44+
std::vector<codet> statements =
45+
require_goto_statements::get_all_statements(code);
46+
return std::any_of(statements.begin(), statements.end(), predicate);
47+
}
48+
49+
static bool
50+
contains(const typet &type, std::function<bool(const typet &)> predicate)
51+
{
52+
if(predicate(type))
53+
return true;
54+
55+
if(type.has_subtypes())
56+
{
57+
for(const auto &subtype : to_type_with_subtypes(type).subtypes())
58+
{
59+
if(contains(subtype, predicate))
60+
return true;
61+
}
62+
}
63+
64+
return false;
65+
}
66+
67+
static bool contains_decl_of_type(const codet &code, const typet &type)
68+
{
69+
return contains(code, [&type](const codet &subcode) {
70+
return is_decl_of_type(subcode, type);
71+
});
72+
}
73+
74+
static bool contains_decl_with_struct_tag(const codet &code, const irep_idt &id)
75+
{
76+
return contains(code, [&id](const codet &subcode) {
77+
return is_decl_with_struct_tag(subcode, id);
78+
});
79+
}
80+
81+
static bool uses_raw_struct_types(const typet &type)
82+
{
83+
return contains(
84+
type, [](const typet &subtype) { return subtype.id() == ID_struct; });
85+
}
86+
87+
static bool uses_raw_struct_types(const exprt &expr)
88+
{
89+
return contains(expr, [](const exprt &subexpr) {
90+
return uses_raw_struct_types(subexpr.type());
91+
});
92+
}
93+
94+
code_blockt
95+
initialise_nondet_object_of_type(const typet &type, symbol_tablet &symbol_table)
96+
{
97+
code_blockt created_code;
98+
java_object_factory_parameterst parameters;
99+
select_pointer_typet pointer_selector;
100+
101+
object_factory(
102+
type,
103+
"root",
104+
created_code,
105+
symbol_table,
106+
parameters,
107+
lifetimet::AUTOMATIC_LOCAL,
108+
source_locationt(),
109+
pointer_selector);
110+
111+
return created_code;
112+
}
113+
114+
SCENARIO(
115+
"java_object_factory_tag_types",
116+
"[core][java_bytecode][java_object_factory]")
117+
{
118+
GIVEN("Some classes with fields")
119+
{
120+
register_language(new_java_bytecode_language);
121+
symbol_tablet symbol_table =
122+
load_java_class("Root", "./java_bytecode/java_object_factory");
123+
124+
WHEN("Creating a nondet 'A' object")
125+
{
126+
struct_tag_typet A_type("java::A");
127+
struct_tag_typet B_type("java::B");
128+
struct_tag_typet C_type("java::C");
129+
130+
const auto a_pointer = java_reference_type(A_type);
131+
code_blockt created_code =
132+
initialise_nondet_object_of_type(a_pointer, symbol_table);
133+
134+
THEN("An A, a B and a C object should be allocated")
135+
{
136+
REQUIRE(contains_decl_of_type(created_code, A_type));
137+
REQUIRE(contains_decl_of_type(created_code, B_type));
138+
REQUIRE(contains_decl_of_type(created_code, C_type));
139+
}
140+
141+
THEN("No raw struct expressions should appear")
142+
{
143+
REQUIRE_FALSE(uses_raw_struct_types(created_code));
144+
}
145+
}
146+
147+
WHEN("Creating a nondet 'HasArray' object")
148+
{
149+
struct_tag_typet HasArray_type("java::HasArray");
150+
struct_tag_typet D_type("java::D");
151+
152+
const auto HasArray_pointer = java_reference_type(HasArray_type);
153+
code_blockt created_code =
154+
initialise_nondet_object_of_type(HasArray_pointer, symbol_table);
155+
156+
THEN("A HasArray object should be created")
157+
{
158+
REQUIRE(contains_decl_of_type(created_code, HasArray_type));
159+
}
160+
161+
THEN("No raw struct expressions should appear")
162+
{
163+
REQUIRE_FALSE(uses_raw_struct_types(created_code));
164+
}
165+
}
166+
167+
WHEN("Creating a nondet 'HasEnum' object")
168+
{
169+
struct_tag_typet HasEnum_type("java::HasEnum");
170+
struct_tag_typet E_type("java::E");
171+
172+
const auto HasEnum_pointer = java_reference_type(HasEnum_type);
173+
code_blockt created_code =
174+
initialise_nondet_object_of_type(HasEnum_pointer, symbol_table);
175+
176+
THEN("A HasEnum object should be allocated")
177+
{
178+
REQUIRE(contains_decl_of_type(created_code, HasEnum_type));
179+
}
180+
181+
THEN("No raw struct expressions should appear")
182+
{
183+
REQUIRE_FALSE(uses_raw_struct_types(created_code));
184+
}
185+
}
186+
187+
WHEN("Creating a nondet 'HasGeneric' object")
188+
{
189+
struct_tag_typet HasGeneric_type("java::HasGeneric");
190+
irep_idt generic_id = "java::Generic";
191+
irep_idt other_generic_id = "java::OtherGeneric";
192+
193+
const auto HasGeneric_pointer = java_reference_type(HasGeneric_type);
194+
code_blockt created_code =
195+
initialise_nondet_object_of_type(HasGeneric_pointer, symbol_table);
196+
197+
THEN("An HasGeneric, Generic and OtherGeneric object should be allocated")
198+
{
199+
REQUIRE(contains_decl_of_type(created_code, HasGeneric_type));
200+
// These ones are just checked for a tag rather than a full type because
201+
// the tags are decorated with generic information, and I just want to
202+
// check they (a) are created and (b) don't use expanded types, rather
203+
// than verifying their full structure.
204+
REQUIRE(contains_decl_with_struct_tag(created_code, generic_id));
205+
REQUIRE(contains_decl_with_struct_tag(created_code, other_generic_id));
206+
}
207+
208+
THEN("No raw struct expressions should appear")
209+
{
210+
REQUIRE_FALSE(uses_raw_struct_types(created_code));
211+
}
212+
}
213+
}
214+
}

0 commit comments

Comments
 (0)