@@ -525,3 +525,275 @@ SCENARIO(
525
525
}
526
526
}
527
527
}
528
+ SCENARIO (
529
+ " lambda_method_handle_map with member lambdas" ,
530
+ " [core][java_bytecode][java_bytecode_parse_lambda_method_handle]" )
531
+ {
532
+ null_message_handlert message_handler;
533
+ GIVEN (" A class that has lambdas as member variables" )
534
+ {
535
+ java_bytecode_parse_treet parse_tree;
536
+ java_bytecode_parse (
537
+ " ./java_bytecode/java_bytecode_parser/lambda_examples/"
538
+ " MemberLambdas.class" ,
539
+ parse_tree,
540
+ message_handler);
541
+ WHEN (" Parsing that class" )
542
+ {
543
+ REQUIRE (parse_tree.loading_successful );
544
+ const java_bytecode_parse_treet::classt parsed_class =
545
+ parse_tree.parsed_class ;
546
+ REQUIRE (parsed_class.attribute_bootstrapmethods_read );
547
+ REQUIRE (parsed_class.lambda_method_handle_map .size () == 12 );
548
+
549
+ // Simple lambdas
550
+ THEN (
551
+ " There should be an entry for the lambda that has no parameters or "
552
+ " returns and the method it references should have an appropriate "
553
+ " descriptor" )
554
+ {
555
+ const lambda_method_handlet &lambda_entry =
556
+ require_parse_tree::require_lambda_entry_for_descriptor (
557
+ parsed_class, " ()V" );
558
+
559
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
560
+
561
+ const auto lambda_method =
562
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
563
+ REQUIRE (id2string (lambda_method.descriptor ) == " ()V" );
564
+ }
565
+
566
+ // Parameter lambdas
567
+ THEN (
568
+ " There should be an entry for the lambda that takes parameters and the "
569
+ " method it references should have an appropriate descriptor" )
570
+ {
571
+ std::string descriptor = " (ILjava/lang/Object;LDummyGeneric;)V" ;
572
+ const lambda_method_handlet &lambda_entry =
573
+ require_parse_tree::require_lambda_entry_for_descriptor (
574
+ parsed_class, descriptor);
575
+
576
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
577
+
578
+ const auto lambda_method =
579
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
580
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
581
+ }
582
+ THEN (
583
+ " There should be an entry for the lambda that takes array parameters "
584
+ " and the method it references should have an appropriate descriptor" )
585
+ {
586
+ std::string descriptor = " ([I[Ljava/lang/Object;[LDummyGeneric;)V" ;
587
+ const lambda_method_handlet &lambda_entry =
588
+ require_parse_tree::require_lambda_entry_for_descriptor (
589
+ parsed_class, descriptor);
590
+
591
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
592
+
593
+ const auto lambda_method =
594
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
595
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
596
+ }
597
+
598
+ // Return lambdas
599
+ THEN (
600
+ " There should be an entry for the lambda that returns a primitive and "
601
+ " the method it references should have an appropriate descriptor" )
602
+ {
603
+ std::string descriptor = " ()I" ;
604
+ const lambda_method_handlet &lambda_entry =
605
+ require_parse_tree::require_lambda_entry_for_descriptor (
606
+ parsed_class, descriptor);
607
+
608
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
609
+
610
+ const auto lambda_method =
611
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
612
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
613
+ }
614
+ THEN (
615
+ " There should be an entry for the lambda that returns a reference type "
616
+ " and the method it references should have an appropriate descriptor" )
617
+ {
618
+ std::string descriptor = " ()Ljava/lang/Object;" ;
619
+ const lambda_method_handlet &lambda_entry =
620
+ require_parse_tree::require_lambda_entry_for_descriptor (
621
+ parsed_class, descriptor);
622
+
623
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
624
+
625
+ const auto lambda_method =
626
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
627
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
628
+ }
629
+ THEN (
630
+ " There should be an entry for the lambda that returns a specialised "
631
+ " generic type and the method it references should have an appropriate "
632
+ " descriptor" )
633
+ {
634
+ std::string descriptor = " ()LDummyGeneric;" ;
635
+ const lambda_method_handlet &lambda_entry =
636
+ require_parse_tree::require_lambda_entry_for_descriptor (
637
+ parsed_class, descriptor);
638
+
639
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
640
+
641
+ const auto lambda_method =
642
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
643
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
644
+ }
645
+
646
+ // Array returning lambdas
647
+ THEN (
648
+ " There should be an entry for the lambda that returns an array of "
649
+ " primitives and the method it references should have an appropriate "
650
+ " descriptor" )
651
+ {
652
+ std::string descriptor = " ()[I" ;
653
+ const lambda_method_handlet &lambda_entry =
654
+ require_parse_tree::require_lambda_entry_for_descriptor (
655
+ parsed_class, descriptor);
656
+
657
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
658
+
659
+ const auto lambda_method =
660
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
661
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
662
+ }
663
+ THEN (
664
+ " There should be an entry for the lambda that returns an array of "
665
+ " reference types and the method it references should have an "
666
+ " appropriate descriptor" )
667
+ {
668
+ std::string descriptor = " ()[Ljava/lang/Object;" ;
669
+ const lambda_method_handlet &lambda_entry =
670
+ require_parse_tree::require_lambda_entry_for_descriptor (
671
+ parsed_class, descriptor);
672
+
673
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
674
+
675
+ const auto lambda_method =
676
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
677
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
678
+ }
679
+ THEN (
680
+ " There should be an entry for the lambda that returns an array of "
681
+ " specialised generic types and the method it references should have an "
682
+ " appropriate descriptor" )
683
+ {
684
+ std::string descriptor = " ()[LDummyGeneric;" ;
685
+ const lambda_method_handlet &lambda_entry =
686
+ require_parse_tree::require_lambda_entry_for_descriptor (
687
+ parsed_class, descriptor);
688
+
689
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
690
+
691
+ const auto lambda_method =
692
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
693
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
694
+ }
695
+
696
+ // Capturing lamdbas
697
+ THEN (
698
+ " There should be an entry for the lambda that returns a primitive "
699
+ " local variable and the method it references should have an "
700
+ " appropriate descriptor" )
701
+ {
702
+ std::string descriptor = " ()I" ;
703
+ const lambda_method_handlet &lambda_entry =
704
+ require_parse_tree::require_lambda_entry_for_descriptor (
705
+ parsed_class, descriptor, 1 );
706
+
707
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
708
+
709
+ const auto lambda_method =
710
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
711
+ // Note here the descriptor of the implementation is different - the
712
+ // implementation requries the input to be passed in
713
+ REQUIRE (id2string (lambda_method.descriptor ) == " ()I" );
714
+ REQUIRE_FALSE (lambda_method.is_static );
715
+
716
+ const fieldref_exprt primitive_fieldref{
717
+ java_int_type (), " memberPrimitive" , " java::MemberLambdas" };
718
+
719
+ std::vector<require_parse_tree::expected_instructiont>
720
+ expected_instructions{{" aload_0" , {}}, // load this of stack
721
+ {" getfield" , {primitive_fieldref}},
722
+ {" ireturn" , {}}};
723
+
724
+ require_parse_tree::require_instructions_match_expectation (
725
+ expected_instructions, lambda_method.instructions );
726
+ }
727
+ THEN (
728
+ " There should be an entry for the lambda that returns a reference type "
729
+ " local variable and the method it references should have an "
730
+ " appropriate descriptor" )
731
+ {
732
+ // Since it is a local variable, the corresponding method takes the
733
+ // captured variable as an input
734
+ std::string descriptor = " ()Ljava/lang/Object;" ;
735
+ const lambda_method_handlet &lambda_entry =
736
+ require_parse_tree::require_lambda_entry_for_descriptor (
737
+ parsed_class, descriptor, 1 );
738
+
739
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
740
+
741
+ const auto lambda_method =
742
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
743
+ REQUIRE (id2string (lambda_method.descriptor ) == " ()Ljava/lang/Object;" );
744
+ REQUIRE_FALSE (lambda_method.is_static );
745
+
746
+ const reference_typet dummy_generic_reference_type =
747
+ java_reference_type (symbol_typet{" java::java.lang.Object" });
748
+
749
+ const fieldref_exprt reference_fieldref{dummy_generic_reference_type,
750
+ " memberReference" ,
751
+ " java::MemberLambdas" };
752
+
753
+ std::vector<require_parse_tree::expected_instructiont>
754
+ expected_instructions{{" aload_0" , {}}, // load this of stack
755
+ {" getfield" , {reference_fieldref}},
756
+ {" areturn" , {}}};
757
+
758
+ require_parse_tree::require_instructions_match_expectation (
759
+ expected_instructions, lambda_method.instructions );
760
+ }
761
+ THEN (
762
+ " There should be an entry for the lambda that returns a specialised "
763
+ " generic type local variable and the method it references should have "
764
+ " an appropriate descriptor" )
765
+ {
766
+ // Since it is a local variable, the corresponding method takes the
767
+ // captured variable as an input
768
+ std::string descriptor = " ()LDummyGeneric;" ;
769
+ const lambda_method_handlet &lambda_entry =
770
+ require_parse_tree::require_lambda_entry_for_descriptor (
771
+ parsed_class, descriptor, 1 );
772
+
773
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
774
+
775
+ const java_bytecode_parse_treet::methodt &lambda_method =
776
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
777
+ REQUIRE (id2string (lambda_method.descriptor ) == " ()LDummyGeneric;" );
778
+ REQUIRE_FALSE (lambda_method.is_static );
779
+
780
+ const reference_typet dummy_generic_reference_type =
781
+ java_reference_type (symbol_typet{" java::DummyGeneric" });
782
+
783
+ const fieldref_exprt generic_reference_fieldref{
784
+ dummy_generic_reference_type,
785
+ " memberSpecalisedGeneric" ,
786
+ " java::MemberLambdas" };
787
+
788
+ // since just returning the parameter, nothing to put on the stack
789
+ std::vector<require_parse_tree::expected_instructiont>
790
+ expected_instructions{{" aload_0" , {}}, // load this of stack
791
+ {" getfield" , {generic_reference_fieldref}},
792
+ {" areturn" , {}}};
793
+
794
+ require_parse_tree::require_instructions_match_expectation (
795
+ expected_instructions, lambda_method.instructions );
796
+ }
797
+ }
798
+ }
799
+ }
0 commit comments