[Metadata] Add tests for missing rewrite of context receivers

Bug: b/266396725
Change-Id: Ifd02bd5ca3a823dc96358a33f79086cf1fa97b62
diff --git a/src/test/java/com/android/tools/r8/KotlinCompilerTool.java b/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
index 36f3b07..259f1a0 100644
--- a/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
+++ b/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
@@ -5,6 +5,7 @@
 
 import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MAX_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.isWindows;
+import static com.google.common.io.Files.getNameWithoutExtension;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
@@ -223,6 +224,10 @@
     return this;
   }
 
+  public KotlinCompilerTool enableExperimentalContextReceivers() {
+    return addArguments("-Xcontext-receivers");
+  }
+
   public KotlinCompilerTool addSourceFiles(Path... files) {
     return addSourceFiles(Arrays.asList(files));
   }
@@ -268,7 +273,8 @@
                   try {
                     // The Kotlin compiler does not require particular naming of files except for
                     // the extension, so just create a file called source.kt in a new directory.
-                    Path fileNamedKt = temp.newFolder().toPath().resolve("source.kt");
+                    String newFileName = getNameWithoutExtension(fileNotNamedKt.toString()) + ".kt";
+                    Path fileNamedKt = temp.newFolder().toPath().resolve(newFileName);
                     Files.copy(fileNotNamedKt, fileNamedKt);
                     return fileNamedKt;
                   } catch (IOException e) {
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteContextReceiverTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteContextReceiverTest.java
new file mode 100644
index 0000000..206b7c9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteContextReceiverTest.java
@@ -0,0 +1,189 @@
+// Copyright (c) 2023, 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.KotlinCompilerVersion.KOTLINC_1_8_0;
+import static com.android.tools.r8.KotlinCompilerTool.KotlinTargetVersion.JAVA_8;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRewriteContextReceiverTest extends KotlinMetadataTestBase {
+
+  private static final String PKG_LIB = PKG + ".context_receiver_lib";
+  private static final String PKG_APP = PKG + ".context_receiver_app";
+  private static final Path LIB_FILE =
+      getFileInTest(PKG_PREFIX + "/context_receiver_lib", "lib.txt");
+  private static final Path MAIN_FILE =
+      getFileInTest(PKG_PREFIX + "/context_receiver_app", "main.txt");
+  private static final String MAIN = PKG_APP + ".MainKt";
+  private final TestParameters parameters;
+
+  private static final String EXPECTED =
+      StringUtils.lines(
+          "FooImpl::m1",
+          "BarImpl::m2",
+          "BazImpl::m3",
+          "BazImpl::m3",
+          "FooImpl::m1",
+          "BarImpl::m2",
+          "Hello World!");
+
+  @Parameterized.Parameters(name = "{0}, {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withCfRuntimes().build(),
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(KOTLINC_1_8_0)
+            .withOldCompilersStartingFrom(KOTLINC_1_8_0)
+            .withTargetVersion(JAVA_8)
+            .build());
+  }
+
+  public MetadataRewriteContextReceiverTest(
+      TestParameters parameters, KotlinTestParameters kotlinParameters) {
+    super(kotlinParameters);
+    this.parameters = parameters;
+  }
+
+  private static final KotlinCompileMemoizer libJars =
+      getCompileMemoizer()
+          .configure(
+              kotlinc ->
+                  kotlinc
+                      .addSourceFilesWithNonKtExtension(getStaticTemp(), LIB_FILE)
+                      .enableExperimentalContextReceivers());
+
+  @Test
+  public void smokeTest() throws Exception {
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
+            .addClasspathFiles(libJars.getForConfiguration(kotlinc, targetVersion))
+            .addSourceFilesWithNonKtExtension(temp, MAIN_FILE)
+            .setOutputPath(temp.newFolder().toPath())
+            .enableExperimentalContextReceivers()
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(
+            kotlinc.getKotlinStdlibJar(),
+            kotlinc.getKotlinReflectJar(),
+            libJars.getForConfiguration(kotlinc, targetVersion))
+        .addClasspath(output)
+        .run(parameters.getRuntime(), MAIN)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testMetadataForCompilationWithKeepAll() throws Exception {
+    Path libJar =
+        testForR8(parameters.getBackend())
+            .addClasspathFiles(kotlinc.getKotlinAnnotationJar())
+            .addProgramFiles(
+                libJars.getForConfiguration(kotlinc, targetVersion), kotlinc.getKotlinStdlibJar())
+            .addKeepClassAndMembersRules(PKG_LIB + ".*")
+            .addKeepAttributes(
+                ProguardKeepAttributes.SIGNATURE,
+                ProguardKeepAttributes.INNER_CLASSES,
+                ProguardKeepAttributes.ENCLOSING_METHOD)
+            .addKeepKotlinMetadata()
+            .allowDiagnosticWarningMessages()
+            .addOptionsModification(
+                options -> options.testing.keepMetadataInR8IfNotRewritten = false)
+            .compile()
+            // TODO(b/266396725): Assert equivalence of metadata.
+            .writeToZip();
+    Path main =
+        kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFilesWithNonKtExtension(temp, MAIN_FILE)
+            .setOutputPath(temp.newFolder().toPath())
+            .enableExperimentalContextReceivers()
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
+        .addClasspath(main)
+        .run(parameters.getRuntime(), MAIN)
+        // TODO(b/266396725): Rewrite context receivers in metadata.
+        .assertFailureWithErrorThatThrows(NoSuchMethodError.class);
+  }
+
+  @Test
+  public void testMetadataInExtensionFunction_renamedKotlinSources() throws Exception {
+    R8TestCompileResult r8LibraryResult =
+        testForR8(parameters.getBackend())
+            .addClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinAnnotationJar())
+            .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
+            // Ensure that we do not rename members
+            .addKeepRules("-keepclassmembers class * { *; }")
+            // Keep the Foo class but rename it.
+            .addKeepRules("-keep,allowobfuscation class " + PKG_LIB + ".Foo")
+            // Keep the Bar class but rename it.
+            .addKeepRules("-keep,allowobfuscation class " + PKG_LIB + ".Bar")
+            // Keep the Baz class but rename it.
+            .addKeepRules("-keep,allowobfuscation class " + PKG_LIB + ".Baz")
+            // Keep all Printer fields.
+            .addKeepRules("-keep class " + PKG_LIB + ".Printer { *; }")
+            // Keep Super, but allow minification.
+            .addKeepRules("-keep class " + PKG_LIB + ".LibKt { <methods>; }")
+            .addKeepKotlinMetadata()
+            .compile();
+
+    // Rewrite the kotlin source to rewrite the classes from the mapping file
+    String kotlinSource = FileUtils.readTextFile(MAIN_FILE, StandardCharsets.UTF_8);
+
+    CodeInspector inspector = r8LibraryResult.inspector();
+    // Rewrite the source kotlin file that reference the renamed classes uses in the context
+    // receivers.
+    for (String className : new String[] {"Foo", "Bar", "Baz"}) {
+      String originalClassName = PKG_LIB + "." + className;
+      ClassSubject clazz = inspector.clazz(originalClassName);
+      assertThat(clazz, isPresentAndRenamed());
+      kotlinSource =
+          kotlinSource.replace("import " + originalClassName, "import " + clazz.getFinalName());
+      kotlinSource =
+          kotlinSource.replace(
+              ": " + className + " {",
+              ": "
+                  + DescriptorUtils.getSimpleClassNameFromDescriptor(clazz.getFinalDescriptor())
+                  + " {");
+    }
+
+    Path newSource = temp.newFolder().toPath().resolve("main.kt");
+    Files.write(newSource, kotlinSource.getBytes(StandardCharsets.UTF_8));
+
+    Path libJar = r8LibraryResult.writeToZip();
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(newSource)
+            .setOutputPath(temp.newFolder().toPath())
+            .enableExperimentalContextReceivers()
+            .compile();
+
+    testForJvm()
+        .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
+        .addClasspath(output)
+        .run(parameters.getRuntime(), MAIN)
+        // TODO(b/266396725): Rewrite context receivers in metadata.
+        .assertFailureWithErrorThatThrows(NoSuchMethodError.class);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/context_receiver_app/main.txt b/src/test/java/com/android/tools/r8/kotlin/metadata/context_receiver_app/main.txt
new file mode 100644
index 0000000..9380c6f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/context_receiver_app/main.txt
@@ -0,0 +1,46 @@
+// Copyright (c) 2023, 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.context_receiver_app
+
+import com.android.tools.r8.kotlin.metadata.context_receiver_lib.Bar
+import com.android.tools.r8.kotlin.metadata.context_receiver_lib.Foo
+import com.android.tools.r8.kotlin.metadata.context_receiver_lib.Baz
+import com.android.tools.r8.kotlin.metadata.context_receiver_lib.Printer
+import com.android.tools.r8.kotlin.metadata.context_receiver_lib.callFooBar
+
+class FooImpl : Foo {
+
+  override fun m1(): String {
+    println("FooImpl::m1")
+    return "Hello "
+  }
+}
+
+class BarImpl : Bar {
+  override fun m2(): String {
+    println("BarImpl::m2")
+    return "World!"
+  }
+}
+
+class BazImpl : Baz {
+  override fun m3(): String {
+    println("BazImpl::m3")
+    return "BazImpl::m3"
+  }
+}
+
+fun main() {
+  with (FooImpl()) {
+    with (BarImpl()) {
+      val printer = Printer()
+      printer.fooBar()
+      with (BazImpl()) {
+        println(printer.getValue)
+        println(callFooBar())
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/context_receiver_lib/lib.txt b/src/test/java/com/android/tools/r8/kotlin/metadata/context_receiver_lib/lib.txt
new file mode 100644
index 0000000..0235848
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/context_receiver_lib/lib.txt
@@ -0,0 +1,35 @@
+// Copyright (c) 2023, 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.context_receiver_lib
+
+interface Foo {
+  fun m1(): String
+}
+
+interface Bar {
+  fun m2(): String
+}
+
+interface Baz {
+  fun m3(): String
+}
+
+context(Foo, Bar)
+class Printer {
+
+  fun fooBar() {
+    m1();
+    m2();
+  }
+
+  context(Baz)
+  val getValue: String
+    get() = if (System.currentTimeMillis() == 0L) "foo" else m3()
+}
+
+context(Foo, Bar)
+fun callFooBar() : String {
+  return m1() + m2();
+}
\ No newline at end of file