Skip to content

[TG-1301] Parsing nested generics #1575

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 29 additions & 29 deletions src/java_bytecode/generate_java_generic_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ typet generate_java_generic_typet::substitute_type(
java_generics_get_index_for_subtype(generic_class, component_identifier);

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

java_generic_typet::generic_type_variablest replaced_type_variables;
java_generic_typet::generic_type_argumentst replaced_type_variables;

// Swap each parameter
std::transform(
generic_type.generic_type_variables().begin(),
generic_type.generic_type_variables().end(),
generic_type.generic_type_arguments().begin(),
generic_type.generic_type_arguments().end(),
std::back_inserter(replaced_type_variables),
[&](const java_generic_parametert &generic_param)
-> java_generic_parametert {
const typet &replacement_type =
substitute_type(generic_param, generic_class, generic_reference);

// This code will be simplified when references aren't considered to
// be generic parameters
if(is_java_generic_parameter(replacement_type))
{
return to_java_generic_parameter(replacement_type);
}
else
{
INVARIANT(
is_reference(replacement_type),
"All generic parameters should be references");
return java_generic_inst_parametert(
to_symbol_type(replacement_type.subtype()));
}
});
[&](const reference_typet &generic_param) -> reference_typet
{
const typet &replacement_type =
substitute_type(generic_param, generic_class, generic_reference);

// This code will be simplified when references aren't considered to
// be generic parameters
if(is_java_generic_parameter(replacement_type))
{
return to_java_generic_parameter(replacement_type);
}
else
{
INVARIANT(
is_reference(replacement_type),
"All generic parameters should be references");
return to_reference_type(replacement_type);
}
});

java_generic_typet new_type = generic_type;
new_type.generic_type_variables() = replaced_type_variables;
new_type.generic_type_arguments() = replaced_type_variables;
return new_type;
}
else if(parameter_type.subtype().id() == ID_symbol)
Expand Down Expand Up @@ -190,21 +189,22 @@ irep_idt generate_java_generic_typet::build_generic_tag(
new_tag_buffer << original_class.get_tag();
new_tag_buffer << "<";
bool first=true;
for(const typet &param : existing_generic_type.generic_type_variables())
for(const typet &type_argument : existing_generic_type
.generic_type_arguments())
{
if(!first)
new_tag_buffer << ",";
first=false;

INVARIANT(
is_java_generic_inst_parameter(param),
!is_java_generic_parameter(type_argument),
"Only create full concretized generic types");
const irep_idt &id(id2string(param.subtype().get(ID_identifier)));
const irep_idt &id(id2string(type_argument.subtype().get(ID_identifier)));
new_tag_buffer << id2string(id);
if(is_java_array_tag(id))
{
const typet &element_type =
java_array_element_type(to_symbol_type(param.subtype()));
java_array_element_type(to_symbol_type(type_argument.subtype()));

// If this is an array of references then we will specialize its
// identifier using the type of the objects in the array. Else, there can
Expand Down
10 changes: 2 additions & 8 deletions src/java_bytecode/java_bytecode_convert_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,27 +236,21 @@ void java_bytecode_convert_classt::convert(
#endif
}

/// this is for a field that holds a generic type, wither with instantiated
/// this is for a field that holds a generic type, either with instantiated
/// or with free type variables, e.g., `List<T> l;` or `List<Integer> l;`
else if(is_java_generic_type(field_type))
{
java_generic_typet &with_gen_type=
to_java_generic_type(field_type);
#ifdef DEBUG
std::cout << "fieldtype: generic container type "
<< std::to_string(with_gen_type.generic_type_variables().size())
<< std::to_string(with_gen_type.generic_type_arguments().size())
<< " type " << with_gen_type.id()
<< " name " << f.name
<< " subtype id " << with_gen_type.subtype().id() << "\n";
#endif
field_type=with_gen_type;
}

/// This case is not possible, a field is either a non-instantiated type
/// variable or a generics container type.
INVARIANT(
!is_java_generic_inst_parameter(field_type),
"Cannot be an instantiated type variable here.");
}
else
field_type=java_type_from_string(f.descriptor);
Expand Down
74 changes: 34 additions & 40 deletions src/java_bytecode/java_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,49 +188,42 @@ exprt java_bytecode_promotion(const exprt &expr)
return typecast_exprt(expr, new_type);
}

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

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

CHECK_RETURN(!params.empty()); // We should have at least one generic param

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

// Add the type arguments to the generic type
std::transform(
params.begin(),
params.end(),
std::back_inserter(generic_type.generic_type_variables()),
[](const typet &type) -> java_generic_parametert {
if(is_java_generic_parameter(type))
{
return to_java_generic_parameter(type);
}
else
{
INVARIANT(
is_reference(type), "All generic parameters should be references");
return java_generic_inst_parametert(to_symbol_type(type.subtype()));
}
type_arguments_types.begin(),
type_arguments_types.end(),
std::back_inserter(generic_type.generic_type_arguments()),
[](const typet &type) -> reference_typet
{
INVARIANT(
is_reference(type), "All generic type arguments should be references");
return to_reference_type(type);
});
}

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

/// Given a substring of a descriptor or signature that contains one or more
/// types parse out the individual types. This is used for parsing the
/// parameters of a function or the generic arguments contained within angle
/// brackets.
/// parameters of a function or the generic type variables/parameters or
/// arguments contained within angle brackets.
/// \param src: The input string that is wrapped in either ( ) or < >
/// \param class_name_prefix: The name of the class to use to prefix any found
/// generic types
Expand All @@ -314,18 +307,18 @@ std::vector<typet> parse_list_types(
size_t start = i;
while(i < src.size())
{
// parameter is an object type or instantiated generic type
// type is an object type or instantiated generic type
if(src[i] == 'L')
{
i = find_closing_semi_colon_for_reference_type(src, i);
break;
}

// parameter is an array
// type is an array
else if(src[i] == '[')
i++;

// parameter is a type variable
// type is a type variable/parameter
else if(src[i] == 'T')
i = src.find(';', i); // ends on ;

Expand Down Expand Up @@ -425,12 +418,13 @@ size_t find_closing_semi_colon_for_reference_type(
/// Transforms a string representation of a Java type into an internal type
/// representation thereof.
///
/// Example use are object types like "Ljava/lang/Integer;", type variables like
/// "TE;" which require a non-empty \p class_name or generic types like
/// "Ljava/util/List<T>;" or "Ljava/util/List<Integer>;"
/// Example use are object types like "Ljava/lang/Integer;", type
/// variables/parameters like "TE;" which require a non-empty \p class_name
/// or generic types like "Ljava/util/List<T>;" or "Ljava/util/List<Integer>;"
///
/// \param src: the string representation as used in the class file
/// \param class_name_prefix: name of class to append to generic type variables
/// \param class_name_prefix: name of class to append to generic type
/// variables/parameters
/// \returns internal type representation for GOTO programs
typet java_type_from_string(
const std::string &src,
Expand Down
Loading