Skip to content

Commit 7f53f02

Browse files
author
Thomas Kiley
authored
Merge pull request diffblue#1569 from thk123/bugfix/TG-1403/generic-field-arrays
[TG-1403] Correctly specialise classes with generic arrays or generic types
2 parents 94ffce3 + 0f98cb4 commit 7f53f02

18 files changed

+334
-101
lines changed

src/java_bytecode/generate_java_generic_type.cpp

Lines changed: 105 additions & 32 deletions
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)
@@ -33,41 +32,26 @@ symbolt generate_java_generic_typet::operator()(
3332

3433
INVARIANT(
3534
pointer_subtype.id()==ID_struct, "Only pointers to classes in java");
35+
INVARIANT(
36+
is_java_generic_class_type(pointer_subtype),
37+
"Generic references type must be a generic class");
3638

37-
const java_class_typet &replacement_type=
38-
to_java_class_type(pointer_subtype);
39-
const irep_idt new_tag=build_generic_tag(
40-
existing_generic_type, replacement_type);
41-
struct_union_typet::componentst replacement_components=
42-
replacement_type.components();
39+
const java_generic_class_typet &generic_class_definition =
40+
to_java_generic_class_type(to_java_class_type(pointer_subtype));
41+
42+
const irep_idt new_tag =
43+
build_generic_tag(existing_generic_type, generic_class_definition);
44+
struct_union_typet::componentst replacement_components =
45+
generic_class_definition.components();
4346

4447
// Small auxiliary function, to perform the inplace
4548
// 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_generics_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);
49+
auto replace_type_for_generic_field =
50+
[&](struct_union_typet::componentt &component) {
6051

61-
INVARIANT(
62-
results.has_value(),
63-
"generic component type not found");
52+
component.type() = substitute_type(
53+
component.type(), generic_class_definition, existing_generic_type);
6454

65-
if(results)
66-
{
67-
component.type()=
68-
existing_generic_type.generic_type_variables()[*results];
69-
}
70-
}
7155
return component;
7256
};
7357

@@ -79,8 +63,8 @@ symbolt generate_java_generic_typet::operator()(
7963
replacement_components.end(),
8064
replace_type_for_generic_field);
8165

82-
std::size_t after_modification_size=
83-
replacement_type.components().size();
66+
std::size_t after_modification_size =
67+
generic_class_definition.components().size();
8468

8569
INVARIANT(
8670
pre_modification_size==after_modification_size,
@@ -98,6 +82,95 @@ symbolt generate_java_generic_typet::operator()(
9882
return *symbol;
9983
}
10084

85+
/// For a given type, if the type contains a Java generic parameter, we look
86+
/// that parameter up and return the relevant type. This works recursively on
87+
/// arrays so that T [] is converted to RelevantType [].
88+
/// \param parameter_type: The type under consideration
89+
/// \param generic_class: The generic class that the \p parameter_type
90+
/// belongs to (e.g. the type of a component of the class). This is used to
91+
/// look up the mapping from name of generic parameter to its index.
92+
/// \param generic_reference: The instantiated version of the generic class
93+
/// used to look up the instantiated type. This is expected to be fully
94+
/// instantiated.
95+
/// \return A newly constructed type with generic parameters replaced, or if
96+
/// there are none to replace, the original type.
97+
typet generate_java_generic_typet::substitute_type(
98+
const typet &parameter_type,
99+
const java_generic_class_typet &generic_class,
100+
const java_generic_typet &generic_reference) const
101+
{
102+
if(is_java_generic_parameter(parameter_type))
103+
{
104+
auto component_identifier = to_java_generic_parameter(parameter_type)
105+
.type_variable()
106+
.get_identifier();
107+
108+
optionalt<size_t> results =
109+
java_generics_get_index_for_subtype(generic_class, component_identifier);
110+
111+
INVARIANT(results.has_value(), "generic component type not found");
112+
return generic_reference.generic_type_variables()[*results];
113+
}
114+
else if(parameter_type.id() == ID_pointer)
115+
{
116+
if(is_java_generic_type(parameter_type))
117+
{
118+
const java_generic_typet &generic_type =
119+
to_java_generic_type(parameter_type);
120+
121+
java_generic_typet::generic_type_variablest replaced_type_variables;
122+
123+
// Swap each parameter
124+
std::transform(
125+
generic_type.generic_type_variables().begin(),
126+
generic_type.generic_type_variables().end(),
127+
std::back_inserter(replaced_type_variables),
128+
[&](const java_generic_parametert &generic_param)
129+
-> java_generic_parametert {
130+
const typet &replacement_type =
131+
substitute_type(generic_param, generic_class, generic_reference);
132+
133+
// This code will be simplified when references aren't considered to
134+
// be generic parameters
135+
if(is_java_generic_parameter(replacement_type))
136+
{
137+
return to_java_generic_parameter(replacement_type);
138+
}
139+
else
140+
{
141+
INVARIANT(
142+
is_reference(replacement_type),
143+
"All generic parameters should be references");
144+
return java_generic_inst_parametert(
145+
to_symbol_type(replacement_type.subtype()));
146+
}
147+
});
148+
149+
java_generic_typet new_type = generic_type;
150+
new_type.generic_type_variables() = replaced_type_variables;
151+
return new_type;
152+
}
153+
else if(parameter_type.subtype().id() == ID_symbol)
154+
{
155+
const symbol_typet &array_subtype =
156+
to_symbol_type(parameter_type.subtype());
157+
if(is_java_array_tag(array_subtype.get_identifier()))
158+
{
159+
const typet &array_element_type =
160+
java_array_element_type(array_subtype);
161+
162+
const typet &new_array_type =
163+
substitute_type(array_element_type, generic_class, generic_reference);
164+
165+
typet replacement_array_type = java_array_type('a');
166+
replacement_array_type.subtype().set(ID_C_element_type, new_array_type);
167+
return replacement_array_type;
168+
}
169+
}
170+
}
171+
return parameter_type;
172+
}
173+
101174
/// Build a unique tag for the generic to be instantiated.
102175
/// \param existing_generic_type The type we want to concretise
103176
/// \param original_class

src/java_bytecode/generate_java_generic_type.h

Lines changed: 5 additions & 0 deletions
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_generic_class_typet &replacement_type,
34+
const java_generic_typet &generic_reference) const;
35+
3136
message_handlert &message_handler;
3237
};
3338

src/java_bytecode/java_bytecode_convert_class.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ void java_bytecode_convert_classt::convert(const classt &c)
9797
java_class_typet class_type;
9898
if(c.signature.has_value() && c.signature.value()[0]=='<')
9999
{
100-
java_generics_class_typet generic_class_type;
100+
java_generic_class_typet generic_class_type;
101101
#ifdef DEBUG
102102
std::cout << "INFO: found generic class signature "
103103
<< c.signature.value()

src/java_bytecode/java_types.h

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -254,12 +254,12 @@ inline java_generic_typet &to_java_generic_type(typet &type)
254254
/// vector of java_generic_type variables.
255255
///
256256
/// For example, a class definition `class MyGenericClass<T>`
257-
class java_generics_class_typet:public java_class_typet
257+
class java_generic_class_typet : public java_class_typet
258258
{
259259
public:
260260
typedef std::vector<java_generic_parametert> generic_typest;
261261

262-
java_generics_class_typet()
262+
java_generic_class_typet()
263263
{
264264
set(ID_C_java_generics_class_type, true);
265265
}
@@ -277,27 +277,27 @@ class java_generics_class_typet:public java_class_typet
277277

278278
/// \param type: the type to check
279279
/// \return true if type is a java class type with generics
280-
inline bool is_java_generics_class_type(const typet &type)
280+
inline bool is_java_generic_class_type(const typet &type)
281281
{
282282
return type.get_bool(ID_C_java_generics_class_type);
283283
}
284284

285285
/// \param type: the type to check
286286
/// \return cast of type to java_generics_class_typet
287-
inline const java_generics_class_typet &to_java_generics_class_type(
288-
const java_class_typet &type)
287+
inline const java_generic_class_typet &
288+
to_java_generic_class_type(const java_class_typet &type)
289289
{
290-
PRECONDITION(is_java_generics_class_type(type));
291-
return static_cast<const java_generics_class_typet &>(type);
290+
PRECONDITION(is_java_generic_class_type(type));
291+
return static_cast<const java_generic_class_typet &>(type);
292292
}
293293

294294
/// \param type: source type
295295
/// \return cast of type into a java class type with generics
296-
inline java_generics_class_typet &to_java_generics_class_type(
297-
java_class_typet &type)
296+
inline java_generic_class_typet &
297+
to_java_generic_class_type(java_class_typet &type)
298298
{
299-
PRECONDITION(is_java_generics_class_type(type));
300-
return static_cast<java_generics_class_typet &>(type);
299+
PRECONDITION(is_java_generic_class_type(type));
300+
return static_cast<java_generic_class_typet &>(type);
301301
}
302302

303303
/// Access information of instantiated type params of java instantiated type.
@@ -318,9 +318,8 @@ inline const typet &java_generic_get_inst_type(
318318
/// \param index: the index of the type variable
319319
/// \param type: the type from which to extract the type variable
320320
/// \return the name of the generic type variable of t at the given index
321-
inline const irep_idt &java_generics_class_type_var(
322-
size_t index,
323-
const java_generics_class_typet &type)
321+
inline const irep_idt &
322+
java_generic_class_type_var(size_t index, const java_generic_class_typet &type)
324323
{
325324
const std::vector<java_generic_parametert> &gen_types=type.generic_types();
326325

@@ -334,13 +333,11 @@ inline const irep_idt &java_generics_class_type_var(
334333
/// \param index: the index of the type variable
335334
/// \param t: the type from which to extract the type bound
336335
/// \return the type of the bound of the type variable
337-
inline const typet &java_generics_class_type_bound(
338-
size_t index,
339-
const typet &t)
336+
inline const typet &java_generic_class_type_bound(size_t index, const typet &t)
340337
{
341-
PRECONDITION(is_java_generics_class_type(t));
342-
const java_generics_class_typet &type=
343-
to_java_generics_class_type(to_java_class_type(t));
338+
PRECONDITION(is_java_generic_class_type(t));
339+
const java_generic_class_typet &type =
340+
to_java_generic_class_type(to_java_class_type(t));
344341
const std::vector<java_generic_parametert> &gen_types=type.generic_types();
345342

346343
PRECONDITION(index<gen_types.size());
@@ -381,7 +378,7 @@ inline typet java_type_from_string_with_exception(
381378
/// \param identifier The string identifier of the type of the component.
382379
/// \return Optional with the size if the identifier was found.
383380
inline const optionalt<size_t> java_generics_get_index_for_subtype(
384-
const java_generics_class_typet &t,
381+
const java_generic_class_typet &t,
385382
const irep_idt &identifier)
386383
{
387384
const std::vector<java_generic_parametert> &gen_types=

0 commit comments

Comments
 (0)