Skip to content

Commit af31813

Browse files
Merge pull request #1575 from svorenova/nested_generics_tg1301
[TG-1301] Parsing nested generics
2 parents 1aefb09 + 21b4e7e commit af31813

17 files changed

+936
-629
lines changed

src/java_bytecode/generate_java_generic_type.cpp

+29-29
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ typet generate_java_generic_typet::substitute_type(
116116
java_generics_get_index_for_subtype(generic_class, component_identifier);
117117

118118
INVARIANT(results.has_value(), "generic component type not found");
119-
return generic_reference.generic_type_variables()[*results];
119+
return generic_reference.generic_type_arguments()[*results];
120120
}
121121
else if(parameter_type.id() == ID_pointer)
122122
{
@@ -125,36 +125,35 @@ typet generate_java_generic_typet::substitute_type(
125125
const java_generic_typet &generic_type =
126126
to_java_generic_type(parameter_type);
127127

128-
java_generic_typet::generic_type_variablest replaced_type_variables;
128+
java_generic_typet::generic_type_argumentst replaced_type_variables;
129129

130130
// Swap each parameter
131131
std::transform(
132-
generic_type.generic_type_variables().begin(),
133-
generic_type.generic_type_variables().end(),
132+
generic_type.generic_type_arguments().begin(),
133+
generic_type.generic_type_arguments().end(),
134134
std::back_inserter(replaced_type_variables),
135-
[&](const java_generic_parametert &generic_param)
136-
-> java_generic_parametert {
137-
const typet &replacement_type =
138-
substitute_type(generic_param, generic_class, generic_reference);
139-
140-
// This code will be simplified when references aren't considered to
141-
// be generic parameters
142-
if(is_java_generic_parameter(replacement_type))
143-
{
144-
return to_java_generic_parameter(replacement_type);
145-
}
146-
else
147-
{
148-
INVARIANT(
149-
is_reference(replacement_type),
150-
"All generic parameters should be references");
151-
return java_generic_inst_parametert(
152-
to_symbol_type(replacement_type.subtype()));
153-
}
154-
});
135+
[&](const reference_typet &generic_param) -> reference_typet
136+
{
137+
const typet &replacement_type =
138+
substitute_type(generic_param, generic_class, generic_reference);
139+
140+
// This code will be simplified when references aren't considered to
141+
// be generic parameters
142+
if(is_java_generic_parameter(replacement_type))
143+
{
144+
return to_java_generic_parameter(replacement_type);
145+
}
146+
else
147+
{
148+
INVARIANT(
149+
is_reference(replacement_type),
150+
"All generic parameters should be references");
151+
return to_reference_type(replacement_type);
152+
}
153+
});
155154

156155
java_generic_typet new_type = generic_type;
157-
new_type.generic_type_variables() = replaced_type_variables;
156+
new_type.generic_type_arguments() = replaced_type_variables;
158157
return new_type;
159158
}
160159
else if(parameter_type.subtype().id() == ID_symbol)
@@ -190,21 +189,22 @@ irep_idt generate_java_generic_typet::build_generic_tag(
190189
new_tag_buffer << original_class.get_tag();
191190
new_tag_buffer << "<";
192191
bool first=true;
193-
for(const typet &param : existing_generic_type.generic_type_variables())
192+
for(const typet &type_argument : existing_generic_type
193+
.generic_type_arguments())
194194
{
195195
if(!first)
196196
new_tag_buffer << ",";
197197
first=false;
198198

199199
INVARIANT(
200-
is_java_generic_inst_parameter(param),
200+
!is_java_generic_parameter(type_argument),
201201
"Only create full concretized generic types");
202-
const irep_idt &id(id2string(param.subtype().get(ID_identifier)));
202+
const irep_idt &id(id2string(type_argument.subtype().get(ID_identifier)));
203203
new_tag_buffer << id2string(id);
204204
if(is_java_array_tag(id))
205205
{
206206
const typet &element_type =
207-
java_array_element_type(to_symbol_type(param.subtype()));
207+
java_array_element_type(to_symbol_type(type_argument.subtype()));
208208

209209
// If this is an array of references then we will specialize its
210210
// identifier using the type of the objects in the array. Else, there can

src/java_bytecode/java_bytecode_convert_class.cpp

+2-8
Original file line numberDiff line numberDiff line change
@@ -236,27 +236,21 @@ void java_bytecode_convert_classt::convert(
236236
#endif
237237
}
238238

239-
/// this is for a field that holds a generic type, wither with instantiated
239+
/// this is for a field that holds a generic type, either with instantiated
240240
/// or with free type variables, e.g., `List<T> l;` or `List<Integer> l;`
241241
else if(is_java_generic_type(field_type))
242242
{
243243
java_generic_typet &with_gen_type=
244244
to_java_generic_type(field_type);
245245
#ifdef DEBUG
246246
std::cout << "fieldtype: generic container type "
247-
<< std::to_string(with_gen_type.generic_type_variables().size())
247+
<< std::to_string(with_gen_type.generic_type_arguments().size())
248248
<< " type " << with_gen_type.id()
249249
<< " name " << f.name
250250
<< " subtype id " << with_gen_type.subtype().id() << "\n";
251251
#endif
252252
field_type=with_gen_type;
253253
}
254-
255-
/// This case is not possible, a field is either a non-instantiated type
256-
/// variable or a generics container type.
257-
INVARIANT(
258-
!is_java_generic_inst_parameter(field_type),
259-
"Cannot be an instantiated type variable here.");
260254
}
261255
else
262256
field_type=java_type_from_string(f.descriptor);

src/java_bytecode/java_types.cpp

+34-40
Original file line numberDiff line numberDiff line change
@@ -188,49 +188,42 @@ exprt java_bytecode_promotion(const exprt &expr)
188188
return typecast_exprt(expr, new_type);
189189
}
190190

191-
/// Take a list of generic arguments and parse them into the generic type.
191+
/// Take a list of generic type arguments and parse them into the generic type.
192192
/// \param generic_type [out]: The existing generic type to add the information
193193
/// to
194-
/// \param parameters: The string representing the generic arguments for a
195-
/// signature. For example <TT;Ljava/lang/Foo;> (including wrapping angle
196-
/// brackets).
194+
/// \param type_arguments: The string representing the generic type arguments
195+
/// for a signature. For example `<TT;Ljava/lang/Foo;LList<LInteger;>;>`
196+
/// (including the wrapping angle brackets).
197197
/// \param class_name_prefix: The name of the class to use to prefix any found
198198
/// generic types
199199
void add_generic_type_information(
200200
java_generic_typet &generic_type,
201-
const std::string &parameters,
201+
const std::string &type_arguments,
202202
const std::string &class_name_prefix)
203203
{
204-
PRECONDITION(parameters.size() >= 2);
205-
PRECONDITION(parameters[0] == '<');
206-
PRECONDITION(parameters[parameters.size() - 1] == '>');
204+
PRECONDITION(type_arguments.size() >= 2);
205+
PRECONDITION(type_arguments[0] == '<');
206+
PRECONDITION(type_arguments[type_arguments.size() - 1] == '>');
207207

208-
// parse contained types, can be either type variables, starting with T
209-
// or instantiated types
210-
std::vector<typet> params =
211-
parse_list_types(parameters, class_name_prefix, '<', '>');
208+
// Parse contained arguments, can be either type parameters (`TT;`)
209+
// or instantiated types - either generic types (`LList<LInteger;>;`) or
210+
// just references (`Ljava/lang/Foo;`)
211+
std::vector<typet> type_arguments_types =
212+
parse_list_types(type_arguments, class_name_prefix, '<', '>');
212213

213-
CHECK_RETURN(!params.empty()); // We should have at least one generic param
214-
215-
// take these types - they should either be java_generic_parameters, in which
216-
// case they can be directly added to the generic_type
217-
// otherwise they should be wrapped in a java_generic_inst_parametert
214+
// We should have at least one generic type argument
215+
CHECK_RETURN(!type_arguments_types.empty());
218216

217+
// Add the type arguments to the generic type
219218
std::transform(
220-
params.begin(),
221-
params.end(),
222-
std::back_inserter(generic_type.generic_type_variables()),
223-
[](const typet &type) -> java_generic_parametert {
224-
if(is_java_generic_parameter(type))
225-
{
226-
return to_java_generic_parameter(type);
227-
}
228-
else
229-
{
230-
INVARIANT(
231-
is_reference(type), "All generic parameters should be references");
232-
return java_generic_inst_parametert(to_symbol_type(type.subtype()));
233-
}
219+
type_arguments_types.begin(),
220+
type_arguments_types.end(),
221+
std::back_inserter(generic_type.generic_type_arguments()),
222+
[](const typet &type) -> reference_typet
223+
{
224+
INVARIANT(
225+
is_reference(type), "All generic type arguments should be references");
226+
return to_reference_type(type);
234227
});
235228
}
236229

@@ -286,8 +279,8 @@ std::string gather_full_class_name(const std::string &src)
286279

287280
/// Given a substring of a descriptor or signature that contains one or more
288281
/// types parse out the individual types. This is used for parsing the
289-
/// parameters of a function or the generic arguments contained within angle
290-
/// brackets.
282+
/// parameters of a function or the generic type variables/parameters or
283+
/// arguments contained within angle brackets.
291284
/// \param src: The input string that is wrapped in either ( ) or < >
292285
/// \param class_name_prefix: The name of the class to use to prefix any found
293286
/// generic types
@@ -314,18 +307,18 @@ std::vector<typet> parse_list_types(
314307
size_t start = i;
315308
while(i < src.size())
316309
{
317-
// parameter is an object type or instantiated generic type
310+
// type is an object type or instantiated generic type
318311
if(src[i] == 'L')
319312
{
320313
i = find_closing_semi_colon_for_reference_type(src, i);
321314
break;
322315
}
323316

324-
// parameter is an array
317+
// type is an array
325318
else if(src[i] == '[')
326319
i++;
327320

328-
// parameter is a type variable
321+
// type is a type variable/parameter
329322
else if(src[i] == 'T')
330323
i = src.find(';', i); // ends on ;
331324

@@ -425,12 +418,13 @@ size_t find_closing_semi_colon_for_reference_type(
425418
/// Transforms a string representation of a Java type into an internal type
426419
/// representation thereof.
427420
///
428-
/// Example use are object types like "Ljava/lang/Integer;", type variables like
429-
/// "TE;" which require a non-empty \p class_name or generic types like
430-
/// "Ljava/util/List<T>;" or "Ljava/util/List<Integer>;"
421+
/// Example use are object types like "Ljava/lang/Integer;", type
422+
/// variables/parameters like "TE;" which require a non-empty \p class_name
423+
/// or generic types like "Ljava/util/List<T>;" or "Ljava/util/List<Integer>;"
431424
///
432425
/// \param src: the string representation as used in the class file
433-
/// \param class_name_prefix: name of class to append to generic type variables
426+
/// \param class_name_prefix: name of class to append to generic type
427+
/// variables/parameters
434428
/// \returns internal type representation for GOTO programs
435429
typet java_type_from_string(
436430
const std::string &src,

0 commit comments

Comments
 (0)