diff --git a/src/java_bytecode/java_types.cpp b/src/java_bytecode/java_types.cpp index 5945624ad28..e9d99e44c85 100644 --- a/src/java_bytecode/java_types.cpp +++ b/src/java_bytecode/java_types.cpp @@ -252,7 +252,7 @@ std::string erase_type_arguments(const std::string &src) class_name.erase(f_pos, e_pos - f_pos + 1); // Search the remainder of the string for generic signature - f_pos = class_name.find('<', e_pos + 1); + f_pos = class_name.find('<', f_pos + 1); } return class_name; } diff --git a/unit/java_bytecode/java_bytecode_parse_generics/GenericClassWithGenericInnerClasses.class b/unit/java_bytecode/java_bytecode_parse_generics/GenericClassWithGenericInnerClasses.class index fe2480d4734..49969bba811 100644 Binary files a/unit/java_bytecode/java_bytecode_parse_generics/GenericClassWithGenericInnerClasses.class and b/unit/java_bytecode/java_bytecode_parse_generics/GenericClassWithGenericInnerClasses.class differ diff --git a/unit/java_bytecode/java_bytecode_parse_generics/GenericClassWithGenericInnerClasses.java b/unit/java_bytecode/java_bytecode_parse_generics/GenericClassWithGenericInnerClasses.java index 91d269a85dd..28587c09948 100644 --- a/unit/java_bytecode/java_bytecode_parse_generics/GenericClassWithGenericInnerClasses.java +++ b/unit/java_bytecode/java_bytecode_parse_generics/GenericClassWithGenericInnerClasses.java @@ -45,6 +45,8 @@ class TwoParamInnerClass TwoParamInnerClass field9; TwoParamInnerClass field10; + GenericInnerClass>.DoublyNestedInnerGenericClass field11; + void method(InnerClass input) { diff --git a/unit/java_bytecode/java_bytecode_parse_generics/parse_generic_class_with_generic_inner_classes.cpp b/unit/java_bytecode/java_bytecode_parse_generics/parse_generic_class_with_generic_inner_classes.cpp index 3d0b45dba8e..da1d0303e54 100644 --- a/unit/java_bytecode/java_bytecode_parse_generics/parse_generic_class_with_generic_inner_classes.cpp +++ b/unit/java_bytecode/java_bytecode_parse_generics/parse_generic_class_with_generic_inner_classes.cpp @@ -248,6 +248,47 @@ SCENARIO( {require_type::type_argument_kindt::Var, class_prefix + "::T"}}); } } + + THEN( + "The field11 component should be a pointer to " + "GenericClassWithGenericInnerClasses$" + "GenericInnerClass$DoublyNestedInnerGenericClass") + { + const struct_union_typet::componentt &field_component = + require_type::require_component(java_generic_class, "field11"); + + // Declaration of field11 to be tested - + // GenericInnerClass>. + // DoublyNestedInnerGenericClass field11; + + require_type::require_pointer( + field_component.type(), + symbol_typet( + class_prefix + "$GenericInnerClass$DoublyNestedInnerGenericClass")); + + THEN("The pointer should be GenericClassWithGenericInnerClasses") + { + const java_generic_typet &generic_field = + require_type::require_java_generic_type( + field_component.type(), + {{require_type::type_argument_kindt::Var, + "java::GenericClassWithGenericInnerClasses::T"}, + {require_type::type_argument_kindt::Inst, + "java::GenericClassWithGenericInnerClasses"}, + {require_type::type_argument_kindt::Var, + "java::GenericClassWithGenericInnerClasses::T"}}); + + THEN("Test nested Integer parameter.") + { + const typet &nested_generic_field = + generic_field.generic_type_arguments().at(1); + require_type::require_java_generic_type( + nested_generic_field, + {{require_type::type_argument_kindt::Inst, + "java::java.lang.Integer"}}); + } + } + } } } diff --git a/unit/java_bytecode/java_types/erase_type_arguments.cpp b/unit/java_bytecode/java_types/erase_type_arguments.cpp new file mode 100644 index 00000000000..4fd181eda3c --- /dev/null +++ b/unit/java_bytecode/java_types/erase_type_arguments.cpp @@ -0,0 +1,68 @@ +/*******************************************************************\ + + Module: Unit tests for java_types + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ + +#include +#include + +SCENARIO("erase_type_arguments", "[core][java_types]") +{ + THEN( + "erase_type_arguments should leave strings with no type arguments " + "unaltered.") + { + const std::string testInput1 = "testString1"; + REQUIRE(erase_type_arguments(testInput1) == testInput1); + } + + THEN("erase_type_arguments should remove a simple type argument") + { + REQUIRE( + erase_type_arguments("testClassName") == + "testClassName"); + } + + THEN( + "erase_type_arguments should remove multiple type arguments in cases " + "of nested classes") + { + REQUIRE( + erase_type_arguments( + "outerClass$" + "innerClass") == "outerClass$innerClass"); + } + + THEN( + "erase_type_arguments should remove type arguments which contain nested " + "type arguments") + { + REQUIRE( + erase_type_arguments( + "outerClass>") == "outerClass"); + } + + THEN( + "erase_type_arguments should remove multiple type arguments which contain " + "nested type arguments in cases of nested classes") + { + REQUIRE( + erase_type_arguments( + "outerClass>$" + "innerClass>") == + "outerClass$innerClass"); + } + + THEN( + "erase_type_arguments should throw an error if a type argument is " + "unterminated") + { + REQUIRE_THROWS_AS( + erase_type_arguments( + "testClassName"), + unsupported_java_class_signature_exceptiont &); + } +}