Add tests about @Metadata rewriting of nestedClass.
Bug: 70169921
Change-Id: I9655b98df0201cd490b99cb8f9e5938cb2f7b287
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
new file mode 100644
index 0000000..e05cd9a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
@@ -0,0 +1,125 @@
+// 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.DescriptorUtils.descriptorToJavaType;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.KmClassSubject;
+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 MetadataRewriteInNestedClassTest extends KotlinMetadataTestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0} target: {1}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ }
+
+ public MetadataRewriteInNestedClassTest(
+ TestParameters parameters, KotlinTargetVersion targetVersion) {
+ super(targetVersion);
+ this.parameters = parameters;
+ }
+
+ private static final Map<KotlinTargetVersion, Path> nestedLibJarMap = new HashMap<>();
+
+ @BeforeClass
+ public static void createLibJar() throws Exception {
+ String nestedLibFolder = PKG_PREFIX + "/nested_lib";
+ for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
+ Path nestedLibJar =
+ kotlinc(KOTLINC, targetVersion)
+ .addSourceFiles(getKotlinFileInTest(nestedLibFolder, "lib"))
+ .compile();
+ nestedLibJarMap.put(targetVersion, nestedLibJar);
+ }
+ }
+
+ @Test
+ public void testMetadataInNestedClass() throws Exception {
+ Path libJar =
+ testForR8(parameters.getBackend())
+ .addProgramFiles(nestedLibJarMap.get(targetVersion))
+ // Keep the Outer class and delegations.
+ .addKeepRules("-keep class **.Outer { <init>(...); *** delegate*(...); }")
+ // Keep Inner to check the hierarchy.
+ .addKeepRules("-keep class **.*Inner")
+ // Keep Nested, but allow obfuscation.
+ .addKeepRules("-keep,allowobfuscation class **.*Nested")
+ .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+ .addKeepAttributes(ProguardKeepAttributes.INNER_CLASSES)
+ .addKeepAttributes(ProguardKeepAttributes.ENCLOSING_METHOD)
+ .compile()
+ .inspect(this::inspect)
+ .writeToZip();
+
+ Path output =
+ kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ .addClasspathFiles(libJar)
+ .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/nested_app", "main"))
+ .setOutputPath(temp.newFolder().toPath())
+ .compile();
+
+ testForJvm()
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addClasspath(output)
+ .run(parameters.getRuntime(), PKG + ".nested_app.MainKt")
+ .assertSuccessWithOutputLines("Inner::inner", "42", "Nested::nested", "42");
+ }
+
+ private void inspect(CodeInspector inspector) {
+ String outerClassName = PKG + ".nested_lib.Outer";
+ String innerClassName = outerClassName + "$Inner";
+ String nestedClassName = outerClassName + "$Nested";
+
+ ClassSubject inner = inspector.clazz(innerClassName);
+ assertThat(inner, isPresent());
+ assertThat(inner, not(isRenamed()));
+
+ ClassSubject nested = inspector.clazz(nestedClassName);
+ assertThat(nested, isRenamed());
+
+ ClassSubject outer = inspector.clazz(outerClassName);
+ assertThat(outer, isPresent());
+ assertThat(outer, not(isRenamed()));
+
+ KmClassSubject kmClass = outer.getKmClass();
+ assertThat(kmClass, isPresent());
+
+ kmClass.getNestedClassDescriptors().forEach(nestedClassDescriptor -> {
+ ClassSubject nestedClass = inspector.clazz(descriptorToJavaType(nestedClassDescriptor));
+ if (nestedClass.getOriginalName().contains("Inner")) {
+ assertThat(nestedClass, not(isRenamed()));
+ assertEquals(nestedClassDescriptor, nestedClass.getFinalDescriptor());
+ } else {
+ assertThat(nestedClass, isRenamed());
+ // TODO(b/70169921): nestedClass in KmClass should refer to renamed classes.
+ assertNotEquals(nestedClassDescriptor, nestedClass.getFinalDescriptor());
+ }
+ });
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/nested_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/nested_app/main.kt
new file mode 100644
index 0000000..d4f91d4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/nested_app/main.kt
@@ -0,0 +1,12 @@
+// 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.nested_app
+
+import com.android.tools.r8.kotlin.metadata.nested_lib.Outer
+
+fun main() {
+ val o = Outer()
+ println(o.delegateInner())
+ println(o.delegateNested(21))
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/nested_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/nested_lib/lib.kt
new file mode 100644
index 0000000..13765fc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/nested_lib/lib.kt
@@ -0,0 +1,27 @@
+// 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.nested_lib
+
+class Outer {
+ val prop1
+ get() = 42
+
+ fun delegateInner() = Inner().inner()
+
+ fun delegateNested(x: Int) = Nested().nested(x)
+
+ inner class Inner {
+ fun inner(): Int {
+ println("Inner::inner")
+ return this@Outer.prop1
+ }
+ }
+
+ class Nested {
+ fun nested(x: Int): Int {
+ println("Nested::nested")
+ return 2 * x
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmClassSubject.java
index af619ea..c467da4 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmClassSubject.java
@@ -104,6 +104,16 @@
}
@Override
+ public List<String> getNestedClassDescriptors() {
+ return null;
+ }
+
+ @Override
+ public List<ClassSubject> getNestedClasses() {
+ return null;
+ }
+
+ @Override
public List<String> getSealedSubclassDescriptors() {
return null;
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmClassSubject.java
index 39a3ce7..f99ac6c 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmClassSubject.java
@@ -76,6 +76,26 @@
.collect(Collectors.toList());
}
+ private String nestClassDescriptor(String nestClassName) {
+ return DescriptorUtils.getDescriptorFromClassBinaryName(
+ kmClass.name + DescriptorUtils.INNER_CLASS_SEPARATOR + nestClassName);
+ }
+
+ @Override
+ public List<String> getNestedClassDescriptors() {
+ return kmClass.getNestedClasses().stream()
+ .map(this::nestClassDescriptor)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List<ClassSubject> getNestedClasses() {
+ return kmClass.getNestedClasses().stream()
+ .map(this::nestClassDescriptor)
+ .map(this::getClassSubjectFromDescriptor)
+ .collect(Collectors.toList());
+ }
+
@Override
public List<String> getSealedSubclassDescriptors() {
return kmClass.getSealedSubclasses().stream()
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassSubject.java
index 191956c..7fb1f9f 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassSubject.java
@@ -15,6 +15,10 @@
public abstract List<ClassSubject> getSuperTypes();
+ public abstract List<String> getNestedClassDescriptors();
+
+ public abstract List<ClassSubject> getNestedClasses();
+
public abstract List<String> getSealedSubclassDescriptors();
public abstract List<ClassSubject> getSealedSubclasses();