@@ -276,3 +276,252 @@ SCENARIO(
276
276
}
277
277
}
278
278
}
279
+ SCENARIO (
280
+ " lambda_method_handle_map with local lambdas" ,
281
+ " [core][java_bytecode][java_bytecode_parse_lambda_method_handle]" )
282
+ {
283
+ null_message_handlert message_handler;
284
+ GIVEN (" A method with local lambdas" )
285
+ {
286
+ java_bytecode_parse_treet parse_tree;
287
+ java_bytecode_parse (
288
+ " ./java_bytecode/java_bytecode_parser/lambda_examples/"
289
+ " LocalLambdas.class" ,
290
+ parse_tree,
291
+ message_handler);
292
+ WHEN (" Parsing that class" )
293
+ {
294
+ REQUIRE (parse_tree.loading_successful );
295
+ const java_bytecode_parse_treet::classt parsed_class =
296
+ parse_tree.parsed_class ;
297
+ REQUIRE (parsed_class.attribute_bootstrapmethods_read );
298
+ REQUIRE (parsed_class.lambda_method_handle_map .size () == 12 );
299
+
300
+ // Simple lambdas
301
+ THEN (
302
+ " There should be an entry for the lambda that has no parameters or "
303
+ " returns and the method it references should have an appropriate "
304
+ " descriptor" )
305
+ {
306
+ const lambda_method_handlet &lambda_entry =
307
+ require_parse_tree::require_lambda_entry_for_descriptor (
308
+ parsed_class, " ()V" );
309
+
310
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
311
+
312
+ const auto lambda_method =
313
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
314
+ REQUIRE (id2string (lambda_method.descriptor ) == " ()V" );
315
+ }
316
+
317
+ // Parameter lambdas
318
+ THEN (
319
+ " There should be an entry for the lambda that takes parameters and the "
320
+ " method it references should have an appropriate descriptor" )
321
+ {
322
+ std::string descriptor = " (ILjava/lang/Object;LDummyGeneric;)V" ;
323
+ const lambda_method_handlet &lambda_entry =
324
+ require_parse_tree::require_lambda_entry_for_descriptor (
325
+ parsed_class, descriptor);
326
+
327
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
328
+
329
+ const auto lambda_method =
330
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
331
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
332
+ }
333
+ THEN (
334
+ " There should be an entry for the lambda that takes array parameters "
335
+ " and the method it references should have an appropriate descriptor" )
336
+ {
337
+ std::string descriptor = " ([I[Ljava/lang/Object;[LDummyGeneric;)V" ;
338
+ const lambda_method_handlet &lambda_entry =
339
+ require_parse_tree::require_lambda_entry_for_descriptor (
340
+ parsed_class, descriptor);
341
+
342
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
343
+
344
+ const auto lambda_method =
345
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
346
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
347
+ }
348
+
349
+ // Return lambdas
350
+ THEN (
351
+ " There should be an entry for the lambda that returns a primitive and "
352
+ " the method it references should have an appropriate descriptor" )
353
+ {
354
+ std::string descriptor = " ()I" ;
355
+ const lambda_method_handlet &lambda_entry =
356
+ require_parse_tree::require_lambda_entry_for_descriptor (
357
+ parsed_class, descriptor);
358
+
359
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
360
+
361
+ const auto lambda_method =
362
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
363
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
364
+ }
365
+ THEN (
366
+ " There should be an entry for the lambda that returns a reference type "
367
+ " and the method it references should have an appropriate descriptor" )
368
+ {
369
+ std::string descriptor = " ()Ljava/lang/Object;" ;
370
+ const lambda_method_handlet &lambda_entry =
371
+ require_parse_tree::require_lambda_entry_for_descriptor (
372
+ parsed_class, descriptor);
373
+
374
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
375
+
376
+ const auto lambda_method =
377
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
378
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
379
+ }
380
+ THEN (
381
+ " There should be an entry for the lambda that returns a specialised "
382
+ " generic type and the method it references should have an appropriate "
383
+ " descriptor" )
384
+ {
385
+ std::string descriptor = " ()LDummyGeneric;" ;
386
+ const lambda_method_handlet &lambda_entry =
387
+ require_parse_tree::require_lambda_entry_for_descriptor (
388
+ parsed_class, descriptor);
389
+
390
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
391
+
392
+ const auto lambda_method =
393
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
394
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
395
+ }
396
+
397
+ // Array returning lambdas
398
+ THEN (
399
+ " There should be an entry for the lambda that returns an array of "
400
+ " primitives and the method it references should have an appropriate "
401
+ " descriptor" )
402
+ {
403
+ std::string descriptor = " ()[I" ;
404
+ const lambda_method_handlet &lambda_entry =
405
+ require_parse_tree::require_lambda_entry_for_descriptor (
406
+ parsed_class, descriptor);
407
+
408
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
409
+
410
+ const auto lambda_method =
411
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
412
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
413
+ }
414
+ THEN (
415
+ " There should be an entry for the lambda that returns an array of "
416
+ " reference types and the method it references should have an "
417
+ " appropriate descriptor" )
418
+ {
419
+ std::string descriptor = " ()[Ljava/lang/Object;" ;
420
+ const lambda_method_handlet &lambda_entry =
421
+ require_parse_tree::require_lambda_entry_for_descriptor (
422
+ parsed_class, descriptor);
423
+
424
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
425
+
426
+ const auto lambda_method =
427
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
428
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
429
+ }
430
+ THEN (
431
+ " There should be an entry for the lambda that returns an array of "
432
+ " specialised generic types and the method it references should have an "
433
+ " appropriate descriptor" )
434
+ {
435
+ std::string descriptor = " ()[LDummyGeneric;" ;
436
+ const lambda_method_handlet &lambda_entry =
437
+ require_parse_tree::require_lambda_entry_for_descriptor (
438
+ parsed_class, descriptor);
439
+
440
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
441
+
442
+ const auto lambda_method =
443
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
444
+ REQUIRE (id2string (lambda_method.descriptor ) == descriptor);
445
+ }
446
+
447
+ // Capturing lamdbas
448
+ THEN (
449
+ " There should be an entry for the lambda that returns a primitive "
450
+ " local variable and the method it references should have an "
451
+ " appropriate descriptor" )
452
+ {
453
+ std::string descriptor = " ()I" ;
454
+ const lambda_method_handlet &lambda_entry =
455
+ require_parse_tree::require_lambda_entry_for_descriptor (
456
+ parsed_class, descriptor, 1 );
457
+
458
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
459
+
460
+ const auto lambda_method =
461
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
462
+ // Note here the descriptor of the implementation is different - the
463
+ // implementation requries the input to be passed in
464
+ REQUIRE (id2string (lambda_method.descriptor ) == " (I)I" );
465
+
466
+ std::vector<require_parse_tree::expected_instructiont>
467
+ expected_instructions{{" iload_0" , {}}, {" ireturn" , {}}};
468
+
469
+ require_parse_tree::require_instructions_match_expectation (
470
+ expected_instructions, lambda_method.instructions );
471
+ }
472
+ THEN (
473
+ " There should be an entry for the lambda that returns a reference type "
474
+ " local variable and the method it references should have an "
475
+ " appropriate descriptor" )
476
+ {
477
+ // Since it is a local variable, the corresponding method takes the
478
+ // captured variable as an input
479
+ std::string descriptor = " ()Ljava/lang/Object;" ;
480
+ const lambda_method_handlet &lambda_entry =
481
+ require_parse_tree::require_lambda_entry_for_descriptor (
482
+ parsed_class, descriptor, 1 );
483
+
484
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
485
+
486
+ const auto lambda_method =
487
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
488
+ REQUIRE (
489
+ id2string (lambda_method.descriptor ) ==
490
+ " (Ljava/lang/Object;)Ljava/lang/Object;" );
491
+
492
+ std::vector<require_parse_tree::expected_instructiont>
493
+ expected_instructions{{" aload_0" , {}}, {" areturn" , {}}};
494
+
495
+ require_parse_tree::require_instructions_match_expectation (
496
+ expected_instructions, lambda_method.instructions );
497
+ }
498
+ THEN (
499
+ " There should be an entry for the lambda that returns a specialised "
500
+ " generic type local variable and the method it references should have "
501
+ " an appropriate descriptor" )
502
+ {
503
+ // Since it is a local variable, the corresponding method takes the
504
+ // captured variable as an input
505
+ std::string descriptor = " ()LDummyGeneric;" ;
506
+ const lambda_method_handlet &lambda_entry =
507
+ require_parse_tree::require_lambda_entry_for_descriptor (
508
+ parsed_class, descriptor, 1 );
509
+
510
+ const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name ;
511
+
512
+ const java_bytecode_parse_treet::methodt &lambda_method =
513
+ require_parse_tree::require_method (parsed_class, lambda_impl_name);
514
+ REQUIRE (
515
+ id2string (lambda_method.descriptor ) ==
516
+ " (LDummyGeneric;)LDummyGeneric;" );
517
+
518
+ // since just returning the parameter, nothing to put on the stack
519
+ std::vector<require_parse_tree::expected_instructiont>
520
+ expected_instructions{{" aload_0" , {}}, {" areturn" , {}}};
521
+
522
+ require_parse_tree::require_instructions_match_expectation (
523
+ expected_instructions, lambda_method.instructions );
524
+ }
525
+ }
526
+ }
527
+ }
0 commit comments