| // 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.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| |
| import com.android.tools.r8.ToolHelper; |
| import com.android.tools.r8.ToolHelper.ProcessResult; |
| import com.android.tools.r8.jasmin.JasminBuilder; |
| import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder; |
| import com.android.tools.r8.kotlin.TestKotlinClass.AccessorKind; |
| import com.android.tools.r8.kotlin.TestKotlinClass.Visibility; |
| import com.android.tools.r8.naming.MemberNaming; |
| import com.android.tools.r8.utils.AndroidApp; |
| import com.android.tools.r8.utils.DexInspector; |
| import com.android.tools.r8.utils.DexInspector.ClassSubject; |
| import com.android.tools.r8.utils.DexInspector.FieldSubject; |
| import java.nio.file.Path; |
| import java.util.Collections; |
| import org.junit.Assert; |
| import org.junit.Ignore; |
| import org.junit.Test; |
| |
| public class R8KotlinAccessorTest extends AbstractR8KotlinTestBase { |
| |
| private static final String JAVA_LANG_STRING = "java.lang.String"; |
| |
| private static final TestKotlinCompanionClass ACCESSOR_COMPANION_PROPERTY_CLASS = |
| new TestKotlinCompanionClass("accessors.Accessor") |
| .addProperty("property", JAVA_LANG_STRING, Visibility.PRIVATE); |
| |
| private static final String PROPERTIES_PACKAGE_NAME = "properties"; |
| |
| 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); |
| |
| 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 PROPERTY_ACCESS_FOR_INNER_CLASS = |
| new TestKotlinClass("accessors.PropertyAccessorForInnerClass") |
| .addProperty("privateProp", JAVA_LANG_STRING, Visibility.PRIVATE) |
| .addProperty("privateLateInitProp", JAVA_LANG_STRING, Visibility.PRIVATE); |
| |
| private static final TestKotlinClass PROPERTY_ACCESS_FOR_LAMBDA_CLASS = |
| new TestKotlinClass("accessors.PropertyAccessorForLambda") |
| .addProperty("property", JAVA_LANG_STRING, Visibility.PRIVATE) |
| .addProperty("indirectPropertyGetter", JAVA_LANG_STRING, Visibility.PRIVATE); |
| |
| @Test |
| public void testCompanionProperty_primitivePropertyIsAlwaysInlined() throws Exception { |
| final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath("properties.CompanionPropertiesKt", |
| "companionProperties_usePrimitiveProp"); |
| runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> { |
| DexInspector dexInspector = new DexInspector(app); |
| ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName()); |
| String propertyName = "primitiveProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, "int", propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getterAccessor = testedClass |
| .getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| MemberNaming.MethodSignature setterAccessor = testedClass |
| .getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(outerClass, getterAccessor); |
| checkMethodIsRemoved(outerClass, setterAccessor); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(outerClass, getterAccessor); |
| checkMethodIsKept(outerClass, setterAccessor); |
| } |
| }); |
| } |
| |
| @Test |
| public void testCompanionProperty_privatePropertyIsAlwaysInlined() throws Exception { |
| final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath("properties.CompanionPropertiesKt", |
| "companionProperties_usePrivateProp"); |
| runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> { |
| DexInspector dexInspector = new DexInspector(app); |
| ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName()); |
| String propertyName = "privateProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getterAccessor = testedClass |
| .getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| MemberNaming.MethodSignature setterAccessor = testedClass |
| .getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| |
| checkMethodIsRemoved(outerClass, getterAccessor); |
| checkMethodIsRemoved(outerClass, setterAccessor); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| |
| checkMethodIsKept(outerClass, getterAccessor); |
| checkMethodIsKept(outerClass, setterAccessor); |
| } |
| }); |
| } |
| |
| @Test |
| public void testCompanionProperty_internalPropertyIsAlwaysInlined() throws Exception { |
| final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath("properties.CompanionPropertiesKt", |
| "companionProperties_useInternalProp"); |
| runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> { |
| DexInspector dexInspector = new DexInspector(app); |
| ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName()); |
| String propertyName = "internalProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getterAccessor = testedClass |
| .getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| MemberNaming.MethodSignature setterAccessor = testedClass |
| .getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(outerClass, getterAccessor); |
| checkMethodIsRemoved(outerClass, setterAccessor); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(outerClass, getterAccessor); |
| checkMethodIsKept(outerClass, setterAccessor); |
| } |
| }); |
| } |
| |
| @Test |
| public void testCompanionProperty_publicPropertyIsAlwaysInlined() throws Exception { |
| final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath("properties.CompanionPropertiesKt", |
| "companionProperties_usePublicProp"); |
| runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> { |
| DexInspector dexInspector = new DexInspector(app); |
| ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName()); |
| String propertyName = "publicProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getterAccessor = testedClass |
| .getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| MemberNaming.MethodSignature setterAccessor = testedClass |
| .getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(outerClass, getterAccessor); |
| checkMethodIsRemoved(outerClass, setterAccessor); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(outerClass, getterAccessor); |
| checkMethodIsKept(outerClass, setterAccessor); |
| } |
| }); |
| } |
| |
| @Test |
| public void testCompanionLateInitProperty_privatePropertyIsAlwaysInlined() throws Exception { |
| final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt", |
| "companionLateInitProperties_usePrivateLateInitProp"); |
| runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> { |
| DexInspector dexInspector = new DexInspector(app); |
| ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName()); |
| String propertyName = "privateLateInitProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getterAccessor = testedClass |
| .getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| MemberNaming.MethodSignature setterAccessor = testedClass |
| .getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(outerClass, getterAccessor); |
| checkMethodIsRemoved(outerClass, setterAccessor); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(outerClass, getterAccessor); |
| checkMethodIsKept(outerClass, setterAccessor); |
| } |
| }); |
| } |
| |
| @Test |
| public void testCompanionLateInitProperty_internalPropertyIsAlwaysInlined() throws Exception { |
| final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt", |
| "companionLateInitProperties_useInternalLateInitProp"); |
| runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> { |
| DexInspector dexInspector = new DexInspector(app); |
| ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName()); |
| String propertyName = "internalLateInitProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| |
| MemberNaming.MethodSignature getterAccessor = testedClass |
| .getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| MemberNaming.MethodSignature setterAccessor = testedClass |
| .getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsAbsent(outerClass, getterAccessor); |
| checkMethodIsAbsent(outerClass, setterAccessor); |
| }); |
| } |
| |
| @Test |
| public void testCompanionLateInitProperty_publicPropertyIsAlwaysInlined() throws Exception { |
| final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt", |
| "companionLateInitProperties_usePublicLateInitProp"); |
| runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> { |
| DexInspector dexInspector = new DexInspector(app); |
| ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName()); |
| String propertyName = "publicLateInitProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| |
| MemberNaming.MethodSignature getterAccessor = testedClass |
| .getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| MemberNaming.MethodSignature setterAccessor = testedClass |
| .getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsAbsent(outerClass, getterAccessor); |
| checkMethodIsAbsent(outerClass, setterAccessor); |
| }); |
| } |
| |
| @Test |
| public void testAccessor() throws Exception { |
| TestKotlinCompanionClass testedClass = ACCESSOR_COMPANION_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath("accessors.AccessorKt", |
| "accessor_accessPropertyFromCompanionClass"); |
| runTest("accessors", mainClass, (app) -> { |
| DexInspector dexInspector = new DexInspector(app); |
| ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName()); |
| ClassSubject companionClass = checkClassIsKept(dexInspector, testedClass.getClassName()); |
| String propertyName = "property"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| // The getter is always inlined since it just calls into the accessor. |
| MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); |
| checkMethodIsRemoved(companionClass, getter); |
| |
| MemberNaming.MethodSignature getterAccessor = |
| testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(outerClass, getterAccessor); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(outerClass, getterAccessor); |
| } |
| }); |
| } |
| |
| @Test |
| @Ignore("b/74103342") |
| public void testAccessorFromPrivate() throws Exception { |
| TestKotlinCompanionClass testedClass = ACCESSOR_COMPANION_PROPERTY_CLASS; |
| String mainClass = addMainToClasspath("accessors.AccessorKt", |
| "accessor_accessPropertyFromOuterClass"); |
| runTest("accessors", mainClass, (app) -> { |
| DexInspector dexInspector = new DexInspector(app); |
| ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName()); |
| ClassSubject companionClass = checkClassIsKept(dexInspector, testedClass.getClassName()); |
| String propertyName = "property"; |
| FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName); |
| assertTrue(fieldSubject.getField().accessFlags.isStatic()); |
| |
| // We cannot inline the getter because we don't know if NPE is preserved. |
| MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName); |
| checkMethodIsKept(companionClass, getter); |
| |
| // We should always inline the static accessor method. |
| MemberNaming.MethodSignature getterAccessor = |
| testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER); |
| checkMethodIsRemoved(companionClass, getterAccessor); |
| |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testAccessorForInnerClassIsRemovedWhenNotUsed() throws Exception { |
| TestKotlinClass testedClass = PROPERTY_ACCESS_FOR_INNER_CLASS; |
| String mainClass = addMainToClasspath(testedClass.className + "Kt", |
| "noUseOfPropertyAccessorFromInnerClass"); |
| runTest("accessors", mainClass, (app) -> { |
| DexInspector dexInspector = new DexInspector(app); |
| ClassSubject classSubject = checkClassIsKept(dexInspector, testedClass.getClassName()); |
| |
| for (String propertyName : testedClass.properties.keySet()) { |
| MemberNaming.MethodSignature getterAccessor = |
| testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER); |
| MemberNaming.MethodSignature setterAccessor = |
| testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER); |
| |
| checkMethodIsRemoved(classSubject, getterAccessor); |
| checkMethodIsRemoved(classSubject, setterAccessor); |
| } |
| }); |
| } |
| |
| @Test |
| @Ignore("b/74103342") |
| public void testPrivatePropertyAccessorForInnerClassCanBeInlined() throws Exception { |
| TestKotlinClass testedClass = PROPERTY_ACCESS_FOR_INNER_CLASS; |
| String mainClass = addMainToClasspath(testedClass.className + "Kt", |
| "usePrivatePropertyAccessorFromInnerClass"); |
| runTest("accessors", mainClass, (app) -> { |
| DexInspector dexInspector = new DexInspector(app); |
| ClassSubject classSubject = checkClassIsKept(dexInspector, testedClass.getClassName()); |
| |
| String propertyName = "privateProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(classSubject, JAVA_LANG_STRING, |
| propertyName); |
| assertFalse(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getterAccessor = |
| testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER); |
| MemberNaming.MethodSignature setterAccessor = |
| testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(classSubject, getterAccessor); |
| checkMethodIsRemoved(classSubject, setterAccessor); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(classSubject, getterAccessor); |
| checkMethodIsKept(classSubject, setterAccessor); |
| } |
| }); |
| } |
| |
| @Test |
| @Ignore("b/74103342") |
| public void testPrivateLateInitPropertyAccessorForInnerClassCanBeInlined() throws Exception { |
| TestKotlinClass testedClass = PROPERTY_ACCESS_FOR_INNER_CLASS; |
| String mainClass = addMainToClasspath(testedClass.className + "Kt", |
| "usePrivateLateInitPropertyAccessorFromInnerClass"); |
| runTest("accessors", mainClass, (app) -> { |
| DexInspector dexInspector = new DexInspector(app); |
| ClassSubject classSubject = checkClassIsKept(dexInspector, testedClass.getClassName()); |
| |
| String propertyName = "privateLateInitProp"; |
| FieldSubject fieldSubject = checkFieldIsKept(classSubject, JAVA_LANG_STRING, |
| propertyName); |
| assertFalse(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getterAccessor = |
| testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER); |
| MemberNaming.MethodSignature setterAccessor = |
| testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(classSubject, getterAccessor); |
| checkMethodIsRemoved(classSubject, setterAccessor); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(classSubject, getterAccessor); |
| checkMethodIsKept(classSubject, setterAccessor); |
| } |
| }); |
| } |
| |
| @Test |
| @Ignore("b/74103342") |
| public void testAccessorForLambdaIsRemovedWhenNotUsed() throws Exception { |
| TestKotlinClass testedClass = PROPERTY_ACCESS_FOR_LAMBDA_CLASS; |
| String mainClass = addMainToClasspath(testedClass.className + "Kt", |
| "noUseOfPropertyAccessorFromLambda"); |
| runTest("accessors", mainClass, (app) -> { |
| DexInspector dexInspector = new DexInspector(app); |
| ClassSubject classSubject = checkClassIsKept(dexInspector, testedClass.getClassName()); |
| String propertyName = "property"; |
| |
| MemberNaming.MethodSignature getterAccessor = |
| testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_LAMBDA); |
| MemberNaming.MethodSignature setterAccessor = |
| testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_LAMBDA); |
| |
| checkMethodIsRemoved(classSubject, getterAccessor); |
| checkMethodIsRemoved(classSubject, setterAccessor); |
| }); |
| } |
| |
| @Test |
| @Ignore("b/74103342") |
| public void testAccessorForLambdaCanBeInlined() throws Exception { |
| TestKotlinClass testedClass = PROPERTY_ACCESS_FOR_LAMBDA_CLASS; |
| String mainClass = addMainToClasspath(testedClass.className + "Kt", |
| "usePropertyAccessorFromLambda"); |
| runTest("accessors", mainClass, (app) -> { |
| DexInspector dexInspector = new DexInspector(app); |
| ClassSubject classSubject = checkClassIsKept(dexInspector, testedClass.getClassName()); |
| String propertyName = "property"; |
| FieldSubject fieldSubject = checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName); |
| assertFalse(fieldSubject.getField().accessFlags.isStatic()); |
| |
| MemberNaming.MethodSignature getterAccessor = |
| testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_LAMBDA); |
| MemberNaming.MethodSignature setterAccessor = |
| testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_LAMBDA); |
| if (allowAccessModification) { |
| assertTrue(fieldSubject.getField().accessFlags.isPublic()); |
| checkMethodIsRemoved(classSubject, getterAccessor); |
| checkMethodIsRemoved(classSubject, setterAccessor); |
| } else { |
| assertTrue(fieldSubject.getField().accessFlags.isPrivate()); |
| checkMethodIsKept(classSubject, getterAccessor); |
| checkMethodIsKept(classSubject, setterAccessor); |
| } |
| }); |
| } |
| |
| @Test |
| public void testStaticFieldAccessorWithJasmin() throws Exception { |
| JasminBuilder jasminBuilder = new JasminBuilder(); |
| ClassBuilder classBuilder = jasminBuilder.addClass("Foo"); |
| classBuilder.addDefaultConstructor(); |
| classBuilder.addStaticField("aField", "I", "5"); |
| classBuilder.addMainMethod( |
| ".limit stack 1", |
| "invokestatic Foo$Inner/readField()V", |
| "return" |
| ); |
| classBuilder.addStaticMethod("access$field", Collections.emptyList(), "I", |
| ".limit stack 1", |
| "getstatic Foo.aField I", |
| "ireturn"); |
| |
| classBuilder = jasminBuilder.addClass("Foo$Inner"); |
| classBuilder.addDefaultConstructor(); |
| classBuilder.addStaticMethod("readField", Collections.emptyList(), "V", |
| ".limit stack 2", |
| "getstatic java/lang/System.out Ljava/io/PrintStream;", |
| "invokestatic Foo/access$field()I", |
| "invokevirtual java/io/PrintStream/println(I)V", |
| "return" |
| ); |
| |
| Path javaOutput = writeToZip(jasminBuilder); |
| ProcessResult javaResult = ToolHelper.runJava(javaOutput, "Foo"); |
| if (javaResult.exitCode != 0) { |
| System.err.println(javaResult.stderr); |
| Assert.fail(); |
| } |
| |
| AndroidApp app = compileWithR8(jasminBuilder.build(), |
| keepMainProguardConfiguration("Foo") + "\n-dontobfuscate"); |
| String artOutput = runOnArt(app, "Foo"); |
| assertEquals(javaResult.stdout, artOutput); |
| } |
| } |