diff --git a/src/java_bytecode/generate_java_generic_type.cpp b/src/java_bytecode/generate_java_generic_type.cpp index 7edcdf08bd1..00f45eb8ec9 100644 --- a/src/java_bytecode/generate_java_generic_type.cpp +++ b/src/java_bytecode/generate_java_generic_type.cpp @@ -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) { @@ -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) @@ -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 ¶m : 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 diff --git a/src/java_bytecode/java_bytecode_convert_class.cpp b/src/java_bytecode/java_bytecode_convert_class.cpp index b84978b2020..42d3992081d 100644 --- a/src/java_bytecode/java_bytecode_convert_class.cpp +++ b/src/java_bytecode/java_bytecode_convert_class.cpp @@ -236,7 +236,7 @@ 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 l;` or `List l;` else if(is_java_generic_type(field_type)) { @@ -244,19 +244,13 @@ void java_bytecode_convert_classt::convert( 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); diff --git a/src/java_bytecode/java_types.cpp b/src/java_bytecode/java_types.cpp index ad928710f5b..bbb24205439 100644 --- a/src/java_bytecode/java_types.cpp +++ b/src/java_bytecode/java_types.cpp @@ -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 (including wrapping angle -/// brackets). +/// \param type_arguments: The string representing the generic type arguments +/// for a signature. For example `;>` +/// (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 ¶meters, + 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 params = - parse_list_types(parameters, class_name_prefix, '<', '>'); + // Parse contained arguments, can be either type parameters (`TT;`) + // or instantiated types - either generic types (`LList;`) or + // just references (`Ljava/lang/Foo;`) + std::vector 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); }); } @@ -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 @@ -314,18 +307,18 @@ std::vector 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 ; @@ -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;" or "Ljava/util/List;" +/// 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;" or "Ljava/util/List;" /// /// \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, diff --git a/src/java_bytecode/java_types.h b/src/java_bytecode/java_types.h index cd4aa45813d..4925f03a4f8 100644 --- a/src/java_bytecode/java_types.h +++ b/src/java_bytecode/java_types.h @@ -85,8 +85,9 @@ exprt java_bytecode_promotion(const exprt &); bool is_java_array_tag(const irep_idt &tag); bool is_valid_java_array(const struct_typet &); -/// class to hold a Java generic type -/// upper bound can specify type requirements +/// Class to hold a Java generic type parameter (also called type variable), +/// e.g., `T` in `List`. +/// The bound can specify type requirements. class java_generic_parametert:public reference_typet { public: @@ -121,8 +122,10 @@ class java_generic_parametert:public reference_typet } }; -/// \param type: type the type to check -/// \return true if type is a generic Java parameter type, e.g., T in List +/// Checks whether the type is a java generic parameter/variable, e.g., `T` in +/// `List`. +/// \param type: the type to check +/// \return true if type is a generic Java parameter type inline bool is_java_generic_parameter(const typet &type) { return type.get_bool(ID_C_java_generic_parameter); @@ -145,61 +148,25 @@ inline java_generic_parametert &to_java_generic_parameter(typet &type) return static_cast(type); } -/// class to hold an instantiated type variable bound is exact, for example the -/// `java.lang.Integer` type in a `List` -class java_generic_inst_parametert:public java_generic_parametert -{ -public: - // uses empty name for base type variable java_generic_parametert as real name - // is not known here - explicit java_generic_inst_parametert(const symbol_typet &type): - java_generic_parametert(irep_idt(), type) - { - set(ID_C_java_generic_inst_parameter, true); - } -}; - -/// \param type: the type to check -/// \return true if type is an instantiated generic Java type, e.g., the Integer -/// in List -inline bool is_java_generic_inst_parameter(const typet &type) -{ - return type.get_bool(ID_C_java_generic_inst_parameter); -} - -/// \param type: source type -/// \return cast of type into an instantiated java_generic_parameter -inline const java_generic_inst_parametert &to_java_generic_inst_parameter( - const typet &type) -{ - PRECONDITION( - type.id()==ID_pointer && - is_java_generic_inst_parameter(type)); - return static_cast(type); -} - -/// \param type: source type -/// \return cast of type into an instantiated java_generic_inst_parametert -inline java_generic_inst_parametert &to_java_generic_inst_parameter(typet &type) -{ - PRECONDITION( - type.id()==ID_pointer && - is_java_generic_inst_parameter(type)); - return static_cast(type); -} - -/// class to hold type with generic type variable, for example `java.util.List` -/// in either a reference of type List or List. The vector holds -/// the types of the type Variables, that is the vector has the length of the -/// number of type variables of the generic class. For example in `HashMap` it would contain two elements, each of type `java_generic_parametert`, -/// in `HashMap` it would contains two elements, the first of type -/// `java_generic_inst_parametert` and the second of type -/// `java_generic_parametert`. +/// Class to hold type with generic type arguments, for example `java.util.List` +/// in either a reference of type List or List (here T must have +/// been concretized already to create this object so technically it is an +/// argument rather than parameter/variable, but in the symbol table this still +/// shows as the parameter T). The vector holds the types of the type arguments +/// (all of type or subtype of reference_typet), that is the vector has +/// the length of the number of type parameters of the generic class. +/// For example: +/// - in `HashMap` it would contain two elements, each of type +/// `java_generic_parametert`, +/// - in `HashMap` it would contain two elements, the first of type +/// `reference_typet` and the second of type `java_generic_parametert`, +/// - in `HashMap, V>` it would contain two elements, the first of +/// type `java_generic_typet` and the second of type +/// `java_generic_parametert`. class java_generic_typet:public reference_typet { public: - typedef std::vector generic_type_variablest; + typedef std::vector generic_type_argumentst; explicit java_generic_typet(const typet &_type): reference_typet(java_reference_type(_type)) @@ -208,16 +175,16 @@ class java_generic_typet:public reference_typet } /// \return vector of type variables - const generic_type_variablest &generic_type_variables() const + const generic_type_argumentst &generic_type_arguments() const { - return (const generic_type_variablest &)( + return (const generic_type_argumentst &)( find(ID_type_variables).get_sub()); } /// \return vector of type variables - generic_type_variablest &generic_type_variables() + generic_type_argumentst &generic_type_arguments() { - return (generic_type_variablest &)( + return (generic_type_argumentst &)( add(ID_type_variables).get_sub()); } }; @@ -251,10 +218,9 @@ inline java_generic_typet &to_java_generic_type(typet &type) } /// Class to hold a class with generics, extends the java class type with a -/// vector of java_generic_type variables. -/// -/// For example, a class definition `class MyGenericClass` -class java_generic_class_typet : public java_class_typet +/// vector of java generic type parameters (also called type variables). For +/// example, a class definition `class MyGenericClass`. +class java_generic_class_typet:public java_class_typet { public: typedef std::vector generic_typest; @@ -300,18 +266,18 @@ to_java_generic_class_type(java_class_typet &type) return static_cast(type); } -/// Access information of instantiated type params of java instantiated type. -/// \param index: the index of the type variable -/// \param type: the type from which to extract the type variable +/// Access information of type arguments of java instantiated type. +/// \param index: the index of the type argument +/// \param type: the type from which to extract the type argument /// \return the type variable of t at the given index inline const typet &java_generic_get_inst_type( size_t index, const java_generic_typet &type) { - const std::vector &gen_types= - type.generic_type_variables(); - PRECONDITION(index &type_arguments = + type.generic_type_arguments(); + PRECONDITION(index - expected_type_parameterst; +typedef std::initializer_list + expected_type_argumentst; java_generic_typet require_java_generic_type(const typet &type); java_generic_typet require_java_generic_type( const typet &type, - const require_type::expected_type_parameterst &type_expectations); + const require_type::expected_type_argumentst &type_expectations); java_generic_parametert require_java_generic_parameter(const typet &type); java_generic_parametert require_java_generic_parameter( const typet &type, - const require_type::expected_type_parametert &type_expectation); + const irep_idt ¶meter); const typet &require_java_non_generic_type( const typet &type, @@ -74,7 +74,7 @@ java_generic_class_typet require_java_generic_class(const typet &class_type); java_generic_class_typet require_java_generic_class( const typet &class_type, - const std::initializer_list &type_variables); + const std::initializer_list &type_parameters); java_class_typet require_java_non_generic_class(const typet &class_type); }