Skip to content

Commit b0c4cfa

Browse files
author
thk123
committed
Correctly handle generic classes that have a array field
Previously we only converted types that were precisely a generic parameter. Now we deal with the case where the array is T type'd.
1 parent 7c7d73e commit b0c4cfa

File tree

3 files changed

+117
-65
lines changed

3 files changed

+117
-65
lines changed

src/java_bytecode/generate_java_generic_type.cpp

+67-26
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#include <java_bytecode/java_types.h>
1212
#include <java_bytecode/java_utils.h>
1313

14-
1514
generate_java_generic_typet::generate_java_generic_typet(
1615
message_handlert &message_handler):
1716
message_handler(message_handler)
@@ -43,31 +42,14 @@ symbolt generate_java_generic_typet::operator()(
4342

4443
// Small auxiliary function, to perform the inplace
4544
// modification of the generic fields.
46-
auto replace_type_for_generic_field=
47-
[&](struct_union_typet::componentt &component)
48-
{
49-
if(is_java_generic_parameter(component.type()))
50-
{
51-
auto replacement_type_param=
52-
to_java_generic_class_type(replacement_type);
53-
54-
auto component_identifier=
55-
to_java_generic_parameter(component.type()).type_variable()
56-
.get_identifier();
57-
58-
optionalt<size_t> results=java_generics_get_index_for_subtype(
59-
replacement_type_param, component_identifier);
60-
61-
INVARIANT(
62-
results.has_value(),
63-
"generic component type not found");
64-
65-
if(results)
66-
{
67-
component.type()=
68-
existing_generic_type.generic_type_variables()[*results];
69-
}
70-
}
45+
auto replace_type_for_generic_field =
46+
[&](struct_union_typet::componentt &component) {
47+
48+
component.type() = substitute_type(
49+
component.type(),
50+
to_java_generic_class_type(replacement_type),
51+
existing_generic_type);
52+
7153
return component;
7254
};
7355

@@ -98,6 +80,65 @@ symbolt generate_java_generic_typet::operator()(
9880
return *symbol;
9981
}
10082

83+
/// For a given type, if the type contains a Java generic parameter, we look
84+
/// that parameter up and return the relevant type. This works recursively on
85+
/// arrays so that T [] is converted to RelevantType [].
86+
/// \param parameter_type: The type under consideration
87+
/// \param generic_class: The generic class that the \p parameter_type
88+
/// belongs to (e.g. the type of a component of the class). This is used to
89+
/// look up the mapping from name of generic parameter to its index.
90+
/// \param generic_reference: The instantiated version of the generic class
91+
/// used to look up the instantiated type. This is expected to be fully
92+
/// instantiated.
93+
/// \return A newly constructed type with generic parameters replaced, or if
94+
/// there are none to replace, the original type.
95+
typet generate_java_generic_typet::substitute_type(
96+
const typet &parameter_type,
97+
const java_generics_class_typet &generic_class,
98+
const java_generic_typet &generic_reference) const
99+
{
100+
if(is_java_generic_parameter(parameter_type))
101+
{
102+
auto component_identifier = to_java_generic_parameter(parameter_type)
103+
.type_variable()
104+
.get_identifier();
105+
106+
optionalt<size_t> results =
107+
java_generics_get_index_for_subtype(generic_class, component_identifier);
108+
109+
INVARIANT(results.has_value(), "generic component type not found");
110+
111+
if(results)
112+
{
113+
return generic_reference.generic_type_variables()[*results];
114+
}
115+
else
116+
{
117+
return parameter_type;
118+
}
119+
}
120+
else if(
121+
parameter_type.id() == ID_pointer &&
122+
parameter_type.subtype().id() == ID_symbol)
123+
{
124+
const symbol_typet &array_subtype =
125+
to_symbol_type(parameter_type.subtype());
126+
if(is_java_array_tag(array_subtype.get_identifier()))
127+
{
128+
const typet &array_element_type = java_array_element_type(array_subtype);
129+
130+
const typet &new_array_type =
131+
substitute_type(array_element_type, generic_class, generic_reference);
132+
133+
typet replacement_array_type = java_array_type('a');
134+
replacement_array_type.subtype().set(
135+
ID_C_element_type, new_array_type);
136+
return replacement_array_type;
137+
}
138+
}
139+
return parameter_type;
140+
}
141+
101142
/// Build a unique tag for the generic to be instantiated.
102143
/// \param existing_generic_type The type we want to concretise
103144
/// \param original_class

src/java_bytecode/generate_java_generic_type.h

+5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ class generate_java_generic_typet
2828
const java_generic_typet &existing_generic_type,
2929
const java_class_typet &original_class) const;
3030

31+
typet substitute_type(
32+
const typet &parameter_type,
33+
const java_generics_class_typet &replacement_type,
34+
const java_generic_typet &generic_reference) const;
35+
3136
message_handlert &message_handler;
3237
};
3338

unit/java_bytecode/generate_concrete_generic_type/generate_java_generic_type.cpp

+45-39
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#include <testing-utils/require_type.h>
1818
#include <testing-utils/generic_utils.h>
1919
#include <util/ui_message.h>
20-
#include <iostream>
2120

2221
/// Helper function to specalise a generic class from a named component of a
2322
/// named class
@@ -231,48 +230,55 @@ SCENARIO(
231230
require_type::require_pointer(
232231
java_array_element_type(test_field_array),
233232
symbol_typet("java::java.lang.Float"));
233+
}
234+
}
234235

235-
GIVEN("Specialising a generic class with an array field")
236-
{
237-
const irep_idt &inner_class = "genericArray";
236+
SCENARIO("generate_java_generic_type with a generic array field")
237+
{
238+
const irep_idt harness_class = "java::generic_field_array_instantiation";
239+
GIVEN("A generic class with a field of type T []")
240+
{
241+
symbol_tablet new_symbol_table = load_java_class(
242+
"generic_field_array_instantiation",
243+
"./java_bytecode/generate_concrete_generic_type");
244+
245+
const irep_idt &inner_class = "genericArray";
238246

247+
WHEN("We specialise that class from a reference to it")
248+
{
239249
specialise_generic_from_component(
240250
harness_class, "genericArrayField", new_symbol_table);
241-
242-
const irep_idt &specialised_class_name = id2string(harness_class) + "$" +
243-
id2string(inner_class) +
244-
"<java::java.lang.Float>";
245-
REQUIRE(new_symbol_table.has_symbol(specialised_class_name));
246-
247-
const symbolt test_class_symbol=
248-
new_symbol_table.lookup_ref(specialised_class_name);
249-
250-
REQUIRE(test_class_symbol.type.id()==ID_struct);
251-
const struct_typet::componentt &field_component=
252-
require_type::require_component(
253-
to_struct_type(test_class_symbol.type),
254-
"arrayField");
255-
const typet &test_field_type=field_component.type();
256-
257-
std::cout << test_field_type.pretty() << std::endl;
258-
259-
std::cout << "Hello world" << std::endl;
251+
THEN(
252+
"There should be a specialised version of the class in the symbol "
253+
"table")
254+
{
255+
const irep_idt &specialised_class_name = id2string(harness_class) +
256+
"$" + id2string(inner_class) +
257+
"<java::java.lang.Float>";
258+
REQUIRE(new_symbol_table.has_symbol(specialised_class_name));
259+
260+
const symbolt test_class_symbol =
261+
new_symbol_table.lookup_ref(specialised_class_name);
262+
263+
THEN("The array field should be specialised to be an array of floats")
264+
{
265+
REQUIRE(test_class_symbol.type.id() == ID_struct);
266+
const struct_typet::componentt &field_component =
267+
require_type::require_component(
268+
to_struct_type(test_class_symbol.type), "arrayField");
269+
270+
const pointer_typet &component_pointer_type =
271+
require_type::require_pointer(field_component.type(), {});
272+
273+
const symbol_typet &pointer_subtype = require_type::require_symbol(
274+
component_pointer_type.subtype(), "java::array[reference]");
275+
276+
const typet &array_type = java_array_element_type(pointer_subtype);
277+
278+
require_type::require_pointer(
279+
array_type, symbol_typet("java::java.lang.Float"));
280+
}
281+
}
260282
}
261-
262283
}
263284
}
264-
//
265-
//SCENARIO("Specialising a generic class with a generic field ")
266-
//{
267-
// const irep_idt harness_class =
268-
// "java::generic_field_array_instantiation";
269-
// GIVEN("A generic type with a generic array field")
270-
// {
271-
// symbol_tablet new_symbol_table=
272-
// load_java_class(
273-
// "generic_field_array_instantiation",
274-
// "./java_bytecode/generate_concrete_generic_type");
275-
//
276-
//
277-
// }
278-
//}

0 commit comments

Comments
 (0)