@@ -797,3 +797,139 @@ SCENARIO(
797
797
}
798
798
}
799
799
}
800
+ SCENARIO (
801
+ " lambda_method_handle_map with member lambdas capturing outer class "
802
+ " variables" ,
803
+ " [core][java_bytecode][java_bytecode_parse_lambda_method_handle]" )
804
+ {
805
+ null_message_handlert message_handler;
806
+ GIVEN (
807
+ " An inner class with member variables as lambdas that capture outer "
808
+ " variables" )
809
+ {
810
+ java_bytecode_parse_treet parse_tree;
811
+ java_bytecode_parse (
812
+ " ./java_bytecode/java_bytecode_parser/lambda_examples/"
813
+ " OuterMemberLambdas$Inner.class" ,
814
+ parse_tree,
815
+ message_handler);
816
+ WHEN (" Parsing that class" )
817
+ {
818
+ REQUIRE (parse_tree.loading_successful );
819
+ const java_bytecode_parse_treet::classt parsed_class =
820
+ parse_tree.parsed_class ;
821
+ REQUIRE (parsed_class.attribute_bootstrapmethods_read );
822
+ REQUIRE (parsed_class.lambda_method_handle_map .size () == 3 );
823
+
824
+ // Field ref for getting the outer class
825
+ const reference_typet outer_class_reference_type =
826
+ java_reference_type (symbol_typet{" java::OuterMemberLambdas" });
827
+ const fieldref_exprt outer_fieldref{
828
+ outer_class_reference_type, " this$0" , " java::OuterMemberLambdas$Inner" };
829
+
830
+ THEN (
831
+ " There should be an entry for the lambda that returns a primitive "
832
+ " local variable and the method it references should have an "
833
+ " appropriate descriptor" )
834
+ {
835
+ std::string descriptor = " ()I" ;
836
+ const lambda_method_handlet &lambda_entry =
837
+ require_parse_tree::require_lambda_entry_for_descriptor (
838
+ parsed_class, descriptor);
839
+
840
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
841
+
842
+ const auto lambda_method =
843
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
844
+ // Note here the descriptor of the implementation is different - the
845
+ // implementation requries the input to be passed in
846
+ REQUIRE (id2string (lambda_method.descriptor ) == " ()I" );
847
+ REQUIRE_FALSE (lambda_method.is_static );
848
+
849
+ const fieldref_exprt primitive_fieldref{
850
+ java_int_type (), " memberPrimitive" , " java::OuterMemberLambdas" };
851
+
852
+ std::vector<require_parse_tree::expected_instructiont>
853
+ expected_instructions{{" aload_0" , {}}, // load this of stack
854
+ {" getfield" , {outer_fieldref}},
855
+ {" getfield" , {primitive_fieldref}},
856
+ {" ireturn" , {}}};
857
+
858
+ require_parse_tree::require_instructions_match_expectation (
859
+ expected_instructions, lambda_method.instructions );
860
+ }
861
+ THEN (
862
+ " There should be an entry for the lambda that returns a reference type "
863
+ " local variable and the method it references should have an "
864
+ " appropriate descriptor" )
865
+ {
866
+ // Since it is a local variable, the corresponding method takes the
867
+ // captured variable as an input
868
+ std::string descriptor = " ()Ljava/lang/Object;" ;
869
+ const lambda_method_handlet &lambda_entry =
870
+ require_parse_tree::require_lambda_entry_for_descriptor (
871
+ parsed_class, descriptor);
872
+
873
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
874
+
875
+ const auto lambda_method =
876
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
877
+ REQUIRE (id2string (lambda_method.descriptor ) == " ()Ljava/lang/Object;" );
878
+ REQUIRE_FALSE (lambda_method.is_static );
879
+
880
+ const reference_typet dummy_generic_reference_type =
881
+ java_reference_type (symbol_typet{" java::java.lang.Object" });
882
+
883
+ const fieldref_exprt reference_fieldref{dummy_generic_reference_type,
884
+ " memberReference" ,
885
+ " java::OuterMemberLambdas" };
886
+
887
+ std::vector<require_parse_tree::expected_instructiont>
888
+ expected_instructions{{" aload_0" , {}}, // load this of stack
889
+ {" getfield" , {outer_fieldref}},
890
+ {" getfield" , {reference_fieldref}},
891
+ {" areturn" , {}}};
892
+
893
+ require_parse_tree::require_instructions_match_expectation (
894
+ expected_instructions, lambda_method.instructions );
895
+ }
896
+ THEN (
897
+ " There should be an entry for the lambda that returns a specialised "
898
+ " generic type local variable and the method it references should have "
899
+ " an appropriate descriptor" )
900
+ {
901
+ // Since it is a local variable, the corresponding method takes the
902
+ // captured variable as an input
903
+ std::string descriptor = " ()LDummyGeneric;" ;
904
+ const lambda_method_handlet &lambda_entry =
905
+ require_parse_tree::require_lambda_entry_for_descriptor (
906
+ parsed_class, descriptor);
907
+
908
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
909
+
910
+ const java_bytecode_parse_treet::methodt &lambda_method =
911
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
912
+ REQUIRE (id2string (lambda_method.descriptor ) == " ()LDummyGeneric;" );
913
+ REQUIRE_FALSE (lambda_method.is_static );
914
+
915
+ const reference_typet dummy_generic_reference_type =
916
+ java_reference_type (symbol_typet{" java::DummyGeneric" });
917
+
918
+ const fieldref_exprt generic_reference_fieldref{
919
+ dummy_generic_reference_type,
920
+ " memberSpecalisedGeneric" ,
921
+ " java::OuterMemberLambdas" };
922
+
923
+ // since just returning the parameter, nothing to put on the stack
924
+ std::vector<require_parse_tree::expected_instructiont>
925
+ expected_instructions{{" aload_0" , {}}, // load this of stack
926
+ {" getfield" , {outer_fieldref}},
927
+ {" getfield" , {generic_reference_fieldref}},
928
+ {" areturn" , {}}};
929
+
930
+ require_parse_tree::require_instructions_match_expectation (
931
+ expected_instructions, lambda_method.instructions );
932
+ }
933
+ }
934
+ }
935
+ }
0 commit comments