Skip to content

Commit 186adb8

Browse files
Make explicit type parameters shadow implicit ones with the same names
Fixes problem where outer class type parameters take precedence over inner class ones Previously field would be given the type of the argument assigned to A::T, not B::T. class A<T> { class B<T> { T field; } }?
1 parent 8fe86ee commit 186adb8

13 files changed

+130
-7
lines changed

jbmc/src/java_bytecode/java_bytecode_convert_class.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,17 @@ void mark_java_implicitly_generic_class_type(
12051205
java_implicitly_generic_class_typet new_class_type(
12061206
class_type, implicit_generic_type_parameters);
12071207

1208+
// Prepend existing parameters so choose those above any inherited
1209+
if(is_java_generic_class_type(class_type))
1210+
{
1211+
const java_generic_class_typet::generic_typest &class_type_params =
1212+
to_java_generic_class_type(class_type).generic_types();
1213+
implicit_generic_type_parameters.insert(
1214+
implicit_generic_type_parameters.begin(),
1215+
class_type_params.begin(),
1216+
class_type_params.end());
1217+
}
1218+
12081219
for(auto &field : new_class_type.components())
12091220
{
12101221
find_and_replace_parameters(

jbmc/unit/java_bytecode/goto_program_generics/MutuallyRecursiveGenerics.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ class Inner<U> {
33
Outer<V, K, U> o;
44
U u;
55
}
6-
Inner<U> inner;
6+
Inner<V> inner;
77
K key;
88
V value;
99
}
Binary file not shown.

jbmc/unit/java_bytecode/goto_program_generics/mutually_recursive_generics.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,45 @@ SCENARIO(
298298
}
299299
}
300300

301+
THEN(
302+
"The Object has a field `example3` of type `Outer<Boolean, Byte, Short>`")
303+
{
304+
const auto &example3_field =
305+
require_goto_statements::require_struct_component_assignment(
306+
tmp_object_name,
307+
{},
308+
"example3",
309+
"java::Outer",
310+
{},
311+
entry_point_code,
312+
symbol_table);
313+
314+
THEN("`example3` has field `inner` of type `Inner<Byte>`")
315+
{
316+
const auto &inner_field =
317+
require_goto_statements::require_struct_component_assignment(
318+
example3_field,
319+
{},
320+
"inner",
321+
"java::Outer$Inner",
322+
{},
323+
entry_point_code,
324+
symbol_table);
325+
326+
THEN("`inner` has a field `u` of type `Byte`")
327+
{
328+
require_goto_statements::require_struct_component_assignment(
329+
inner_field,
330+
{},
331+
"u",
332+
"java::java.lang.Byte",
333+
{},
334+
entry_point_code,
335+
symbol_table);
336+
}
337+
}
338+
}
339+
301340
THEN("The Object has a field `testFoo` of type `Foo<Long>`")
302341
{
303342
const auto &testFoo_field =

jbmc/unit/java_bytecode/java_bytecode_parse_generics/GenericClassWithInnerClasses.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ class GenericInner<U> {
1717
class GenericInnerInner<V>{
1818

1919
}
20+
21+
class ShadowingGenericInner<U> {
22+
U shadowedField;
23+
}
24+
25+
ShadowingGenericInner<String> shadowingField;
2026
}
2127

2228
static class StaticInner<U>{

jbmc/unit/java_bytecode/java_bytecode_parse_generics/parse_generic_class_with_inner_classes.cpp

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ SCENARIO(
1717
const symbol_tablet &new_symbol_table = load_java_class(
1818
"GenericClassWithInnerClasses",
1919
"./java_bytecode/java_bytecode_parse_generics");
20+
namespacet ns{new_symbol_table};
2021

2122
std::string outer_class_name = "GenericClassWithInnerClasses";
2223
std::string outer_class_prefix = "java::" + outer_class_name;
@@ -49,13 +50,59 @@ SCENARIO(
4950
}
5051
THEN("There is a field f3 of generic type with correct arguments")
5152
{
53+
std::string inner_class_prefix = outer_class_prefix + "$GenericInner";
5254
const auto &field = require_type::require_component(generic_class, "f3");
53-
require_type::require_pointer_to_tag(
54-
field.type(), outer_class_prefix + "$GenericInner");
55-
require_type::require_java_generic_type(
56-
field.type(),
57-
{{require_type::type_argument_kindt::Var, outer_class_prefix + "::T"},
58-
{require_type::type_argument_kindt::Inst, "java::java.lang.Integer"}});
55+
const auto &field_type =
56+
require_type::require_pointer_to_tag(field.type(), inner_class_prefix);
57+
java_generic_struct_tag_typet inner_class_tag =
58+
require_type::require_java_generic_struct_tag_type(
59+
field_type.subtype(),
60+
inner_class_prefix,
61+
{
62+
{require_type::type_argument_kindt::Var,
63+
outer_class_prefix + "::T"},
64+
{require_type::type_argument_kindt::Inst,
65+
"java::java.lang.Integer"},
66+
});
67+
const java_generic_class_typet &inner_class =
68+
require_type::require_complete_java_generic_class(
69+
ns.follow_tag(inner_class_tag), {inner_class_prefix + "::U"});
70+
THEN(
71+
"There is a field shadowingField of generic type with correct "
72+
"arguments")
73+
{
74+
std::string shadowing_inner_class_prefix =
75+
inner_class_prefix + "$ShadowingGenericInner";
76+
const auto &shadowing_field =
77+
require_type::require_component(inner_class, "shadowingField");
78+
const auto &shadowing_field_type = require_type::require_pointer_to_tag(
79+
shadowing_field.type(), shadowing_inner_class_prefix);
80+
java_generic_struct_tag_typet shadowing_inner_class_tag =
81+
require_type::require_java_generic_struct_tag_type(
82+
shadowing_field_type.subtype(),
83+
shadowing_inner_class_prefix,
84+
{
85+
{require_type::type_argument_kindt::Var,
86+
inner_class_prefix + "::" + outer_class_name + "::T"},
87+
{require_type::type_argument_kindt::Var,
88+
inner_class_prefix + "::U"},
89+
{require_type::type_argument_kindt::Inst,
90+
"java::java.lang.String"},
91+
});
92+
const java_generic_class_typet &shadowing_inner_class =
93+
require_type::require_complete_java_generic_class(
94+
ns.follow_tag(shadowing_inner_class_tag),
95+
{shadowing_inner_class_prefix + "::U"});
96+
THEN(
97+
"There is a field shadowedField which is the generic parameter of "
98+
"the inner class")
99+
{
100+
const auto &shadowed_field = require_type::require_component(
101+
shadowing_inner_class, "shadowedField");
102+
require_type::require_java_generic_parameter(
103+
shadowed_field.type(), shadowing_inner_class_prefix + "::U");
104+
}
105+
}
59106
}
60107
}
61108

@@ -183,6 +230,26 @@ SCENARIO(
183230
{require_type::type_argument_kindt::Var,
184231
generic_inner_class_prefix + "::U"}});
185232
}
233+
THEN(
234+
"There is a field shadowingField of generic type with a generic "
235+
"type argument of String")
236+
{
237+
std::string shadowing_inner_class_prefix =
238+
generic_inner_class_prefix + "$ShadowingGenericInner";
239+
const auto &field =
240+
require_type::require_component(generic_class, "shadowingField");
241+
require_type::require_pointer_to_tag(
242+
field.type(), shadowing_inner_class_prefix);
243+
require_type::require_java_generic_type(
244+
field.type(),
245+
{
246+
{require_type::type_argument_kindt::Var,
247+
generic_inner_class_prefix + "::" + outer_class_name + "::T"},
248+
{require_type::type_argument_kindt::Var,
249+
generic_inner_class_prefix + "::U"},
250+
{require_type::type_argument_kindt::Inst, "java::java.lang.String"},
251+
});
252+
}
186253
}
187254
}
188255

0 commit comments

Comments
 (0)