Add test for localDelegatedProperties in R8
Bug: 157988734
Change-Id: Ia1ceedbad10c313cfeedf87b1d672977ef058ab5
diff --git a/build.gradle b/build.gradle
index 919888b..6050eda 100644
--- a/build.gradle
+++ b/build.gradle
@@ -279,6 +279,7 @@
examplesKotlinCompileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
kotlinR8TestResourcesCompileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
errorprone("com.google.errorprone:error_prone_core:$errorproneVersion")
+ testImplementation "org.jetbrains.kotlin:kotlin-reflect:1.3.31"
}
def r8LibPath = "$buildDir/libs/r8lib.jar"
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
index b96a52c..ce26b77 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
@@ -76,7 +76,6 @@
Path libJar =
testForR8(parameters.getBackend())
.addProgramFiles(libJars.get(targetVersion))
- // Allow renaming A to ensure that we rename in the flexible upper bound type.
.addKeepAllClassesRule()
.addKeepAllAttributes()
.compile()
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
new file mode 100644
index 0000000..50007fb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
@@ -0,0 +1,174 @@
+// 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 org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+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 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 MetadataRewriteDelegatedPropertyTest extends KotlinMetadataTestBase {
+
+ private static final String PKG_LIB = PKG + ".delegated_property_lib";
+ private static final String PKG_APP = PKG + ".delegated_property_app";
+ private static final String EXPECTED_MAIN =
+ StringUtils.lines(
+ "foo has been assigned to 'customDelegate' in"
+ + " com.android.tools.r8.kotlin.metadata.delegated_property_lib.Delegates",
+ "foo has been read in CustomDelegate from 'customDelegate' in"
+ + " com.android.tools.r8.kotlin.metadata.delegated_property_lib.Delegates",
+ "foo",
+ "read-only has been read in CustomReadOnlyDelegate from 'customReadOnlyDelegate' in"
+ + " com.android.tools.r8.kotlin.metadata.delegated_property_lib.Delegates",
+ "read-only",
+ "Generating lazy string",
+ "42",
+ "Hello World!",
+ "Hello World!",
+ "Jane Doe",
+ "42",
+ "Checking property for image",
+ "Checking property for text",
+ "image_id",
+ "text_id");
+ private static final String EXPECTED_REFLECT =
+ StringUtils.lines(
+ "foo has been assigned to 'customDelegate' in"
+ + " com.android.tools.r8.kotlin.metadata.delegated_property_lib.Delegates",
+ "foo");
+
+ @Parameterized.Parameters(name = "{0} target: {1}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ }
+
+ public MetadataRewriteDelegatedPropertyTest(
+ TestParameters parameters, KotlinTargetVersion targetVersion) {
+ super(targetVersion);
+ this.parameters = parameters;
+ }
+
+ private final TestParameters parameters;
+ private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+
+ @BeforeClass
+ public static void createLibJar() throws Exception {
+ for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
+ Path baseLibJar =
+ kotlinc(KOTLINC, targetVersion)
+ .addSourceFiles(
+ getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
+ .compile();
+ libJars.put(targetVersion, baseLibJar);
+ }
+ }
+
+ @Test
+ public void smokeTest() throws Exception {
+ Path libJar = libJars.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_MAIN);
+ }
+
+ @Test
+ public void smokeTestReflect() throws Exception {
+ Path libJar = libJars.get(targetVersion);
+ Path output =
+ kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ .addClasspathFiles(libJar)
+ .addSourceFiles(
+ getKotlinFileInTest(
+ DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main_reflect"))
+ .setOutputPath(temp.newFolder().toPath())
+ .compile();
+ testForJvm()
+ .addRunClasspathFiles(
+ ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar)
+ .addClasspath(output)
+ .run(parameters.getRuntime(), PKG_APP + ".Main_reflectKt")
+ .assertSuccessWithOutput(EXPECTED_REFLECT);
+ }
+
+ @Test
+ public void testMetadataForLib() throws Exception {
+ Path libJar =
+ testForR8(parameters.getBackend())
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(libJars.get(targetVersion))
+ .addKeepRules("-keep class " + PKG_LIB + ".Delegates { *; }")
+ .addKeepRules("-keep class " + PKG_LIB + ".Resource { *; }")
+ .addKeepRules("-keep class " + PKG_LIB + ".User { *; }")
+ .addKeepRules("-keep class " + PKG_LIB + ".ProvidedDelegates { *; }")
+ .compile()
+ // TODO(b/157988734): When we start modeling localDelegatedProperties, inspect the code.
+ .writeToZip();
+ 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_MAIN);
+ }
+
+ @Test
+ public void testMetadataForReflect() throws Exception {
+ Path libJar =
+ testForR8(parameters.getBackend())
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(libJars.get(targetVersion))
+ .addKeepRules("-keep class " + PKG_LIB + ".Delegates { *; }")
+ .addKeepRules("-keep class " + PKG_LIB + ".Resource { *; }")
+ .addKeepRules("-keep class " + PKG_LIB + ".CustomDelegate { *; }")
+ .compile()
+ .writeToZip();
+ ProcessResult result =
+ kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ .addClasspathFiles(libJar)
+ .addSourceFiles(
+ getKotlinFileInTest(
+ DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main_reflect"))
+ .setOutputPath(temp.newFolder().toPath())
+ .compileRaw();
+ assertEquals(1, result.exitCode);
+ assertThat(
+ result.stderr,
+ containsString(
+ "unsupported [reference to the synthetic extension property for a Java get/set"
+ + " method]"));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/delegated_property_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/delegated_property_app/main.kt
new file mode 100644
index 0000000..7bfd637
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/delegated_property_app/main.kt
@@ -0,0 +1,31 @@
+// 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.delegated_property_app
+
+import com.android.tools.r8.kotlin.metadata.delegated_property_lib.Delegates
+import com.android.tools.r8.kotlin.metadata.delegated_property_lib.ProvidedDelegates
+import com.android.tools.r8.kotlin.metadata.delegated_property_lib.Resource
+import com.android.tools.r8.kotlin.metadata.delegated_property_lib.User
+
+fun main() {
+
+ val delegates = Delegates()
+ delegates.customDelegate = Resource("foo");
+ println(delegates.customDelegate)
+ println(delegates.customReadOnlyDelegate)
+ println(delegates.lazyString)
+ println(delegates.localDelegatedProperties { Resource("Hello World!") })
+
+ val user = User(mapOf(
+ "name" to "Jane Doe",
+ "age" to 42
+ ))
+
+ println(user.name)
+ println(user.age)
+
+ val providedDelegates = ProvidedDelegates()
+ println(providedDelegates.image)
+ println(providedDelegates.text)
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/delegated_property_app/main_reflect.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/delegated_property_app/main_reflect.kt
new file mode 100644
index 0000000..0369a86
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/delegated_property_app/main_reflect.kt
@@ -0,0 +1,21 @@
+// 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.delegated_property_app
+
+import com.android.tools.r8.kotlin.metadata.delegated_property_lib.CustomDelegate
+import com.android.tools.r8.kotlin.metadata.delegated_property_lib.Delegates
+import com.android.tools.r8.kotlin.metadata.delegated_property_lib.Resource
+import kotlin.reflect.KMutableProperty0
+import kotlin.reflect.jvm.isAccessible
+
+fun main() {
+ val delegates = Delegates()
+ delegates.customDelegate = Resource("foo");
+ println(delegates::customDelegate.getResource())
+}
+
+inline fun KMutableProperty0<*>.getResource(): Resource {
+ isAccessible = true
+ return (getDelegate() as CustomDelegate).resource
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/delegated_property_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/delegated_property_lib/lib.kt
new file mode 100644
index 0000000..54c58df
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/delegated_property_lib/lib.kt
@@ -0,0 +1,88 @@
+// 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.delegated_property_lib
+
+import kotlin.properties.ReadOnlyProperty
+import kotlin.reflect.KProperty
+
+class Resource(private var s : String = "") {
+
+ override fun toString(): String {
+ return s;
+ }
+}
+
+class CustomDelegate(var resource: Resource = Resource()) {
+
+ operator fun getValue(thisRef: Any?, property: KProperty<*>): Resource {
+ println("$resource has been read in CustomDelegate from '" +
+ "${property.name}' in ${thisRef?.javaClass?.typeName}")
+ return resource;
+ }
+
+ operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Resource) {
+ println("$value has been assigned to '${property.name}'" +
+ " in ${thisRef?.javaClass?.typeName}")
+ this.resource = value
+ }
+}
+
+class CustomReadOnlyDelegate(private var resource : Resource = Resource("read-only"))
+ : ReadOnlyProperty<Any?, Resource> {
+ override fun getValue(thisRef: Any?, property: KProperty<*>): Resource {
+ println("$resource has been read in CustomReadOnlyDelegate" +
+ " from '${property.name}' in ${thisRef?.javaClass?.typeName}")
+ return resource;
+ }
+}
+
+class Delegates {
+
+ var customDelegate : Resource by CustomDelegate()
+ val customReadOnlyDelegate : Resource by CustomReadOnlyDelegate()
+ val lazyString : String by lazy {
+ println("Generating lazy string")
+ "42"
+ }
+
+ fun localDelegatedProperties(compute: () -> Resource) : Resource {
+ val foo by lazy(compute)
+ println(foo)
+ return foo
+ }
+}
+class User(val map : Map<String, Any?>) {
+ val name : String by map
+ val age: Int by map
+}
+
+class ResourceDelegate(val r : Resource): ReadOnlyProperty<ProvidedDelegates, Resource> {
+ override fun getValue(thisRef: ProvidedDelegates, property: KProperty<*>): Resource {
+ return r
+ }
+}
+
+class ResourceLoader(val id: Resource) {
+ operator fun provideDelegate(
+ thisRef: ProvidedDelegates,
+ prop: KProperty<*>
+ ): ReadOnlyProperty<ProvidedDelegates, Resource> {
+ checkProperty(prop.name)
+ return ResourceDelegate(id)
+ }
+
+ private fun checkProperty(name: String) {
+ println("Checking property for " + name)
+ }
+}
+
+class ProvidedDelegates {
+ fun bindResource(id: String): ResourceLoader {
+ return ResourceLoader(Resource(id))
+ }
+
+ val image by bindResource("image_id")
+ val text by bindResource("text_id")
+}