diff --git a/unit/java_bytecode/ci_lazy_methods/lazy_load_lambdas.cpp b/unit/java_bytecode/ci_lazy_methods/lazy_load_lambdas.cpp new file mode 100644 index 00000000000..67d993a3304 --- /dev/null +++ b/unit/java_bytecode/ci_lazy_methods/lazy_load_lambdas.cpp @@ -0,0 +1,239 @@ +/*******************************************************************\ + + Module: Unit tests for parsing generic classes + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ + +#include +#include +#include + +SCENARIO( + "Lazy load lambda methods", + "[core][java_bytecode][ci_lazy_methods][lambdas][!mayfail]") +{ + GIVEN("A class with some locally declared lambdas") + { + const symbol_tablet symbol_table = load_java_class_lazy( + "LocalLambdas", + "./java_bytecode/java_bytecode_parser/lambda_examples/", + "LocalLambdas.test"); + + THEN("Then the lambdas should be loaded") + { + std::string lambda_name_prefix = "java::LocalLambdas.lambda$test$"; + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "0:()V"); + + require_symbol::require_symbol_exists( + symbol_table, + lambda_name_prefix + "1:(ILjava/lang/Object;LDummyGeneric;)V"); + + require_symbol::require_symbol_exists( + symbol_table, + lambda_name_prefix + "2:([I[Ljava/lang/Object;[LDummyGeneric;)V"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "3:()I"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "4:()Ljava/lang/Object;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "5:()LDummyGeneric;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "6:()[I"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "7:()[Ljava/lang/Object;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "8:()[LDummyGeneric;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "9:(I)I"); + + require_symbol::require_symbol_exists( + symbol_table, + lambda_name_prefix + "10:(Ljava/lang/Object;)Ljava/lang/Object;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "11:(LDummyGeneric;)LDummyGeneric;"); + } + } + GIVEN("A class with some member lambdas") + { + const symbol_tablet symbol_table = load_java_class_lazy( + "MemberLambdas", + "./java_bytecode/java_bytecode_parser/lambda_examples/", + "MemberLambdas.test"); + + THEN("Then the lambdas should be loaded") + { + std::string lambda_name_prefix = "java::MemberLambdas.lambda$new$"; + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "0:()V"); + + require_symbol::require_symbol_exists( + symbol_table, + lambda_name_prefix + "1:(ILjava/lang/Object;LDummyGeneric;)V"); + + require_symbol::require_symbol_exists( + symbol_table, + lambda_name_prefix + "2:([I[Ljava/lang/Object;[LDummyGeneric;)V"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "3:()I"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "4:()Ljava/lang/Object;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "5:()LDummyGeneric;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "6:()[I"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "7:()[Ljava/lang/Object;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "8:()[LDummyGeneric;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "9:()I"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "10:()Ljava/lang/Object;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "11:()LDummyGeneric;"); + } + } + GIVEN("A class with some static lambdas") + { + const symbol_tablet symbol_table = load_java_class_lazy( + "StaticLambdas", + "./java_bytecode/java_bytecode_parser/lambda_examples/", + "StaticLambdas.test"); + + THEN("Then the lambdas should be loaded") + { + std::string lambda_name_prefix = "java::StaticLambdas.lambda$static$"; + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "0:()V"); + + require_symbol::require_symbol_exists( + symbol_table, + lambda_name_prefix + "1:(ILjava/lang/Object;LDummyGeneric;)V"); + + require_symbol::require_symbol_exists( + symbol_table, + lambda_name_prefix + "2:([I[Ljava/lang/Object;[LDummyGeneric;)V"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "3:()I"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "4:()Ljava/lang/Object;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "5:()LDummyGeneric;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "6:()[I"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "7:()[Ljava/lang/Object;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "8:()[LDummyGeneric;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "9:()I"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "10:()Ljava/lang/Object;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "11:()LDummyGeneric;"); + } + } + GIVEN("A class with some outer member lambdas") + { + const symbol_tablet symbol_table = load_java_class_lazy( + "OuterMemberLambdas$Inner", + "./java_bytecode/java_bytecode_parser/lambda_examples/", + "OuterMemberLambdas$Inner.test"); + + THEN("Then the lambdas should be loaded") + { + std::string lambda_name_prefix = + "java::OuterMemberLambdas$Inner.lambda$new$"; + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "0:()I"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "1:()Ljava/lang/Object;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "2:()LDummyGeneric;"); + } + } +} + +SCENARIO( + "Lazy load lambda methods in seperate class", + "[core][java_bytecode][ci_lazy_methods][lambdas][!mayfail]") +{ + const symbol_tablet symbol_table = load_java_class_lazy( + "ExternalLambdaAccessor", + "./java_bytecode/java_bytecode_parser/lambda_examples/", + "ExternalLambdaAccessor.test"); + + THEN("Then the lambdas should be loaded") + { + std::string lambda_name_prefix = "java::ExternalLambdas.lambda$new$"; + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "0:()V"); + + require_symbol::require_symbol_exists( + symbol_table, + lambda_name_prefix + "1:(ILjava/lang/Object;LDummyGeneric;)V"); + + require_symbol::require_symbol_exists( + symbol_table, + lambda_name_prefix + "2:([I[Ljava/lang/Object;[LDummyGeneric;)V"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "3:()I"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "4:()Ljava/lang/Object;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "5:()LDummyGeneric;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "6:()[I"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "7:()[Ljava/lang/Object;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "8:()[LDummyGeneric;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "9:()I"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "10:()Ljava/lang/Object;"); + + require_symbol::require_symbol_exists( + symbol_table, lambda_name_prefix + "11:()LDummyGeneric;"); + } +} diff --git a/unit/java_bytecode/java_bytecode_parser/lambda_examples/ExternalLambdaAccessor.class b/unit/java_bytecode/java_bytecode_parser/lambda_examples/ExternalLambdaAccessor.class new file mode 100644 index 00000000000..7b4ae9aaa02 Binary files /dev/null and b/unit/java_bytecode/java_bytecode_parser/lambda_examples/ExternalLambdaAccessor.class differ diff --git a/unit/java_bytecode/java_bytecode_parser/lambda_examples/ExternalLambdaAccessor.java b/unit/java_bytecode/java_bytecode_parser/lambda_examples/ExternalLambdaAccessor.java new file mode 100644 index 00000000000..bdeaa7e4c48 --- /dev/null +++ b/unit/java_bytecode/java_bytecode_parser/lambda_examples/ExternalLambdaAccessor.java @@ -0,0 +1,39 @@ +class ExternalLambdas +{ + int memberPrimitive; + Object memberReference; + DummyGeneric memberSpecalisedGeneric; + + public SimpleLambda simpleLambda = () -> { /*NOP*/ }; + public ParameterLambda paramLambda = (int primitive, Object reference, DummyGeneric specalisedGeneric) -> {}; + public ArrayParameterLambda arrayParamLambda = (int[] primitive, Object[] reference, DummyGeneric[] specalisedGeneric) -> {}; + public ReturningLambdaPrimitive returnPrimitiveLambda = () -> { return 1; }; + public ReturningLambdaReference returnReferenceLambda = () -> { return null; }; + public ReturningLambdaSpecalisedGeneric returningSpecalisedGenericLambda = () -> { return null; }; + public ReturningLambdaPrimitiveArray returnPrimitiveArrayLambda = () -> { return null; }; + public ReturningLambdaReferenceArray returnReferenceArrayLambda = () -> { return null; }; + public ReturningLambdaSpecalisedGenericArray returningSpecalisedGenericArrayLambda = () -> { return null; }; + public ReturningLambdaPrimitive returnPrimitiveLambdaCapture = () -> { return memberPrimitive; }; + public ReturningLambdaReference returnReferenceLambdaCapture = () -> { return memberReference; }; + public ReturningLambdaSpecalisedGeneric returningSpecalisedGenericLambdaCapture = () -> { return memberSpecalisedGeneric; }; +} + +public class ExternalLambdaAccessor +{ + public static void test() + { + ExternalLambdas e = new ExternalLambdas(); + e.simpleLambda.Execute(); + e.paramLambda.Execute(4, null, null); + e.arrayParamLambda.Execute(null, null, null); + e.returnPrimitiveLambda.Execute(); + e.returnReferenceLambda.Execute(); + e.returningSpecalisedGenericLambda.Execute(); + e.returnPrimitiveArrayLambda.Execute(); + e.returnReferenceArrayLambda.Execute(); + e.returningSpecalisedGenericArrayLambda.Execute(); + e.returnPrimitiveLambdaCapture.Execute(); + e.returnReferenceLambdaCapture.Execute(); + e.returningSpecalisedGenericLambdaCapture.Execute(); + } +} diff --git a/unit/java_bytecode/java_bytecode_parser/lambda_examples/ExternalLambdas.class b/unit/java_bytecode/java_bytecode_parser/lambda_examples/ExternalLambdas.class new file mode 100644 index 00000000000..06e1b460efe Binary files /dev/null and b/unit/java_bytecode/java_bytecode_parser/lambda_examples/ExternalLambdas.class differ diff --git a/unit/testing-utils/require_symbol.cpp b/unit/testing-utils/require_symbol.cpp new file mode 100644 index 00000000000..fcac85b593f --- /dev/null +++ b/unit/testing-utils/require_symbol.cpp @@ -0,0 +1,23 @@ +/*******************************************************************\ + + Module: Unit test utilities + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ + +#include "require_symbol.h" +#include "catch.hpp" + +/// Verify whether a given identifier is found in the symbol table and return it +/// \param symbol_table: The symbol table to look in +/// \param symbol_identifier: The name of the symbol +const symbolt &require_symbol::require_symbol_exists( + const symbol_tablet &symbol_table, + const irep_idt &symbol_identifier) +{ + const symbolt *found_symbol = symbol_table.lookup(symbol_identifier); + INFO("Looking for symbol: " + id2string(symbol_identifier)); + REQUIRE(found_symbol != nullptr); + return *found_symbol; +} diff --git a/unit/testing-utils/require_symbol.h b/unit/testing-utils/require_symbol.h new file mode 100644 index 00000000000..4523636e17f --- /dev/null +++ b/unit/testing-utils/require_symbol.h @@ -0,0 +1,26 @@ +/*******************************************************************\ + + Module: Unit test utilities + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ + +#ifndef CPROVER_TESTING_UTILS_REQUIRE_SYMBOL_H +#define CPROVER_TESTING_UTILS_REQUIRE_SYMBOL_H + +#include +#include + +/// \file +/// Helper functions for getting symbols from the symbol table during unit tests + +// NOLINTNEXTLINE(readability/namespace) +namespace require_symbol +{ +const symbolt &require_symbol_exists( + const symbol_tablet &symbol_table, + const irep_idt &symbol_identifier); +} + +#endif // CPROVER_TESTING_UTILS_REQUIRE_SYMBOL_H