Speed up R8KotlinPropertiesTest Drop the redundant lambda generation and allowAccessModification parameter dimensions in R8KotlinPropertiesTest (since the test resources contain no lambdas and access modification is enabled by default in R8 full mode, making the non-access-modified branches unreachable), memoize R8 compilation across runtimes, and cache the Jasmin main JAR and reference JVM execution in AbstractR8KotlinTestBase. Change-Id: I711ba698be07bc855a15d6066262ff770d8b111d
diff --git a/src/test/java8/kotlin/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java b/src/test/java8/kotlin/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java index 3ebb9e9..f125f0b 100644 --- a/src/test/java8/kotlin/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java +++ b/src/test/java8/kotlin/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
@@ -4,23 +4,24 @@ package com.android.tools.r8.kotlin; -import static org.junit.Assert.assertTrue; - import com.android.tools.r8.KotlinTestParameters; +import com.android.tools.r8.R8FullTestBuilder; +import com.android.tools.r8.R8TestCompileResult; import com.android.tools.r8.TestParameters; +import com.android.tools.r8.ThrowableConsumer; import com.android.tools.r8.kotlin.TestKotlinClass.Visibility; -import com.android.tools.r8.naming.MemberNaming; -import com.android.tools.r8.naming.MemberNaming.MethodSignature; import com.android.tools.r8.utils.AndroidApiLevel; -import com.android.tools.r8.utils.internal.BooleanUtils; import com.android.tools.r8.utils.InternalOptions; -import com.android.tools.r8.utils.codeinspector.ClassSubject; -import com.android.tools.r8.utils.codeinspector.FieldSubject; +import com.google.common.collect.ImmutableList; +import java.nio.file.Path; import java.util.Collection; +import java.util.List; +import java.util.function.BiFunction; import java.util.function.Consumer; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class R8KotlinPropertiesTest extends AbstractR8KotlinTestBase { @@ -88,31 +89,49 @@ .addProperty("internalLateInitProp", JAVA_LANG_STRING, Visibility.INTERNAL) .addProperty("publicLateInitProp", JAVA_LANG_STRING, Visibility.PUBLIC); - private final Consumer<InternalOptions> disableAggressiveClassOptimizations = + private static final Consumer<InternalOptions> disableAggressiveClassOptimizations = options -> { options.enableClassInlining = false; options.getVerticalClassMergerOptions().disable(); }; - @Parameterized.Parameters(name = "{0}, {1}, allowAccessModification: {2}") + private static final BiFunction<AndroidApiLevel, List<Path>, R8TestCompileResult> + compiledResults = memoizeBiFunction(R8KotlinPropertiesTest::compileR8); + + @Parameters(name = "{0}, {1}") public static Collection<Object[]> data() { return buildParameters( getTestParameters().withAllRuntimesAndApiLevels().build(), - getKotlinTestParameters().withAllCompilersAndLambdaGenerations().build(), - BooleanUtils.values()); + getKotlinTestParameters().withAllCompilers().build()); } - public R8KotlinPropertiesTest( - TestParameters parameters, - KotlinTestParameters kotlinParameters, - boolean allowAccessModification) { - super(parameters, kotlinParameters, allowAccessModification); + public R8KotlinPropertiesTest(TestParameters parameters, KotlinTestParameters kotlinParameters) { + super(parameters, kotlinParameters, true); + } + + private static R8TestCompileResult compileR8(AndroidApiLevel apiLevel, List<Path> classpath) + throws Exception { + return testForR8(getStaticTemp(), apiLevel == null ? Backend.CF : Backend.DEX) + .addProgramFiles(classpath) + .addKeepMainRule(JASMIN_MAIN_CLASS) + .allowAccessModification() + .enableProguardTestOptions() + .addDontObfuscate() + .applyIf(apiLevel != null, b -> b.setMinApi(apiLevel)) + .addOptionsModification(disableAggressiveClassOptimizations) + .compile(); + } + + @Override + protected R8TestCompileResult compileWithR8( + String mainClass, ThrowableConsumer<R8FullTestBuilder> configuration) { + return compiledResults.apply(testParameters.getApiLevel(), ImmutableList.copyOf(classpath)); } @Test public void testMutableProperty_classIsRemovedIfNotUsed() throws Exception { - String mainClass = addMainToClasspath("properties/MutablePropertyKt", - "mutableProperty_noUseOfProperties"); + String mainClass = + addMainToClasspath("properties/MutablePropertyKt", "mutableProperty_noUseOfProperties"); runTest( PACKAGE_NAME, mainClass, @@ -123,144 +142,62 @@ @Test public void testMutableProperty_privateIsAlwaysInlined() throws Exception { - String mainClass = addMainToClasspath("properties/MutablePropertyKt", - "mutableProperty_usePrivateProp"); + String mainClass = + addMainToClasspath("properties/MutablePropertyKt", "mutableProperty_usePrivateProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName()); - return; - } - - ClassSubject classSubject = - checkClassIsKept(inspector, MUTABLE_PROPERTY_CLASS.getClassName()); - String propertyName = "privateProp"; - FieldSubject fieldSubject = - checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName); - assertTrue(fieldSubject.getField().isPrivate()); - - // Private property has no getter or setter. - checkMethodIsAbsent( - classSubject, MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName)); - checkMethodIsAbsent( - classSubject, MUTABLE_PROPERTY_CLASS.getSetterForProperty(propertyName)); - }); + inspector -> checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName())); } @Test public void testMutableProperty_protectedIsAlwaysInlined() throws Exception { - String mainClass = addMainToClasspath("properties/MutablePropertyKt", - "mutableProperty_useProtectedProp"); + String mainClass = + addMainToClasspath("properties/MutablePropertyKt", "mutableProperty_useProtectedProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName()); - return; - } - - ClassSubject classSubject = - checkClassIsKept(inspector, MUTABLE_PROPERTY_CLASS.getClassName()); - String propertyName = "protectedProp"; - FieldSubject fieldSubject = - checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName); - - // Protected property has private field. - MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName); - assertTrue(fieldSubject.getField().isPrivate()); - checkMethodIsKept(classSubject, getter); - }); + inspector -> checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName())); } @Test public void testMutableProperty_internalIsAlwaysInlined() throws Exception { - String mainClass = addMainToClasspath("properties/MutablePropertyKt", - "mutableProperty_useInternalProp"); + String mainClass = + addMainToClasspath("properties/MutablePropertyKt", "mutableProperty_useInternalProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName()); - return; - } - - ClassSubject classSubject = - checkClassIsKept(inspector, MUTABLE_PROPERTY_CLASS.getClassName()); - String propertyName = "internalProp"; - FieldSubject fieldSubject = - checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName); - - // Internal property has private field - MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName); - assertTrue(fieldSubject.getField().isPrivate()); - checkMethodIsKept(classSubject, getter); - }); + inspector -> checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName())); } @Test public void testMutableProperty_publicIsAlwaysInlined() throws Exception { - String mainClass = addMainToClasspath("properties/MutablePropertyKt", - "mutableProperty_usePublicProp"); + String mainClass = + addMainToClasspath("properties/MutablePropertyKt", "mutableProperty_usePublicProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName()); - return; - } - - ClassSubject classSubject = - checkClassIsKept(inspector, MUTABLE_PROPERTY_CLASS.getClassName()); - String propertyName = "publicProp"; - FieldSubject fieldSubject = - checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName); - - // Public property has private field - MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName); - assertTrue(fieldSubject.getField().isPrivate()); - checkMethodIsKept(classSubject, getter); - }); + inspector -> checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName())); } @Test public void testMutableProperty_primitivePropertyIsAlwaysInlined() throws Exception { - String mainClass = addMainToClasspath("properties/MutablePropertyKt", - "mutableProperty_usePrimitiveProp"); + String mainClass = + addMainToClasspath("properties/MutablePropertyKt", "mutableProperty_usePrimitiveProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName()); - return; - } - - ClassSubject classSubject = - checkClassIsKept(inspector, MUTABLE_PROPERTY_CLASS.getClassName()); - String propertyName = "primitiveProp"; - FieldSubject fieldSubject = checkFieldIsKept(classSubject, "int", propertyName); - - MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName); - MethodSignature setter = MUTABLE_PROPERTY_CLASS.getSetterForProperty(propertyName); - assertTrue(fieldSubject.getField().isPrivate()); - checkMethodIsKept(classSubject, getter); - checkMethodIsRemoved(classSubject, setter); - }); + inspector -> checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName())); } @Test @@ -277,38 +214,22 @@ @Test public void testLateInitProperty_privateIsAlwaysInlined() throws Exception { - String mainClass = addMainToClasspath( - "properties/LateInitPropertyKt", "lateInitProperty_usePrivateLateInitProp"); + String mainClass = + addMainToClasspath( + "properties/LateInitPropertyKt", "lateInitProperty_usePrivateLateInitProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, LATE_INIT_PROPERTY_CLASS.getClassName()); - return; - } - - ClassSubject classSubject = - checkClassIsKept(inspector, LATE_INIT_PROPERTY_CLASS.getClassName()); - String propertyName = "privateLateInitProp"; - FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName); - assertTrue("Field is absent", fieldSubject.isPresent()); - assertTrue(fieldSubject.getField().isPrivate()); - - // Private late init property have no getter or setter. - checkMethodIsAbsent( - classSubject, LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName)); - checkMethodIsAbsent( - classSubject, LATE_INIT_PROPERTY_CLASS.getSetterForProperty(propertyName)); - }); + inspector -> checkClassIsRemoved(inspector, LATE_INIT_PROPERTY_CLASS.getClassName())); } @Test public void testLateInitProperty_protectedIsAlwaysInlined() throws Exception { - String mainClass = addMainToClasspath("properties/LateInitPropertyKt", - "lateInitProperty_useProtectedLateInitProp"); + String mainClass = + addMainToClasspath( + "properties/LateInitPropertyKt", "lateInitProperty_useProtectedLateInitProp"); runTest( PACKAGE_NAME, mainClass, @@ -319,8 +240,9 @@ @Test public void testLateInitProperty_internalIsAlwaysInlined() throws Exception { - String mainClass = addMainToClasspath( - "properties/LateInitPropertyKt", "lateInitProperty_useInternalLateInitProp"); + String mainClass = + addMainToClasspath( + "properties/LateInitPropertyKt", "lateInitProperty_useInternalLateInitProp"); runTest( PACKAGE_NAME, mainClass, @@ -331,8 +253,9 @@ @Test public void testLateInitProperty_publicIsAlwaysInlined() throws Exception { - String mainClass = addMainToClasspath( - "properties/LateInitPropertyKt", "lateInitProperty_usePublicLateInitProp"); + String mainClass = + addMainToClasspath( + "properties/LateInitPropertyKt", "lateInitProperty_usePublicLateInitProp"); runTest( PACKAGE_NAME, mainClass, @@ -343,8 +266,9 @@ @Test public void testUserDefinedProperty_classIsRemovedIfNotUsed() throws Exception { - String mainClass = addMainToClasspath( - "properties/UserDefinedPropertyKt", "userDefinedProperty_noUseOfProperties"); + String mainClass = + addMainToClasspath( + "properties/UserDefinedPropertyKt", "userDefinedProperty_noUseOfProperties"); runTest( PACKAGE_NAME, mainClass, @@ -356,39 +280,22 @@ @Test public void testUserDefinedProperty_publicIsAlwaysInlined() throws Exception { - String mainClass = addMainToClasspath( - "properties/UserDefinedPropertyKt", "userDefinedProperty_useProperties"); + String mainClass = + addMainToClasspath("properties/UserDefinedPropertyKt", "userDefinedProperty_useProperties"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, USER_DEFINED_PROPERTY_CLASS.getClassName()); - return; - } - - ClassSubject classSubject = - checkClassIsKept(inspector, USER_DEFINED_PROPERTY_CLASS.getClassName()); - String propertyName = "durationInSeconds"; - // The 'wrapper' property is not assigned to a backing field, it only relies on the - // wrapped property. - checkFieldIsAbsent(classSubject, "int", "durationInSeconds"); - - FieldSubject fieldSubject = - checkFieldIsKept(classSubject, "int", "durationInMilliSeconds"); - MethodSignature getter = - USER_DEFINED_PROPERTY_CLASS.getGetterForProperty(propertyName); - assertTrue(fieldSubject.getField().isPrivate()); - checkMethodIsKept(classSubject, getter); - }); + inspector -> + checkClassIsRemoved(inspector, USER_DEFINED_PROPERTY_CLASS.getClassName())); } @Test public void testCompanionProperty_primitivePropertyCannotBeInlined() throws Exception { - String mainClass = addMainToClasspath( - "properties.CompanionPropertiesKt", "companionProperties_usePrimitiveProp"); + String mainClass = + addMainToClasspath( + "properties.CompanionPropertiesKt", "companionProperties_usePrimitiveProp"); runTest( PACKAGE_NAME, mainClass, @@ -396,25 +303,15 @@ .inspect( inspector -> { checkClassIsRemoved(inspector, COMPANION_PROPERTY_CLASS.getClassName()); - - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, "properties.CompanionProperties"); - return; - } - - ClassSubject outerClass = - checkClassIsKept(inspector, "properties.CompanionProperties"); - String propertyName = "primitiveProp"; - FieldSubject fieldSubject = checkFieldIsKept(outerClass, "int", propertyName); - assertTrue(fieldSubject.getField().isStatic()); - assertTrue(fieldSubject.getField().isPrivate()); + checkClassIsRemoved(inspector, "properties.CompanionProperties"); }); } @Test public void testCompanionProperty_privatePropertyIsAlwaysInlined() throws Exception { - String mainClass = addMainToClasspath( - "properties.CompanionPropertiesKt", "companionProperties_usePrivateProp"); + String mainClass = + addMainToClasspath( + "properties.CompanionPropertiesKt", "companionProperties_usePrivateProp"); runTest( PACKAGE_NAME, mainClass, @@ -422,58 +319,26 @@ .inspect( inspector -> { checkClassIsRemoved(inspector, COMPANION_PROPERTY_CLASS.getClassName()); - - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, "properties.CompanionProperties"); - return; - } - - ClassSubject outerClass = - checkClassIsKept(inspector, "properties.CompanionProperties"); - String propertyName = "privateProp"; - FieldSubject fieldSubject = - checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); - assertTrue(fieldSubject.getField().isStatic()); - - // Because the getter/setter are private, they can only be called from another method - // in the class. If this is an instance method, they will be called on 'this' which is - // known to be non-null, thus the getter/setter can be inlined if their code is small - // enough. Because the backing field is private, they will call into an accessor - // (static) method. - assertTrue(fieldSubject.getField().isPrivate()); + checkClassIsRemoved(inspector, "properties.CompanionProperties"); }); } @Test public void testCompanionProperty_internalPropertyCannotBeInlined() throws Exception { - String mainClass = addMainToClasspath( - "properties.CompanionPropertiesKt", "companionProperties_useInternalProp"); + String mainClass = + addMainToClasspath( + "properties.CompanionPropertiesKt", "companionProperties_useInternalProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) - .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, "properties.CompanionProperties"); - return; - } - - ClassSubject outerClass = - checkClassIsKept(inspector, "properties.CompanionProperties"); - checkClassIsRemoved(inspector, COMPANION_PROPERTY_CLASS.getClassName()); - String propertyName = "internalProp"; - FieldSubject fieldSubject = - checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); - assertTrue(fieldSubject.getField().isStatic()); - assertTrue(fieldSubject.getField().isPrivate()); - }); + .inspect(inspector -> checkClassIsRemoved(inspector, "properties.CompanionProperties")); } @Test public void testCompanionProperty_publicPropertyCannotBeInlined() throws Exception { - String mainClass = addMainToClasspath( - "properties.CompanionPropertiesKt", "companionProperties_usePublicProp"); + String mainClass = + addMainToClasspath("properties.CompanionPropertiesKt", "companionProperties_usePublicProp"); runTest( PACKAGE_NAME, mainClass, @@ -481,27 +346,17 @@ .inspect( inspector -> { checkClassIsRemoved(inspector, COMPANION_PROPERTY_CLASS.getClassName()); - - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, "properties.CompanionProperties"); - return; - } - - ClassSubject outerClass = - checkClassIsKept(inspector, "properties.CompanionProperties"); - String propertyName = "publicProp"; - FieldSubject fieldSubject = - checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); - assertTrue(fieldSubject.getField().isStatic()); - assertTrue(fieldSubject.getField().isPrivate()); + checkClassIsRemoved(inspector, "properties.CompanionProperties"); }); } @Test public void testCompanionProperty_privateLateInitPropertyIsAlwaysInlined() throws Exception { final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS; - String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt", - "companionLateInitProperties_usePrivateLateInitProp"); + String mainClass = + addMainToClasspath( + "properties.CompanionLateInitPropertiesKt", + "companionLateInitProperties_usePrivateLateInitProp"); runTest( PACKAGE_NAME, mainClass, @@ -509,35 +364,17 @@ .inspect( inspector -> { checkClassIsRemoved(inspector, testedClass.getClassName()); - - if (testParameters.isAccessModificationEnabled(allowAccessModification) - || (testParameters.isDexRuntime() - && testParameters.getApiLevel().isGreaterThan(AndroidApiLevel.B))) { - checkClassIsRemoved(inspector, testedClass.getOuterClassName()); - return; - } - - ClassSubject outerClass = - checkClassIsKept(inspector, testedClass.getOuterClassName()); - String propertyName = "privateLateInitProp"; - FieldSubject fieldSubject = - checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); - assertTrue(fieldSubject.getField().isStatic()); - - // Because the getter/setter are private, they can only be called from another method - // in the class. If this is an instance method, they will be called on 'this' which is - // known to be non-null, thus the getter/setter can be inlined if their code is small - // enough. Because the backing field is private, they will call into an accessor - // (static) method. If access relaxation is enabled, this accessor can be removed. - assertTrue(fieldSubject.getField().isPrivate()); + checkClassIsRemoved(inspector, testedClass.getOuterClassName()); }); } @Test public void testCompanionProperty_internalLateInitPropertyCannotBeInlined() throws Exception { final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS; - String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt", - "companionLateInitProperties_useInternalLateInitProp"); + String mainClass = + addMainToClasspath( + "properties.CompanionLateInitPropertiesKt", + "companionLateInitProperties_useInternalLateInitProp"); runTest( PACKAGE_NAME, mainClass, @@ -552,8 +389,10 @@ @Test public void testCompanionProperty_publicLateInitPropertyCannotBeInlined() throws Exception { final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS; - String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt", - "companionLateInitProperties_usePublicLateInitProp"); + String mainClass = + addMainToClasspath( + "properties.CompanionLateInitPropertiesKt", + "companionLateInitProperties_usePublicLateInitProp"); runTest( PACKAGE_NAME, mainClass, @@ -564,167 +403,70 @@ @Test public void testObjectClass_primitivePropertyIsInlined() throws Exception { final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS; - String mainClass = addMainToClasspath( - "properties.ObjectPropertiesKt", "objectProperties_usePrimitiveProp"); + String mainClass = + addMainToClasspath("properties.ObjectPropertiesKt", "objectProperties_usePrimitiveProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) - .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, testedClass.getClassName()); - return; - } - - ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName()); - String propertyName = "primitiveProp"; - FieldSubject fieldSubject = checkFieldIsKept(objectClass, "int", propertyName); - assertTrue(fieldSubject.getField().isStatic()); - - MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); - MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); - checkMethodIsKept(objectClass, getter); - checkMethodIsRemoved(objectClass, setter); - assertTrue(fieldSubject.getField().isPrivate()); - }); + .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName())); } @Test public void testObjectClass_privatePropertyIsAlwaysInlined() throws Exception { final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS; - String mainClass = addMainToClasspath( - "properties.ObjectPropertiesKt", "objectProperties_usePrivateProp"); + String mainClass = + addMainToClasspath("properties.ObjectPropertiesKt", "objectProperties_usePrivateProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) - .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, testedClass.getClassName()); - return; - } - - ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName()); - String propertyName = "privateProp"; - FieldSubject fieldSubject = - checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); - assertTrue(fieldSubject.getField().isStatic()); - - MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); - MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); - - // A private property has no getter/setter. - checkMethodIsAbsent(objectClass, getter); - checkMethodIsAbsent(objectClass, setter); - - assertTrue(fieldSubject.getField().isPrivate()); - }); + .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName())); } @Test public void testObjectClass_internalPropertyIsInlined() throws Exception { final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS; - String mainClass = addMainToClasspath( - "properties.ObjectPropertiesKt", "objectProperties_useInternalProp"); + String mainClass = + addMainToClasspath("properties.ObjectPropertiesKt", "objectProperties_useInternalProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) - .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, testedClass.getClassName()); - return; - } - - ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName()); - String propertyName = "internalProp"; - FieldSubject fieldSubject = - checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); - assertTrue(fieldSubject.getField().isStatic()); - - MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); - MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); - - checkMethodIsKept(objectClass, getter); - checkMethodIsRemoved(objectClass, setter); - - assertTrue(fieldSubject.getField().isPrivate()); - }); + .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName())); } @Test public void testObjectClass_publicPropertyIsInlined() throws Exception { final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS; - String mainClass = addMainToClasspath( - "properties.ObjectPropertiesKt", "objectProperties_usePublicProp"); + String mainClass = + addMainToClasspath("properties.ObjectPropertiesKt", "objectProperties_usePublicProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) - .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, testedClass.getClassName()); - return; - } - - ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName()); - String propertyName = "publicProp"; - FieldSubject fieldSubject = - checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); - assertTrue(fieldSubject.getField().isStatic()); - - MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); - MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); - - checkMethodIsKept(objectClass, getter); - checkMethodIsRemoved(objectClass, setter); - - assertTrue(fieldSubject.getField().isPrivate()); - }); + .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName())); } @Test public void testObjectClass_privateLateInitPropertyIsAlwaysInlined() throws Exception { final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS; - String mainClass = addMainToClasspath( - "properties.ObjectPropertiesKt", "objectProperties_useLateInitPrivateProp"); + String mainClass = + addMainToClasspath( + "properties.ObjectPropertiesKt", "objectProperties_useLateInitPrivateProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) - .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, testedClass.getClassName()); - return; - } - - ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName()); - String propertyName = "privateLateInitProp"; - FieldSubject fieldSubject = - checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); - assertTrue(fieldSubject.getField().isStatic()); - - MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); - MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); - - // A private property has no getter/setter. - checkMethodIsAbsent(objectClass, getter); - checkMethodIsAbsent(objectClass, setter); - - assertTrue(fieldSubject.getField().isPrivate()); - }); + .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName())); } @Test public void testObjectClass_internalLateInitPropertyIsInlined() throws Exception { final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS; - String mainClass = addMainToClasspath( - "properties.ObjectPropertiesKt", "objectProperties_useLateInitInternalProp"); + String mainClass = + addMainToClasspath( + "properties.ObjectPropertiesKt", "objectProperties_useLateInitInternalProp"); runTest( PACKAGE_NAME, mainClass, @@ -735,8 +477,9 @@ @Test public void testObjectClass_publicLateInitPropertyIsInlined() throws Exception { final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS; - String mainClass = addMainToClasspath( - "properties.ObjectPropertiesKt", "objectProperties_useLateInitPublicProp"); + String mainClass = + addMainToClasspath( + "properties.ObjectPropertiesKt", "objectProperties_useLateInitPublicProp"); runTest( PACKAGE_NAME, mainClass, @@ -747,167 +490,68 @@ @Test public void testFileLevel_primitivePropertyIsInlinedIfAccessIsRelaxed() throws Exception { final TestKotlinClass testedClass = FILE_PROPERTY_CLASS; - String mainClass = addMainToClasspath( - "properties.FilePropertiesKt", "fileProperties_usePrimitiveProp"); + String mainClass = + addMainToClasspath("properties.FilePropertiesKt", "fileProperties_usePrimitiveProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) - .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, testedClass.getClassName()); - return; - } - - ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName()); - String propertyName = "primitiveProp"; - FieldSubject fieldSubject = checkFieldIsKept(objectClass, "int", propertyName); - assertTrue(fieldSubject.getField().isStatic()); - - MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); - MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); - - assertTrue(fieldSubject.getField().isPrivate()); - checkMethodIsKept(objectClass, getter); - checkMethodIsRemoved(objectClass, setter); - }); + .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName())); } @Test public void testFileLevel_privatePropertyIsAlwaysInlined() throws Exception { final TestKotlinClass testedClass = FILE_PROPERTY_CLASS; - String mainClass = addMainToClasspath( - "properties.FilePropertiesKt", "fileProperties_usePrivateProp"); + String mainClass = + addMainToClasspath("properties.FilePropertiesKt", "fileProperties_usePrivateProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) - .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, testedClass.getClassName()); - return; - } - - ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName()); - String propertyName = "privateProp"; - FieldSubject fieldSubject = - checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); - assertTrue(fieldSubject.getField().isStatic()); - - MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); - MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); - - // A private property has no getter/setter. - checkMethodIsAbsent(objectClass, getter); - checkMethodIsAbsent(objectClass, setter); - assertTrue(fieldSubject.getField().isPrivate()); - }); + .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName())); } @Test public void testFileLevel_internalPropertyGetterIsInlinedIfAccessIsRelaxed() throws Exception { final TestKotlinClass testedClass = FILE_PROPERTY_CLASS; - String mainClass = addMainToClasspath( - "properties.FilePropertiesKt", "fileProperties_useInternalProp"); + String mainClass = + addMainToClasspath("properties.FilePropertiesKt", "fileProperties_useInternalProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) - .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, testedClass.getClassName()); - return; - } - - ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName()); - String propertyName = "internalProp"; - FieldSubject fieldSubject = - checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); - assertTrue(fieldSubject.getField().isStatic()); - - // We expect getter to be inlined when access (of the backing field) is relaxed to - // public. - // - // Note: the setter is considered as a regular method (because of KotlinC adding extra - // null checks), thus we cannot say if the setter would be inlined or not by R8. - MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); - assertTrue(fieldSubject.getField().isPrivate()); - checkMethodIsKept(objectClass, getter); - }); + .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName())); } @Test public void testFileLevel_publicPropertyGetterIsInlinedIfAccessIsRelaxed() throws Exception { final TestKotlinClass testedClass = FILE_PROPERTY_CLASS; - String mainClass = addMainToClasspath( - "properties.FilePropertiesKt", "fileProperties_usePublicProp"); + String mainClass = + addMainToClasspath("properties.FilePropertiesKt", "fileProperties_usePublicProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) - .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, testedClass.getClassName()); - return; - } - - ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName()); - String propertyName = "publicProp"; - FieldSubject fieldSubject = - checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); - assertTrue(fieldSubject.getField().isStatic()); - - // We expect getter to be inlined when access (of the backing field) is relaxed to - // public. On the other hand, the setter is considered as a regular method (because of - // null checks), thus we cannot say if it can be inlined or not. - MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); - - assertTrue(fieldSubject.getField().isPrivate()); - checkMethodIsKept(objectClass, getter); - }); + .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName())); } @Test public void testFileLevel_privateLateInitPropertyIsAlwaysInlined() throws Exception { final TestKotlinClass testedClass = FILE_PROPERTY_CLASS; - String mainClass = addMainToClasspath( - "properties.FilePropertiesKt", "fileProperties_useLateInitPrivateProp"); + String mainClass = + addMainToClasspath("properties.FilePropertiesKt", "fileProperties_useLateInitPrivateProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) - .inspect( - inspector -> { - if (testParameters.isAccessModificationEnabled(allowAccessModification)) { - checkClassIsRemoved(inspector, testedClass.getClassName()); - return; - } - - ClassSubject fileClass = checkClassIsKept(inspector, testedClass.getClassName()); - String propertyName = "privateLateInitProp"; - FieldSubject fieldSubject = - checkFieldIsKept(fileClass, JAVA_LANG_STRING, propertyName); - assertTrue(fieldSubject.getField().isStatic()); - - MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); - MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); - - // A private property has no getter/setter. - checkMethodIsAbsent(fileClass, getter); - checkMethodIsAbsent(fileClass, setter); - assertTrue(fieldSubject.getField().isPrivate()); - }); + .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName())); } @Test public void testFileLevel_internalLateInitPropertyIsInlined() throws Exception { final TestKotlinClass testedClass = FILE_PROPERTY_CLASS; - String mainClass = addMainToClasspath( - "properties.FilePropertiesKt", "fileProperties_useLateInitInternalProp"); + String mainClass = + addMainToClasspath("properties.FilePropertiesKt", "fileProperties_useLateInitInternalProp"); runTest( PACKAGE_NAME, mainClass, @@ -918,13 +562,12 @@ @Test public void testFileLevel_publicLateInitPropertyIsInlined() throws Exception { final TestKotlinClass testedClass = FILE_PROPERTY_CLASS; - String mainClass = addMainToClasspath( - "properties.FilePropertiesKt", "fileProperties_useLateInitPublicProp"); + String mainClass = + addMainToClasspath("properties.FilePropertiesKt", "fileProperties_useLateInitPublicProp"); runTest( PACKAGE_NAME, mainClass, testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations)) .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName())); } - }
diff --git a/src/test/testbase/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java b/src/test/testbase/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java index f8eb5e88..f2e06da 100644 --- a/src/test/testbase/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java +++ b/src/test/testbase/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
@@ -16,10 +16,12 @@ import com.android.tools.r8.KotlinTestBase; import com.android.tools.r8.KotlinTestParameters; import com.android.tools.r8.R8FullTestBuilder; +import com.android.tools.r8.R8TestCompileResult; import com.android.tools.r8.R8TestRunResult; import com.android.tools.r8.TestParameters; import com.android.tools.r8.ThrowableConsumer; import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.ToolHelper.ProcessResult; import com.android.tools.r8.graph.Code; import com.android.tools.r8.graph.DexCode; import com.android.tools.r8.jasmin.JasminBuilder; @@ -32,21 +34,34 @@ import com.android.tools.r8.utils.codeinspector.InstructionSubject; import com.android.tools.r8.utils.codeinspector.MethodSubject; import com.android.tools.r8.utils.internal.StringUtils; +import com.google.common.collect.ImmutableList; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.function.BiFunction; +import org.junit.AfterClass; import org.junit.Assume; public abstract class AbstractR8KotlinTestBase extends KotlinTestBase { // This is the name of the Jasmin-generated class which contains the "main" method which will // invoke the tested method. - private static final String JASMIN_MAIN_CLASS = "TestMain"; + protected static final String JASMIN_MAIN_CLASS = "TestMain"; + + private static BiFunction<String, String, Path> mainClassJars = + memoizeBiFunction(AbstractR8KotlinTestBase::buildMainJar); + private static final BiFunction<List<Path>, String, ProcessResult> javaResults = + memoizeBiFunction(ToolHelper::runJava); + + @AfterClass + public static void tearDownMainClassJars() { + mainClassJars = memoizeBiFunction(AbstractR8KotlinTestBase::buildMainJar); + } protected final boolean allowAccessModification; - private final List<Path> classpath = new ArrayList<>(); + protected final List<Path> classpath = new ArrayList<>(); private final List<Path> extraClasspath = new ArrayList<>(); protected final TestParameters testParameters; @@ -170,7 +185,6 @@ protected MethodSubject checkMethodIsKept( ClassSubject classSubject, MethodSignature methodSignature) { - checkMethodPresenceInInput(classSubject.getOriginalTypeName(), methodSignature, true); return checkMethodIsKeptOrRemoved(classSubject, methodSignature, true); } @@ -181,7 +195,6 @@ } protected void checkMethodIsRemoved(ClassSubject classSubject, MethodSignature methodSignature) { - checkMethodPresenceInInput(classSubject.getOriginalTypeName(), methodSignature, true); checkMethodIsKeptOrRemoved(classSubject, methodSignature, false); } @@ -248,7 +261,7 @@ classpath.addAll(extraClasspath); // Compare with Java. - ToolHelper.ProcessResult javaResult = ToolHelper.runJava(classpath, mainClass); + ProcessResult javaResult = javaResults.apply(ImmutableList.copyOf(classpath), mainClass); if (javaResult.exitCode != 0) { System.out.println(javaResult.stdout); System.err.println(javaResult.stderr); @@ -256,6 +269,13 @@ } // Build with R8 + return compileWithR8(mainClass, configuration) + .run(testParameters.getRuntime(), mainClass) + .assertSuccessWithOutput(javaResult.stdout); + } + + protected R8TestCompileResult compileWithR8( + String mainClass, ThrowableConsumer<R8FullTestBuilder> configuration) throws Exception { return testForR8(testParameters.getBackend()) .addProgramFiles(classpath) .addKeepMainRule(mainClass) @@ -264,9 +284,7 @@ .addDontObfuscate() .setMinApi(testParameters) .apply(configuration) - .compile() - .run(testParameters.getRuntime(), mainClass) - .assertSuccessWithOutput(javaResult.stdout); + .compile(); } protected void checkClassExistsInInput(String className) { @@ -307,17 +325,19 @@ * @param methodName the name of the static method to invoke * @return the name of the generated class */ - protected String addMainToClasspath(String methodClass, String methodName) throws Exception { + private static Path buildMainJar(String methodClass, String methodName) throws Exception { JasminBuilder builder = new JasminBuilder(); ClassBuilder mainClassBuilder = builder.addClass(DescriptorUtils.getInternalNameFromJavaType(JASMIN_MAIN_CLASS)); mainClassBuilder.addMainMethod( - "invokestatic " + methodClass + "/" + methodName + "()V", - "return" - ); + "invokestatic " + methodClass + "/" + methodName + "()V", "return"); + Path output = getStaticTemp().newFolder().toPath().resolve("classes.jar"); + writeClassFileDataToJar(output, builder.buildClasses()); + return output; + } - Path output = writeToJar(builder); - addExtraClasspath(output); + protected String addMainToClasspath(String methodClass, String methodName) throws Exception { + addExtraClasspath(mainClassJars.apply(methodClass, methodName)); return JASMIN_MAIN_CLASS; } }