| // Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| package com.android.tools.r8.kotlin; |
| |
| import static org.junit.Assert.assertTrue; |
| |
| import com.android.tools.r8.ToolHelper.KotlinTargetVersion; |
| 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.BooleanUtils; |
| import com.android.tools.r8.utils.InternalOptions; |
| import com.android.tools.r8.utils.codeinspector.ClassSubject; |
| import com.android.tools.r8.utils.codeinspector.CodeInspector; |
| import com.android.tools.r8.utils.codeinspector.FieldSubject; |
| import java.util.Collection; |
| import java.util.function.Consumer; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| |
| @RunWith(Parameterized.class) |
| public class R8KotlinPropertiesTest extends AbstractR8KotlinTestBase { |
| |
| private static final String PACKAGE_NAME = "properties"; |
| |
| private static final String JAVA_LANG_STRING = "java.lang.String"; |
| |
| private static final TestKotlinClass MUTABLE_PROPERTY_CLASS = |
| new TestKotlinClass("properties.MutableProperty") |
| .addProperty("privateProp", JAVA_LANG_STRING, Visibility.PRIVATE) |
| .addProperty("protectedProp", JAVA_LANG_STRING, Visibility.PROTECTED) |
| .addProperty("internalProp", JAVA_LANG_STRING, Visibility.INTERNAL) |
| .addProperty("publicProp", JAVA_LANG_STRING, Visibility.PUBLIC) |
| .addProperty("primitiveProp", "int", Visibility.PUBLIC); |
| |
| private static final TestKotlinClass USER_DEFINED_PROPERTY_CLASS = |
| new TestKotlinClass("properties.UserDefinedProperty") |
| .addProperty("durationInMilliSeconds", "int", Visibility.PUBLIC) |
| .addProperty("durationInSeconds", "int", Visibility.PUBLIC); |
| |
| private static final TestKotlinClass LATE_INIT_PROPERTY_CLASS = |
| new TestKotlinClass("properties.LateInitProperty") |
| .addProperty("privateLateInitProp", JAVA_LANG_STRING, Visibility.PRIVATE) |
| .addProperty("protectedLateInitProp", JAVA_LANG_STRING, Visibility.PROTECTED) |
| .addProperty("internalLateInitProp", JAVA_LANG_STRING, Visibility.INTERNAL) |
| .addProperty("publicLateInitProp", JAVA_LANG_STRING, Visibility.PUBLIC); |
| |
| private static final TestKotlinCompanionClass COMPANION_PROPERTY_CLASS = |
| new TestKotlinCompanionClass("properties.CompanionProperties") |
| .addProperty("privateProp", JAVA_LANG_STRING, Visibility.PRIVATE) |
| .addProperty("protectedProp", JAVA_LANG_STRING, Visibility.PROTECTED) |
| .addProperty("internalProp", JAVA_LANG_STRING, Visibility.INTERNAL) |
| .addProperty("publicProp", JAVA_LANG_STRING, Visibility.PUBLIC) |
| .addProperty("primitiveProp", "int", Visibility.PUBLIC) |
| .addProperty("privateLateInitProp", JAVA_LANG_STRING, Visibility.PRIVATE) |
| .addProperty("internalLateInitProp", JAVA_LANG_STRING, Visibility.INTERNAL) |
| .addProperty("publicLateInitProp", JAVA_LANG_STRING, Visibility.PUBLIC); |
| |
| private static final TestKotlinCompanionClass COMPANION_LATE_INIT_PROPERTY_CLASS = |
| new TestKotlinCompanionClass("properties.CompanionLateInitProperties") |
| .addProperty("privateLateInitProp", JAVA_LANG_STRING, Visibility.PRIVATE) |
| .addProperty("internalLateInitProp", JAVA_LANG_STRING, Visibility.INTERNAL) |
| .addProperty("publicLateInitProp", JAVA_LANG_STRING, Visibility.PUBLIC); |
| |
| private static final TestKotlinClass OBJECT_PROPERTY_CLASS = |
| new TestKotlinClass("properties.ObjectProperties") |
| .addProperty("privateProp", JAVA_LANG_STRING, Visibility.PRIVATE) |
| .addProperty("protectedProp", JAVA_LANG_STRING, Visibility.PROTECTED) |
| .addProperty("internalProp", JAVA_LANG_STRING, Visibility.INTERNAL) |
| .addProperty("publicProp", JAVA_LANG_STRING, Visibility.PUBLIC) |
| .addProperty("primitiveProp", "int", Visibility.PUBLIC) |
| .addProperty("privateLateInitProp", JAVA_LANG_STRING, Visibility.PRIVATE) |
| .addProperty("internalLateInitProp", JAVA_LANG_STRING, Visibility.INTERNAL) |
| .addProperty("publicLateInitProp", JAVA_LANG_STRING, Visibility.PUBLIC); |
| |
| private static final TestFileLevelKotlinClass FILE_PROPERTY_CLASS = |
| new TestFileLevelKotlinClass("properties.FilePropertiesKt") |
| .addProperty("privateProp", JAVA_LANG_STRING, Visibility.PRIVATE) |
| .addProperty("protectedProp", JAVA_LANG_STRING, Visibility.PROTECTED) |
| .addProperty("internalProp", JAVA_LANG_STRING, Visibility.INTERNAL) |
| .addProperty("publicProp", JAVA_LANG_STRING, Visibility.PUBLIC) |
| .addProperty("primitiveProp", "int", Visibility.PUBLIC) |
| .addProperty("privateLateInitProp", JAVA_LANG_STRING, Visibility.PRIVATE) |
| .addProperty("internalLateInitProp", JAVA_LANG_STRING, Visibility.INTERNAL) |
| .addProperty("publicLateInitProp", JAVA_LANG_STRING, Visibility.PUBLIC); |
| |
| private Consumer<InternalOptions> disableAggressiveClassOptimizations = |
| o -> { |
| o.enableClassInlining = false; |
| o.enableVerticalClassMerging = false; |
| o.enableClassStaticizer = false; |
| }; |
| |
| @Parameterized.Parameters(name = "target: {0}, allowAccessModification: {1}") |
| public static Collection<Object[]> data() { |
| return buildParameters(KotlinTargetVersion.values(), BooleanUtils.values()); |
| } |
| |
| public R8KotlinPropertiesTest( |
| KotlinTargetVersion targetVersion, boolean allowAccessModification) { |
| super(targetVersion, allowAccessModification); |
| } |
| |
| @Test |
| public void testMutableProperty_classIsRemovedIfNotUsed() throws Exception { |
| String mainClass = addMainToClasspath("properties/MutablePropertyKt", |
| "mutableProperty_noUseOfProperties"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| checkClassIsRemoved(codeInspector, MUTABLE_PROPERTY_CLASS.getClassName()); |
| }); |
| } |
| |
| @Test |
| public void testMutableProperty_privateIsAlwaysInlined() throws Exception { |
| String mainClass = addMainToClasspath("properties/MutablePropertyKt", |
| "mutableProperty_usePrivateProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject classSubject = |
| checkClassIsKept(codeInspector, MUTABLE_PROPERTY_CLASS.getClassName()); |
| String propertyName = "privateProp"; |
| FieldSubject fieldSubject = |
| checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName); |
| if (!allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| } |
| |
| // Private property has no getter or setter. |
| checkMethodIsAbsent( |
| classSubject, MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName)); |
| checkMethodIsAbsent( |
| classSubject, MUTABLE_PROPERTY_CLASS.getSetterForProperty(propertyName)); |
| }); |
| } |
| |
| @Test |
| public void testMutableProperty_protectedIsAlwaysInlined() throws Exception { |
| String mainClass = addMainToClasspath("properties/MutablePropertyKt", |
| "mutableProperty_useProtectedProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject classSubject = |
| checkClassIsKept(codeInspector, 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); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(classSubject, getter); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(classSubject, getter); |
| } |
| }); |
| } |
| |
| @Test |
| public void testMutableProperty_internalIsAlwaysInlined() throws Exception { |
| String mainClass = addMainToClasspath("properties/MutablePropertyKt", |
| "mutableProperty_useInternalProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject classSubject = |
| checkClassIsKept(codeInspector, 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); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(classSubject, getter); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(classSubject, getter); |
| } |
| }); |
| } |
| |
| @Test |
| public void testMutableProperty_publicIsAlwaysInlined() throws Exception { |
| String mainClass = addMainToClasspath("properties/MutablePropertyKt", |
| "mutableProperty_usePublicProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject classSubject = |
| checkClassIsKept(codeInspector, 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); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(classSubject, getter); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(classSubject, getter); |
| } |
| }); |
| } |
| |
| @Test |
| public void testMutableProperty_primitivePropertyIsAlwaysInlined() throws Exception { |
| String mainClass = addMainToClasspath("properties/MutablePropertyKt", |
| "mutableProperty_usePrimitiveProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject classSubject = |
| checkClassIsKept(codeInspector, 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); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(classSubject, getter); |
| checkMethodIsRemoved(classSubject, setter); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(classSubject, getter); |
| checkMethodIsKept(classSubject, setter); |
| } |
| }); |
| } |
| |
| @Test |
| public void testLateInitProperty_classIsRemovedIfNotUsed() throws Exception { |
| String mainClass = |
| addMainToClasspath("properties/LateInitPropertyKt", "lateInitProperty_noUseOfProperties"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| checkClassIsRemoved(codeInspector, LATE_INIT_PROPERTY_CLASS.getClassName()); |
| }); |
| } |
| |
| @Test |
| public void testLateInitProperty_privateIsAlwaysInlined() throws Exception { |
| String mainClass = addMainToClasspath( |
| "properties/LateInitPropertyKt", "lateInitProperty_usePrivateLateInitProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject classSubject = |
| checkClassIsKept(codeInspector, LATE_INIT_PROPERTY_CLASS.getClassName()); |
| String propertyName = "privateLateInitProp"; |
| FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName); |
| assertTrue("Field is absent", fieldSubject.isPresent()); |
| if (!allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.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)); |
| }); |
| } |
| |
| @Test |
| public void testLateInitProperty_protectedIsAlwaysInlined() throws Exception { |
| String mainClass = addMainToClasspath("properties/LateInitPropertyKt", |
| "lateInitProperty_useProtectedLateInitProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject classSubject = |
| checkClassIsKept(codeInspector, LATE_INIT_PROPERTY_CLASS.getClassName()); |
| String propertyName = "protectedLateInitProp"; |
| FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName); |
| assertTrue("Field is absent", fieldSubject.isPresent()); |
| if (!allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isProtected()); |
| } |
| |
| // Protected late init property have protected getter |
| checkMethodIsRemoved( |
| classSubject, LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName)); |
| }); |
| } |
| |
| @Test |
| public void testLateInitProperty_internalIsAlwaysInlined() throws Exception { |
| String mainClass = addMainToClasspath( |
| "properties/LateInitPropertyKt", "lateInitProperty_useInternalLateInitProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject classSubject = |
| checkClassIsKept(codeInspector, LATE_INIT_PROPERTY_CLASS.getClassName()); |
| String propertyName = "internalLateInitProp"; |
| FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName); |
| assertTrue("Field is absent", fieldSubject.isPresent()); |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| |
| // Internal late init property have protected getter |
| checkMethodIsRemoved( |
| classSubject, LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName)); |
| }); |
| } |
| |
| @Test |
| public void testLateInitProperty_publicIsAlwaysInlined() throws Exception { |
| String mainClass = addMainToClasspath( |
| "properties/LateInitPropertyKt", "lateInitProperty_usePublicLateInitProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject classSubject = |
| checkClassIsKept(codeInspector, LATE_INIT_PROPERTY_CLASS.getClassName()); |
| String propertyName = "publicLateInitProp"; |
| FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName); |
| assertTrue("Field is absent", fieldSubject.isPresent()); |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| |
| // Internal late init property have protected getter |
| checkMethodIsRemoved( |
| classSubject, LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName)); |
| }); |
| } |
| |
| @Test |
| public void testUserDefinedProperty_classIsRemovedIfNotUsed() throws Exception { |
| String mainClass = addMainToClasspath( |
| "properties/UserDefinedPropertyKt", "userDefinedProperty_noUseOfProperties"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| checkClassIsRemoved(codeInspector, USER_DEFINED_PROPERTY_CLASS.getClassName()); |
| }); |
| } |
| |
| @Test |
| public void testUserDefinedProperty_publicIsAlwaysInlined() throws Exception { |
| String mainClass = addMainToClasspath( |
| "properties/UserDefinedPropertyKt", "userDefinedProperty_useProperties"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject classSubject = |
| checkClassIsKept(codeInspector, 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); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(classSubject, getter); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(classSubject, getter); |
| } |
| }); |
| } |
| |
| @Test |
| public void testCompanionProperty_primitivePropertyCannotBeInlined() throws Exception { |
| String mainClass = addMainToClasspath( |
| "properties.CompanionPropertiesKt", "companionProperties_usePrimitiveProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject outerClass = |
| checkClassIsKept(codeInspector, "properties.CompanionProperties"); |
| ClassSubject companionClass = |
| checkClassIsKept(codeInspector, COMPANION_PROPERTY_CLASS.getClassName()); |
| String propertyName = "primitiveProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, "int", propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| } |
| |
| MemberNaming.MethodSignature getter = |
| COMPANION_PROPERTY_CLASS.getGetterForProperty(propertyName); |
| checkMethodIsRemoved(companionClass, getter); |
| |
| MemberNaming.MethodSignature setter = |
| COMPANION_PROPERTY_CLASS.getSetterForProperty(propertyName); |
| checkMethodIsRemoved(companionClass, setter); |
| }); |
| } |
| |
| @Test |
| public void testCompanionProperty_privatePropertyIsAlwaysInlined() throws Exception { |
| String mainClass = addMainToClasspath( |
| "properties.CompanionPropertiesKt", "companionProperties_usePrivateProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject outerClass = |
| checkClassIsKept(codeInspector, "properties.CompanionProperties"); |
| ClassSubject companionClass = |
| checkClassIsKept(codeInspector, COMPANION_PROPERTY_CLASS.getClassName()); |
| String propertyName = "privateProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getter = |
| COMPANION_PROPERTY_CLASS.getGetterForProperty(propertyName); |
| MemberNaming.MethodSignature setter = |
| COMPANION_PROPERTY_CLASS.getSetterForProperty(propertyName); |
| |
| // 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. |
| checkMethodIsAbsent(companionClass, getter); |
| checkMethodIsAbsent(companionClass, setter); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testCompanionProperty_internalPropertyCannotBeInlined() throws Exception { |
| String mainClass = addMainToClasspath( |
| "properties.CompanionPropertiesKt", "companionProperties_useInternalProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject outerClass = |
| checkClassIsKept(codeInspector, "properties.CompanionProperties"); |
| ClassSubject companionClass = |
| checkClassIsKept(codeInspector, COMPANION_PROPERTY_CLASS.getClassName()); |
| String propertyName = "internalProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| } |
| |
| MemberNaming.MethodSignature getter = |
| COMPANION_PROPERTY_CLASS.getGetterForProperty(propertyName); |
| checkMethodIsRemoved(companionClass, getter); |
| MemberNaming.MethodSignature setter = |
| COMPANION_PROPERTY_CLASS.getSetterForProperty(propertyName); |
| checkMethodIsRemoved(companionClass, setter); |
| }); |
| } |
| |
| @Test |
| public void testCompanionProperty_publicPropertyCannotBeInlined() throws Exception { |
| String mainClass = addMainToClasspath( |
| "properties.CompanionPropertiesKt", "companionProperties_usePublicProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject outerClass = |
| checkClassIsKept(codeInspector, "properties.CompanionProperties"); |
| ClassSubject companionClass = |
| checkClassIsKept(codeInspector, COMPANION_PROPERTY_CLASS.getClassName()); |
| String propertyName = "publicProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| } |
| |
| MemberNaming.MethodSignature getter = |
| COMPANION_PROPERTY_CLASS.getGetterForProperty(propertyName); |
| checkMethodIsRemoved(companionClass, getter); |
| |
| MemberNaming.MethodSignature setter = |
| COMPANION_PROPERTY_CLASS.getSetterForProperty(propertyName); |
| checkMethodIsRemoved(companionClass, setter); |
| }); |
| } |
| |
| @Test |
| public void testCompanionProperty_privateLateInitPropertyIsAlwaysInlined() throws Exception { |
| final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt", |
| "companionLateInitProperties_usePrivateLateInitProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject outerClass = |
| checkClassIsKept(codeInspector, testedClass.getOuterClassName()); |
| ClassSubject companionClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "privateLateInitProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); |
| MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); |
| |
| // 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. |
| checkMethodIsAbsent(companionClass, getter); |
| checkMethodIsAbsent(companionClass, setter); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testCompanionProperty_internalLateInitPropertyCannotBeInlined() throws Exception { |
| final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt", |
| "companionLateInitProperties_useInternalLateInitProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject outerClass = |
| checkClassIsKept(codeInspector, testedClass.getOuterClassName()); |
| ClassSubject companionClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "internalLateInitProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| |
| MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); |
| checkMethodIsRemoved(companionClass, getter); |
| |
| MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); |
| checkMethodIsRemoved(companionClass, setter); |
| }); |
| } |
| |
| @Test |
| public void testCompanionProperty_publicLateInitPropertyCannotBeInlined() throws Exception { |
| final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt", |
| "companionLateInitProperties_usePublicLateInitProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject outerClass = |
| checkClassIsKept(codeInspector, testedClass.getOuterClassName()); |
| ClassSubject companionClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "publicLateInitProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| |
| MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); |
| checkMethodIsRemoved(companionClass, getter); |
| |
| MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); |
| checkMethodIsRemoved(companionClass, setter); |
| }); |
| } |
| |
| @Test |
| public void testObjectClass_primitivePropertyIsInlined() throws Exception { |
| final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath( |
| "properties.ObjectPropertiesKt", "objectProperties_usePrimitiveProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "primitiveProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(objectClass, "int", propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); |
| MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); |
| |
| if (allowAccessModification) { |
| // Getter and setter is inlined because the constructor of ObjectProperties is |
| // considered trivial, which implies that the member value propagation marks the |
| // INSTANCE field as being non-null. |
| checkMethodIsRemoved(objectClass, getter); |
| checkMethodIsRemoved(objectClass, setter); |
| } else { |
| checkMethodIsKept(objectClass, getter); |
| checkMethodIsKept(objectClass, setter); |
| } |
| |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testObjectClass_privatePropertyIsAlwaysInlined() throws Exception { |
| final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath( |
| "properties.ObjectPropertiesKt", "objectProperties_usePrivateProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "privateProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.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); |
| |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testObjectClass_internalPropertyIsInlined() throws Exception { |
| final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath( |
| "properties.ObjectPropertiesKt", "objectProperties_useInternalProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "internalProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); |
| MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); |
| |
| if (allowAccessModification) { |
| // Getter and setter is inlined because the constructor of ObjectProperties is |
| // considered trivial, which implies that the member value propagation marks the |
| // INSTANCE field as being non-null. |
| checkMethodIsRemoved(objectClass, getter); |
| checkMethodIsRemoved(objectClass, setter); |
| } else { |
| checkMethodIsKept(objectClass, getter); |
| checkMethodIsKept(objectClass, setter); |
| } |
| |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testObjectClass_publicPropertyIsInlined() throws Exception { |
| final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath( |
| "properties.ObjectPropertiesKt", "objectProperties_usePublicProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "publicProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); |
| MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); |
| |
| if (allowAccessModification) { |
| // Getter and setter is inlined because the constructor of ObjectProperties is |
| // considered trivial, which implies that the member value propagation marks the |
| // INSTANCE field as being non-null. |
| checkMethodIsRemoved(objectClass, getter); |
| checkMethodIsRemoved(objectClass, setter); |
| } else { |
| checkMethodIsKept(objectClass, getter); |
| checkMethodIsKept(objectClass, setter); |
| } |
| |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testObjectClass_privateLateInitPropertyIsAlwaysInlined() throws Exception { |
| final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath( |
| "properties.ObjectPropertiesKt", "objectProperties_useLateInitPrivateProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "privateLateInitProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.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); |
| |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testObjectClass_internalLateInitPropertyIsInlined() throws Exception { |
| final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath( |
| "properties.ObjectPropertiesKt", "objectProperties_useLateInitInternalProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "internalLateInitProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); |
| MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); |
| |
| checkMethodIsRemoved(objectClass, getter); |
| checkMethodIsRemoved(objectClass, setter); |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| }); |
| } |
| |
| @Test |
| public void testObjectClass_publicLateInitPropertyIsInlined() throws Exception { |
| final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath( |
| "properties.ObjectPropertiesKt", "objectProperties_useLateInitPublicProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "publicLateInitProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); |
| MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); |
| |
| checkMethodIsRemoved(objectClass, getter); |
| checkMethodIsRemoved(objectClass, setter); |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| }); |
| } |
| |
| @Test |
| public void testFileLevel_primitivePropertyIsInlinedIfAccessIsRelaxed() throws Exception { |
| final TestKotlinClass testedClass = FILE_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath( |
| "properties.FilePropertiesKt", "fileProperties_usePrimitiveProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "primitiveProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(objectClass, "int", propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); |
| MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); |
| |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(objectClass, getter); |
| checkMethodIsRemoved(objectClass, setter); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(objectClass, getter); |
| checkMethodIsKept(objectClass, setter); |
| } |
| }); |
| } |
| |
| @Test |
| public void testFileLevel_privatePropertyIsAlwaysInlined() throws Exception { |
| final TestKotlinClass testedClass = FILE_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath( |
| "properties.FilePropertiesKt", "fileProperties_usePrivateProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "privateProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.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); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testFileLevel_internalPropertyGetterIsInlinedIfAccessIsRelaxed() throws Exception { |
| final TestKotlinClass testedClass = FILE_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath( |
| "properties.FilePropertiesKt", "fileProperties_useInternalProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "internalProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.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); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(objectClass, getter); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(objectClass, getter); |
| } |
| }); |
| } |
| |
| @Test |
| public void testFileLevel_publicPropertyGetterIsInlinedIfAccessIsRelaxed() throws Exception { |
| final TestKotlinClass testedClass = FILE_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath( |
| "properties.FilePropertiesKt", "fileProperties_usePublicProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "publicProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.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); |
| |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(objectClass, getter); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(objectClass, getter); |
| } |
| }); |
| } |
| |
| @Test |
| public void testFileLevel_privateLateInitPropertyIsAlwaysInlined() throws Exception { |
| final TestKotlinClass testedClass = FILE_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath( |
| "properties.FilePropertiesKt", "fileProperties_useLateInitPrivateProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject fileClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "privateLateInitProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(fileClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.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); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testFileLevel_internalLateInitPropertyIsInlined() throws Exception { |
| final TestKotlinClass testedClass = FILE_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath( |
| "properties.FilePropertiesKt", "fileProperties_useLateInitInternalProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "internalLateInitProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| |
| MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); |
| MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); |
| |
| // Field is public and getter/setter is only called from one place so we expect to always |
| // inline it. |
| checkMethodIsRemoved(objectClass, getter); |
| checkMethodIsRemoved(objectClass, setter); |
| }); |
| } |
| |
| @Test |
| public void testFileLevel_publicLateInitPropertyIsInlined() throws Exception { |
| final TestKotlinClass testedClass = FILE_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath( |
| "properties.FilePropertiesKt", "fileProperties_useLateInitPublicProp"); |
| runTest( |
| PACKAGE_NAME, |
| mainClass, |
| disableAggressiveClassOptimizations, |
| app -> { |
| CodeInspector codeInspector = new CodeInspector(app); |
| ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName()); |
| String propertyName = "publicLateInitProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); |
| MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName); |
| |
| checkMethodIsRemoved(objectClass, getter); |
| checkMethodIsRemoved(objectClass, setter); |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| }); |
| } |
| |
| } |