Skip to content

Commit 0163362

Browse files
author
svorenova
committed
Adding a unit test for implicitly generic classes
1 parent ba05f18 commit 0163362

11 files changed

+305
-3
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
class GenericClassWithInnerClasses<T>
2+
{
3+
class Inner {
4+
T t1;
5+
Generic<T> t2;
6+
7+
class InnerInner {
8+
T tt1;
9+
Generic<Generic<T>> tt2;
10+
}
11+
}
12+
13+
class GenericInner<U> {
14+
T gt1;
15+
GenericTwoParam<T,U> gt2;
16+
17+
class GenericInnerInner<V>{
18+
19+
}
20+
}
21+
22+
static class StaticInner<U>{
23+
U st;
24+
}
25+
26+
Inner f1;
27+
Inner.InnerInner f2;
28+
GenericInner<Integer> f3;
29+
}
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for parsing generic classes
4+
5+
Author: DiffBlue Limited. All rights reserved.
6+
7+
\*******************************************************************/
8+
9+
#include <testing-utils/catch.hpp>
10+
#include <testing-utils/load_java_class.h>
11+
#include <testing-utils/require_type.h>
12+
13+
SCENARIO(
14+
"parse_generic_class_with_inner_classes",
15+
"[core][java_bytecode][java_bytecode_parse_generics]")
16+
{
17+
const symbol_tablet &new_symbol_table = load_java_class(
18+
"GenericClassWithInnerClasses",
19+
"./java_bytecode/java_bytecode_parse_generics");
20+
21+
std::string outer_class_prefix = "java::GenericClassWithInnerClasses";
22+
23+
WHEN("Generic outer class has fields which are objects of the inner classes")
24+
{
25+
REQUIRE(new_symbol_table.has_symbol(outer_class_prefix));
26+
const symbolt &class_symbol =
27+
new_symbol_table.lookup_ref(outer_class_prefix);
28+
const java_generic_class_typet &generic_class =
29+
require_type::require_java_generic_class(
30+
class_symbol.type, {outer_class_prefix + "::T"});
31+
THEN("There is a field f1 of generic type with correct arguments")
32+
{
33+
const auto &field = require_type::require_component(generic_class, "f1");
34+
require_type::require_pointer(
35+
field.type(), symbol_typet(outer_class_prefix + "$Inner"));
36+
require_type::require_java_generic_type(
37+
field.type(),
38+
{{require_type::type_argument_kindt::Var, outer_class_prefix + "::T"}});
39+
}
40+
THEN("There is a field f2 of generic type with correct arguments")
41+
{
42+
const auto &field = require_type::require_component(generic_class, "f2");
43+
require_type::require_pointer(
44+
field.type(), symbol_typet(outer_class_prefix + "$Inner$InnerInner"));
45+
require_type::require_java_generic_type(
46+
field.type(),
47+
{{require_type::type_argument_kindt::Var, outer_class_prefix + "::T"}});
48+
}
49+
THEN("There is a field f3 of generic type with correct arguments")
50+
{
51+
const auto &field = require_type::require_component(generic_class, "f3");
52+
require_type::require_pointer(
53+
field.type(), symbol_typet(outer_class_prefix + "$GenericInner"));
54+
require_type::require_java_generic_type(
55+
field.type(),
56+
{{require_type::type_argument_kindt::Var, outer_class_prefix + "::T"},
57+
{require_type::type_argument_kindt::Inst, "java::java.lang.Integer"}});
58+
}
59+
}
60+
61+
WHEN("Inner class of a generic outer class is parsed")
62+
{
63+
std::string inner_class_prefix = outer_class_prefix + "$Inner";
64+
REQUIRE(new_symbol_table.has_symbol(inner_class_prefix));
65+
const symbolt &class_symbol =
66+
new_symbol_table.lookup_ref(inner_class_prefix);
67+
68+
THEN("It has correct implicit generic types")
69+
{
70+
const java_implicitly_generic_class_typet &java_class =
71+
require_type::require_java_implicitly_generic_class(
72+
class_symbol.type, {outer_class_prefix + "::T"});
73+
74+
THEN(
75+
"There is a field t1 which is the generic parameter of the outer "
76+
"class")
77+
{
78+
const auto &field = require_type::require_component(java_class, "t1");
79+
require_type::require_java_generic_parameter(
80+
field.type(), outer_class_prefix + "::T");
81+
}
82+
THEN(
83+
"There is a field t2 of generic type with the generic "
84+
"parameter of the outer class")
85+
{
86+
const auto &field = require_type::require_component(java_class, "t2");
87+
require_type::require_pointer(
88+
field.type(), symbol_typet("java::Generic"));
89+
require_type::require_java_generic_type(
90+
field.type(),
91+
{{require_type::type_argument_kindt::Var,
92+
outer_class_prefix + "::T"}});
93+
}
94+
}
95+
}
96+
97+
WHEN("Inner class of an inner class of a generic outer class is parsed")
98+
{
99+
std::string inner_inner_class_prefix =
100+
outer_class_prefix + "$Inner$InnerInner";
101+
REQUIRE(new_symbol_table.has_symbol(inner_inner_class_prefix));
102+
const symbolt &class_symbol =
103+
new_symbol_table.lookup_ref(inner_inner_class_prefix);
104+
105+
THEN("It has correct implicit generic types")
106+
{
107+
const java_implicitly_generic_class_typet &java_class =
108+
require_type::require_java_implicitly_generic_class(
109+
class_symbol.type, {outer_class_prefix + "::T"});
110+
111+
THEN(
112+
"There is a field tt1 which is the generic parameter of the outer "
113+
"class")
114+
{
115+
const auto &field = require_type::require_component(java_class, "tt1");
116+
require_type::require_java_generic_parameter(
117+
field.type(), outer_class_prefix + "::T");
118+
}
119+
THEN(
120+
"There is a field tt2 of nested generic type with the generic "
121+
"parameter of the outer class")
122+
{
123+
const auto &field = require_type::require_component(java_class, "tt2");
124+
require_type::require_pointer(
125+
field.type(), symbol_typet("java::Generic"));
126+
const java_generic_typet &generic_field =
127+
require_type::require_java_generic_type(
128+
field.type(),
129+
{{require_type::type_argument_kindt::Inst, "java::Generic"}});
130+
131+
const typet &type_argument =
132+
generic_field.generic_type_arguments().at(0);
133+
const java_generic_typet generic_type_argument =
134+
require_type::require_java_generic_type(
135+
type_argument,
136+
{{require_type::type_argument_kindt::Var,
137+
outer_class_prefix + "::T"}});
138+
}
139+
}
140+
}
141+
142+
WHEN("Generic inner class of a generic outer class is parsed")
143+
{
144+
std::string generic_inner_class_prefix =
145+
outer_class_prefix + "$GenericInner";
146+
REQUIRE(new_symbol_table.has_symbol(generic_inner_class_prefix));
147+
const symbolt &class_symbol =
148+
new_symbol_table.lookup_ref(generic_inner_class_prefix);
149+
150+
THEN("It has correct generic types and implicit generic types")
151+
{
152+
require_type::require_java_implicitly_generic_class(
153+
class_symbol.type, {outer_class_prefix + "::T"});
154+
const java_generic_class_typet &generic_class =
155+
require_type::require_java_generic_class(
156+
class_symbol.type, {generic_inner_class_prefix + "::U"});
157+
158+
THEN(
159+
"There is a field gt1 which is the generic parameter of the outer "
160+
"class")
161+
{
162+
const auto &field =
163+
require_type::require_component(generic_class, "gt1");
164+
require_type::require_java_generic_parameter(
165+
field.type(), outer_class_prefix + "::T");
166+
}
167+
THEN(
168+
"There is a field gt2 of generic type with the generic "
169+
"parameter of the outer class")
170+
{
171+
const auto &field =
172+
require_type::require_component(generic_class, "gt2");
173+
require_type::require_pointer(
174+
field.type(), symbol_typet("java::GenericTwoParam"));
175+
require_type::require_java_generic_type(
176+
field.type(),
177+
{{require_type::type_argument_kindt::Var,
178+
outer_class_prefix + "::T"},
179+
{require_type::type_argument_kindt::Var,
180+
generic_inner_class_prefix + "::U"}});
181+
}
182+
}
183+
}
184+
185+
WHEN(
186+
"A generic inner class of a generic inner class of a generic outer class "
187+
"is parsed")
188+
{
189+
std::string generic_inner_inner_class_prefix =
190+
outer_class_prefix + "$GenericInner$GenericInnerInner";
191+
REQUIRE(new_symbol_table.has_symbol(generic_inner_inner_class_prefix));
192+
const symbolt &class_symbol =
193+
new_symbol_table.lookup_ref(generic_inner_inner_class_prefix);
194+
195+
THEN("It has correct generic types and implicit generic types")
196+
{
197+
require_type::require_java_implicitly_generic_class(
198+
class_symbol.type,
199+
{outer_class_prefix + "::T", outer_class_prefix + "$GenericInner::U"});
200+
require_type::require_java_generic_class(
201+
class_symbol.type, {generic_inner_inner_class_prefix + "::V"});
202+
}
203+
}
204+
205+
WHEN("A static generic inner class of a generic class is parsed")
206+
{
207+
std::string static_inner_class_prefix = outer_class_prefix + "$StaticInner";
208+
REQUIRE(new_symbol_table.has_symbol(static_inner_class_prefix));
209+
const symbolt &class_symbol =
210+
new_symbol_table.lookup_ref(static_inner_class_prefix);
211+
212+
THEN("It has correct generic types and no implicit generic types")
213+
{
214+
REQUIRE(!is_java_implicitly_generic_class_type(class_symbol.type));
215+
require_type::require_java_generic_class(
216+
class_symbol.type, {static_inner_class_prefix + "::U"});
217+
}
218+
}
219+
}

unit/java_bytecode/java_bytecode_parse_generics/parse_signature_descriptor_mismatch.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ SCENARIO(
2828

2929
const symbolt &inner_symbol = new_symbol_table.lookup_ref(inner_prefix);
3030
const class_typet &inner_class_type =
31-
require_type::require_java_non_generic_class(inner_symbol.type);
31+
require_type::require_java_implicitly_generic_class(inner_symbol.type);
3232
}
3333

3434
THEN(
@@ -63,8 +63,7 @@ SCENARIO(
6363

6464
const symbolt &inner_enum_symbol =
6565
new_symbol_table.lookup_ref(inner_enum_prefix);
66-
const class_typet &inner_enum_class_type =
67-
require_type::require_java_non_generic_class(inner_enum_symbol.type);
66+
require_type::require_java_non_generic_class(inner_enum_symbol.type);
6867
}
6968

7069
THEN(

unit/testing-utils/require_type.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,53 @@ java_generic_class_typet require_type::require_java_generic_class(
270270
return java_generic_class_type;
271271
}
272272

273+
/// Verify that a class is a complete, valid java implicitly generic class.
274+
/// \param class_type: the class
275+
/// \return: A reference to the java generic class type.
276+
java_implicitly_generic_class_typet
277+
require_type::require_java_implicitly_generic_class(const typet &class_type)
278+
{
279+
const class_typet &class_class_type = require_complete_class(class_type);
280+
java_class_typet java_class_type = to_java_class_type(class_class_type);
281+
282+
REQUIRE(is_java_implicitly_generic_class_type(java_class_type));
283+
java_implicitly_generic_class_typet java_implicitly_generic_class_type =
284+
to_java_implicitly_generic_class_type(java_class_type);
285+
286+
return java_implicitly_generic_class_type;
287+
}
288+
289+
/// Verify that a class is a complete, valid java generic class with the
290+
/// specified list of variables.
291+
/// \param class_type: the class
292+
/// \param type_variables: vector of type variables
293+
/// \return: A reference to the java generic class type.
294+
java_implicitly_generic_class_typet
295+
require_type::require_java_implicitly_generic_class(
296+
const typet &class_type,
297+
const std::initializer_list<irep_idt> &implicit_type_variables)
298+
{
299+
const java_implicitly_generic_class_typet java_implicitly_generic_class_type =
300+
require_type::require_java_implicitly_generic_class(class_type);
301+
302+
const java_implicitly_generic_class_typet::implicit_generic_typest
303+
&implicit_generic_type_vars =
304+
java_implicitly_generic_class_type.implicit_generic_types();
305+
REQUIRE(implicit_generic_type_vars.size() == implicit_type_variables.size());
306+
REQUIRE(
307+
std::equal(
308+
implicit_type_variables.begin(),
309+
implicit_type_variables.end(),
310+
implicit_generic_type_vars.begin(),
311+
[](const irep_idt &type_var_name, const java_generic_parametert &param)
312+
{
313+
REQUIRE(is_java_generic_parameter(param));
314+
return param.type_variable().get_identifier() == type_var_name;
315+
}));
316+
317+
return java_implicitly_generic_class_type;
318+
}
319+
273320
/// Verify that a class is a complete, valid nongeneric java class
274321
/// \param class_type: the class
275322
/// \return: A reference to the java generic class type.
@@ -280,6 +327,7 @@ require_type::require_java_non_generic_class(const typet &class_type)
280327
java_class_typet java_class_type = to_java_class_type(class_class_type);
281328

282329
REQUIRE(!is_java_generic_class_type(java_class_type));
330+
REQUIRE(!is_java_implicitly_generic_class_type(java_class_type));
283331

284332
return java_class_type;
285333
}

unit/testing-utils/require_type.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ java_generic_class_typet require_java_generic_class(
7676
const typet &class_type,
7777
const std::initializer_list<irep_idt> &type_parameters);
7878

79+
java_implicitly_generic_class_typet
80+
require_java_implicitly_generic_class(const typet &class_type);
81+
82+
java_implicitly_generic_class_typet require_java_implicitly_generic_class(
83+
const typet &class_type,
84+
const std::initializer_list<irep_idt> &implicit_type_variables);
85+
7986
java_class_typet require_java_non_generic_class(const typet &class_type);
8087
}
8188

0 commit comments

Comments
 (0)