Add test for allow access modification with kotlin metadata
Bug: 154348683
Change-Id: I93b945e6a8c0c41cf6066018c5b3c2dca0405c85
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
new file mode 100644
index 0000000..549f834
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
@@ -0,0 +1,156 @@
+// Copyright (c) 2020, 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.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static junit.framework.TestCase.assertEquals;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.StringContains.containsString;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRewriteAllowAccessModificationTest extends KotlinMetadataTestBase {
+
+ private static final String PKG_LIB = PKG + ".allow_access_modification_lib";
+ private static final String PKG_APP = PKG + ".allow_access_modification_app";
+ private final String EXPECTED =
+ StringUtils.lines(
+ "4",
+ "2",
+ "42",
+ "3",
+ "1",
+ "42",
+ "5",
+ "6",
+ "7",
+ "funPrivate",
+ "funInternal",
+ "funProtected",
+ "extensionPrivate",
+ "extensionInternal",
+ "companionPrivate",
+ "companionInternal",
+ "staticPrivate",
+ "staticInternal");
+
+ @Parameterized.Parameters(name = "{0} target: {1}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ }
+
+ public MetadataRewriteAllowAccessModificationTest(
+ TestParameters parameters, KotlinTargetVersion targetVersion) {
+ super(targetVersion);
+ this.parameters = parameters;
+ }
+
+ private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+ private static Map<KotlinTargetVersion, Path> libReferenceJars = new HashMap<>();
+ private final TestParameters parameters;
+
+ @BeforeClass
+ public static void createLibJar() throws Exception {
+ for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
+ libJars.put(
+ targetVersion,
+ kotlinc(KOTLINC, targetVersion)
+ .addSourceFiles(
+ getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
+ .compile());
+ libReferenceJars.put(
+ targetVersion,
+ kotlinc(KOTLINC, targetVersion)
+ .addSourceFiles(
+ getKotlinFileInTest(
+ DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib_reference"))
+ .compile());
+ }
+ }
+
+ @Test
+ public void smokeTest() throws Exception {
+ Path libJar = libReferenceJars.get(targetVersion);
+ Path output =
+ kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ .addClasspathFiles(libJar)
+ .addSourceFiles(
+ getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+ .setOutputPath(temp.newFolder().toPath())
+ .compile();
+ testForJvm()
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addClasspath(output)
+ .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ @Test
+ public void testMetadataForLib() throws Exception {
+ // We compile libjar with -allowaccesmodification such that all visibility modifiers are updated
+ // to be public. We also compile it with a mapping file to rename Lib to LibReference. After
+ // running with R8, the output should be binary compatible with libReference.
+ Path libJar =
+ testForR8(parameters.getBackend())
+ .addProgramFiles(libJars.get(targetVersion))
+ .addKeepRules("-keepclassmembers,allowaccessmodification class **.Lib { *; }")
+ .addKeepRules("-keep,allowaccessmodification,allowobfuscation class **.Lib { *; }")
+ .addKeepRules("-keepclassmembers,allowaccessmodification class **.Lib$Comp { *; }")
+ .addKeepRules("-keep,allowaccessmodification,allowobfuscation class **.Lib$Comp { *; }")
+ .addKeepRules("-keep,allowaccessmodification,allowobfuscation class **.LibKt { *; }")
+ .addKeepRules("-allowaccessmodification")
+ .addApplyMapping(
+ StringUtils.lines(
+ PKG_LIB + ".Lib -> " + PKG_LIB + ".LibReference:",
+ PKG_LIB + ".Lib$Comp -> " + PKG_LIB + ".LibReference$Comp:",
+ PKG_LIB + ".LibKt -> " + PKG_LIB + ".LibReferenceKt:",
+ " void extensionPrivate(" + PKG_LIB + ".Lib) -> extensionPrivate",
+ " void extensionInternal(" + PKG_LIB + ".Lib) -> extensionInternal",
+ " void staticPrivate() -> staticPrivateReference",
+ " void staticInternal() -> staticInternalReference"))
+ .addKeepRuntimeVisibleAnnotations()
+ .compile()
+ .inspect(this::inspect)
+ .writeToZip();
+ ProcessResult mainResult =
+ kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ .addClasspathFiles(libJar)
+ .addSourceFiles(
+ getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+ .setOutputPath(temp.newFolder().toPath())
+ .compileRaw();
+ assertEquals(1, mainResult.exitCode);
+ assertThat(mainResult.stderr, containsString("cannot access 'LibReference'"));
+ }
+
+ private void inspect(CodeInspector inspector) throws Exception {
+ // TODO(b/154348683): Assert equality between LibReference and Lib.
+ // assertEqualMetadata(new CodeInspector(libReferenceJars.get(targetVersion)), inspector);
+ ClassSubject lib = inspector.clazz(PKG_LIB + ".Lib");
+ MethodSubject funInline = lib.uniqueMethodWithName("funInline$main");
+ assertThat(funInline, isPresent());
+ // TODO(b/154348683): Keep the inline method package private.
+ // assertTrue(funInline.isPackagePrivate());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_app/main.kt
new file mode 100644
index 0000000..fc2e518
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_app/main.kt
@@ -0,0 +1,40 @@
+// Copyright (c) 2020, 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.metadata.allow_access_modification_app
+
+import com.android.tools.r8.kotlin.metadata.allow_access_modification_lib.LibReference
+import com.android.tools.r8.kotlin.metadata.allow_access_modification_lib.extensionInternal
+import com.android.tools.r8.kotlin.metadata.allow_access_modification_lib.extensionPrivate
+import com.android.tools.r8.kotlin.metadata.allow_access_modification_lib.staticInternalReference
+import com.android.tools.r8.kotlin.metadata.allow_access_modification_lib.staticPrivateReference
+
+fun main() {
+ val libReference = LibReference(1, 2, 3, 4)
+ println(libReference.propPrimaryPrivate)
+ println(libReference.propPrimaryInternal)
+ println(libReference.propPrivate)
+ libReference.propPrimaryPrivate = 5
+ libReference.propPrimaryInternal = 6
+ libReference.propPrivate = 7
+ println(libReference.readOnlyPropPrimaryPrivate)
+ println(libReference.readOnlyPropPrimaryInternal)
+ println(libReference.readOnlyPropInternal)
+ println(libReference.propPrimaryPrivate)
+ println(libReference.propPrimaryInternal)
+ println(libReference.propPrivate)
+
+ libReference.funPrivate()
+ libReference.funInternal()
+ libReference.funProtected()
+
+ libReference.extensionPrivate()
+ libReference.extensionInternal()
+
+ LibReference.companionPrivate()
+ LibReference.companionInternal()
+
+ staticPrivateReference()
+ staticInternalReference()
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_lib/lib.kt
new file mode 100644
index 0000000..f77d4f8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_lib/lib.kt
@@ -0,0 +1,59 @@
+// Copyright (c) 2020, 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.metadata.allow_access_modification_lib
+
+internal class Lib internal constructor(
+ internal val readOnlyPropPrimaryInternal: Int,
+ internal var propPrimaryInternal : Int,
+ private val readOnlyPropPrimaryPrivate: Int,
+ internal var propPrimaryPrivate : Int) {
+
+ internal val propInternal: Int = 42
+ private var propPrivate: Int = 0
+
+ private fun funPrivate() {
+ println("funPrivate")
+ }
+
+ internal fun funInternal() {
+ println("funInternal")
+ }
+
+ protected fun funProtected() {
+ println("funProtected")
+ }
+
+ // Keep this internal to ensure we do not modify inline functions.
+ internal inline fun funInline() {
+ println("funInline")
+ }
+
+ internal companion object Comp {
+
+ private fun companionPrivate() {
+ println("companionPrivate")
+ }
+
+ internal fun companionInternal() {
+ println("companionInternal")
+ }
+ }
+}
+
+private fun Lib.extensionPrivate() {
+ println("extensionPrivate")
+}
+
+internal fun Lib.extensionInternal() {
+ println("extensionInternal")
+}
+
+private fun staticPrivate() {
+ println("staticPrivate")
+}
+
+internal fun staticInternal() {
+ println("staticInternal")
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_lib/lib_reference.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_lib/lib_reference.kt
new file mode 100644
index 0000000..a26d8d2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_lib/lib_reference.kt
@@ -0,0 +1,59 @@
+// Copyright (c) 2020, 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.metadata.allow_access_modification_lib
+
+class LibReference(
+ val readOnlyPropPrimaryInternal: Int,
+ var propPrimaryInternal : Int,
+ val readOnlyPropPrimaryPrivate: Int,
+ var propPrimaryPrivate : Int) {
+
+ val readOnlyPropInternal: Int = 42
+ var propPrivate: Int = 42
+
+ fun funPrivate() {
+ println("funPrivate")
+ }
+
+ fun funInternal() {
+ println("funInternal")
+ }
+
+ fun funProtected() {
+ println("funProtected")
+ }
+
+ // Keep this internal to ensure we do not modify inline functions.
+ internal inline fun funInline() {
+ println("funInline")
+ }
+
+ companion object Factory {
+
+ fun companionPrivate() {
+ println("companionPrivate")
+ }
+
+ fun companionInternal() {
+ println("companionInternal")
+ }
+ }
+}
+
+fun LibReference.extensionPrivate() {
+ println("extensionPrivate")
+}
+
+fun LibReference.extensionInternal() {
+ println("extensionInternal")
+}
+
+fun staticPrivateReference() {
+ println("staticPrivate")
+}
+
+fun staticInternalReference() {
+ println("staticInternal")
+}