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();