diff --git a/jbmc/src/java_bytecode/java_bytecode_convert_method.cpp b/jbmc/src/java_bytecode/java_bytecode_convert_method.cpp index 8e0a1ba9120..a95ed0f9159 100644 --- a/jbmc/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/jbmc/src/java_bytecode/java_bytecode_convert_method.cpp @@ -371,6 +371,9 @@ void java_bytecode_convert_method_lazy( if(m.is_static) member_type.set(ID_is_static, true); + if(m.is_bridge) + member_type.set(ID_is_bridge_method, m.is_bridge); + // do we need to add 'this' as a parameter? if(!m.is_static) { diff --git a/jbmc/src/java_bytecode/java_bytecode_parse_tree.h b/jbmc/src/java_bytecode/java_bytecode_parse_tree.h index 8d4157a2b10..641fba16bc3 100644 --- a/jbmc/src/java_bytecode/java_bytecode_parse_tree.h +++ b/jbmc/src/java_bytecode/java_bytecode_parse_tree.h @@ -86,7 +86,7 @@ struct java_bytecode_parse_treet struct methodt : public membert { irep_idt base_name; - bool is_native, is_abstract, is_synchronized; + bool is_native, is_abstract, is_synchronized, is_bridge; source_locationt source_location; typedef std::vector instructionst; @@ -164,10 +164,11 @@ struct java_bytecode_parse_treet void output(std::ostream &out) const; - methodt(): - is_native(false), - is_abstract(false), - is_synchronized(false) + methodt() + : is_native(false), + is_abstract(false), + is_synchronized(false), + is_bridge(false) { } }; diff --git a/jbmc/src/java_bytecode/java_bytecode_parser.cpp b/jbmc/src/java_bytecode/java_bytecode_parser.cpp index 3ad3ea158ea..71307324aed 100644 --- a/jbmc/src/java_bytecode/java_bytecode_parser.cpp +++ b/jbmc/src/java_bytecode/java_bytecode_parser.cpp @@ -1766,6 +1766,7 @@ void java_bytecode_parsert::rmethod(classt &parsed_class) method.is_private=(access_flags&ACC_PRIVATE)!=0; method.is_synchronized=(access_flags&ACC_SYNCHRONIZED)!=0; method.is_native=(access_flags&ACC_NATIVE)!=0; + method.is_bridge = (access_flags & ACC_BRIDGE) != 0; method.name=pool_entry(name_index).s; method.base_name=pool_entry(name_index).s; method.descriptor=id2string(pool_entry(descriptor_index).s); diff --git a/jbmc/unit/java_bytecode/java_bytecode_convert_method/ClassWithBridgeMethod.class b/jbmc/unit/java_bytecode/java_bytecode_convert_method/ClassWithBridgeMethod.class new file mode 100644 index 00000000000..e1e1fdc6375 Binary files /dev/null and b/jbmc/unit/java_bytecode/java_bytecode_convert_method/ClassWithBridgeMethod.class differ diff --git a/jbmc/unit/java_bytecode/java_bytecode_convert_method/ClassWithBridgeMethod.java b/jbmc/unit/java_bytecode/java_bytecode_convert_method/ClassWithBridgeMethod.java new file mode 100644 index 00000000000..f695e0ea87c --- /dev/null +++ b/jbmc/unit/java_bytecode/java_bytecode_convert_method/ClassWithBridgeMethod.java @@ -0,0 +1,5 @@ +public class ClassWithBridgeMethod implements Comparable { + public int compareTo(ClassWithBridgeMethod other) { + return 0; + } +} diff --git a/jbmc/unit/java_bytecode/java_bytecode_convert_method/convert_method.cpp b/jbmc/unit/java_bytecode/java_bytecode_convert_method/convert_method.cpp new file mode 100644 index 00000000000..a925d8469f8 --- /dev/null +++ b/jbmc/unit/java_bytecode/java_bytecode_convert_method/convert_method.cpp @@ -0,0 +1,55 @@ +/*******************************************************************\ + + Module: Unit tests for converting constructors and static initializers + + Author: Diffblue Limited. + +\*******************************************************************/ + +#include + +#include + +#include +#include + +SCENARIO( + "java_bytecode_convert_bridge_method", + "[core][java_bytecode][java_bytecode_convert_method]") +{ + GIVEN("A class with a bridge method") + { + const symbol_tablet symbol_table = load_java_class( + "ClassWithBridgeMethod", "./java_bytecode/java_bytecode_convert_method"); + + const std::string method_name = "java::ClassWithBridgeMethod.compareTo"; + + WHEN("When parsing the bridge method") + { + const symbolt function_symbol = + symbol_table.lookup_ref(method_name + ":(Ljava/lang/Object;)I"); + + const code_typet &function_type = + require_type::require_code(function_symbol.type); + THEN("The method should be marked as a bridge method") + { + REQUIRE(function_type.get_bool(ID_is_bridge_method)); + } + } + WHEN("When parsing a non-bridge method") + { + THEN("THe method should not be marked as a bridge method") + { + const symbolt function_symbol = + symbol_table.lookup_ref(method_name + ":(LClassWithBridgeMethod;)I"); + + const code_typet &function_type = + require_type::require_code(function_symbol.type); + THEN("The method should be marked as a bridge method") + { + REQUIRE_FALSE(function_type.get_bool(ID_is_bridge_method)); + } + } + } + } +} diff --git a/src/util/irep_ids.def b/src/util/irep_ids.def index bcc6a8f6906..43a74e9e8c2 100644 --- a/src/util/irep_ids.def +++ b/src/util/irep_ids.def @@ -676,6 +676,7 @@ IREP_ID_TWO(C_must_not_throw, #must_not_throw) IREP_ID_ONE(is_inner_class) IREP_ID_ONE(is_anonymous) IREP_ID_ONE(outer_class) +IREP_ID_ONE(is_bridge_method) // Projects depending on this code base that wish to extend the list of // available ids should provide a file local_irep_ids.h in their source tree and