diff --git a/unit/Makefile b/unit/Makefile index c3872f7a98b..1157bb72db0 100644 --- a/unit/Makefile +++ b/unit/Makefile @@ -21,6 +21,7 @@ SRC += unit_tests.cpp \ goto-programs/class_hierarchy_graph.cpp \ goto-programs/remove_virtual_functions_without_fallback.cpp \ java_bytecode/java_bytecode_convert_class/convert_abstract_class.cpp \ + java_bytecode/java_bytecode_convert_method/convert_invoke_dynamic.cpp \ java_bytecode/java_bytecode_parse_generics/parse_generic_class.cpp \ java_bytecode/java_object_factory/gen_nondet_string_init.cpp \ java_bytecode/java_bytecode_parse_lambdas/java_bytecode_parse_lambda_method_table.cpp \ diff --git a/unit/java_bytecode/java_bytecode_convert_method/convert_invoke_dynamic.cpp b/unit/java_bytecode/java_bytecode_convert_method/convert_invoke_dynamic.cpp new file mode 100644 index 00000000000..4cda50514f9 --- /dev/null +++ b/unit/java_bytecode/java_bytecode_convert_method/convert_invoke_dynamic.cpp @@ -0,0 +1,93 @@ +/*******************************************************************\ + + Module: Unit tests for converting invokedynamic instructions into codet + + Author: Diffblue Ltd. + +\*******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +SCENARIO( + "Converting invokedynamic with a local lambda", + "[core]" + "[lamdba][java_bytecode][java_bytecode_convert_method][!mayfail]") +{ + // NOLINTNEXTLINE(whitespace/braces) + run_test_with_compilers([](const std::string &compiler) { + GIVEN( + "A class with a static lambda variables from " + compiler + " compiler.") + { + symbol_tablet symbol_table = load_java_class( + "LocalLambdas", + "./java_bytecode/java_bytecode_parser/lambda_examples/" + compiler + + "_classes/", + "LocalLambdas.test"); + + WHEN("Inspecting the assignments of the entry function") + { + const std::vector &instructions = + require_goto_statements::get_all_statements( + symbol_table.lookup_ref("java::LocalLambdas.test:()V").value); + + THEN("The local variable should be assigned a non-null pointer") + { + // TODO(tkiley): we don't want 11 here + // TODO(tkiley): This is the actual lambda which doesn't currently work + const auto lambda_assignment = + require_goto_statements::find_pointer_assignments( + "java::LocalLambdas.test:()V::11::simpleLambda", instructions); + + REQUIRE(lambda_assignment.non_null_assignments.size() == 1); + REQUIRE_FALSE(lambda_assignment.null_assignment.has_value()); + + const typecast_exprt &rhs_value = require_expr::require_typecast( + lambda_assignment.non_null_assignments[0].rhs()); + + const symbol_exprt &rhs_symbol = + require_expr::require_symbol(rhs_value.op0()); + + const irep_idt &tmp_object_symbol = rhs_symbol.get_identifier(); + + const auto tmp_object_assignments = + require_goto_statements::find_pointer_assignments( + tmp_object_symbol, instructions); + + REQUIRE(tmp_object_assignments.non_null_assignments.size() == 1); + REQUIRE_FALSE(tmp_object_assignments.null_assignment.has_value()); + + const side_effect_exprt &side_effect_expr = + require_expr::require_side_effect_expr( + tmp_object_assignments.non_null_assignments[0].rhs(), + ID_java_new); + + const pointer_typet &lambda_temp_type = + require_type::require_pointer(side_effect_expr.type(), {}); + + const symbol_typet &lambda_implementor_type = + require_type::require_symbol(lambda_temp_type.subtype()); + + const irep_idt &tmp_class_identifier = + lambda_implementor_type.get_identifier(); + + const symbolt &lambda_implementor_type_symbol = + require_symbol::require_symbol_exists( + symbol_table, tmp_class_identifier); + + REQUIRE(lambda_implementor_type_symbol.is_type); + const class_typet &tmp_lambda_class_type = + require_type::require_complete_class( + lambda_implementor_type_symbol.type); + + REQUIRE(tmp_lambda_class_type.has_base("java::SimpleLambda")); + } + } + } + }); +}