Merge "Reproduce b/122819537: kotlinc-generated synthetic methods are not traced."
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index 46d3a68..898d06c 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -885,6 +885,8 @@
     if (context instanceof ProguardKeepRule) {
       if (item.isDexEncodedMethod() && item.asDexEncodedMethod().accessFlags.isSynthetic()) {
         // Don't keep synthetic methods (see b/120971047 for additional details).
+        // TODO(b/122819537): need to distinguish lambda desugared synthetic methods v.s. kotlinc
+        // synthetic methods?
         return;
       }
 
diff --git a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java
index 767e818..700e2d4 100644
--- a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java
@@ -25,32 +25,42 @@
     return buildParameters(Backend.values(), KotlinTargetVersion.values());
   }
 
-  @Test
-  public void testDontShrinkAndDontObfuscate() throws Exception {
+  private void test(String... rules) throws Exception {
     testForR8(backend)
         .addLibraryFiles(ToolHelper.getDefaultAndroidJar(), ToolHelper.getKotlinStdlibJar())
         .addProgramFiles(ToolHelper.getKotlinReflectJar())
-        .addKeepRules("-dontshrink")
-        .addKeepRules("-dontobfuscate")
+        .addKeepRules(rules)
         .compile();
   }
 
   @Test
+  public void testAsIs() throws Exception {
+    test("-dontshrink", "-dontoptimize", "-dontobfuscate");
+  }
+
+  @Test
+  public void testDontShrinkAndDontOptimize() throws Exception {
+    test("-dontshrink", "-dontoptimize");
+  }
+
+  @Test
+  public void testDontShrinkAndDontObfuscate() throws Exception {
+    test("-dontshrink", "-dontobfuscate");
+  }
+
+  @Test
   public void testDontShrink() throws Exception {
-    testForR8(backend)
-        .addLibraryFiles(ToolHelper.getDefaultAndroidJar(), ToolHelper.getKotlinStdlibJar())
-        .addProgramFiles(ToolHelper.getKotlinReflectJar())
-        .addKeepRules("-dontshrink")
-        .compile();
+    test("-dontshrink");
+  }
+
+  @Test
+  public void testDontOptimize() throws Exception {
+    test("-dontoptimize");
   }
 
   @Test
   public void testDontObfuscate() throws Exception {
-    testForR8(backend)
-        .addLibraryFiles(ToolHelper.getDefaultAndroidJar(), ToolHelper.getKotlinStdlibJar())
-        .addProgramFiles(ToolHelper.getKotlinReflectJar())
-        .addKeepRules("-dontobfuscate")
-        .compile();
+    test("-dontobfuscate");
   }
 
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
index 44047d9..f19b089 100644
--- a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
@@ -25,33 +25,49 @@
     return buildParameters(Backend.values(), KotlinTargetVersion.values());
   }
 
-  @Test
-  public void testDontShrinkAndDontObfuscate() throws Exception {
+  private void test(String... rules) throws Exception {
     testForR8(backend)
         .addProgramFiles(ToolHelper.getKotlinStdlibJar())
-        .addKeepRules("-dontshrink")
-        .addKeepRules("-dontobfuscate")
+        .addKeepRules(rules)
         .compile();
   }
 
   @Test
+  public void testAsIs() throws Exception {
+    test("-dontshrink", "-dontoptimize", "-dontobfuscate");
+  }
+
+  @Test
+  public void testDontShrinkAndDontOptimize() throws Exception {
+    // TODO(b/122819537): need to trace kotlinc-generated synthetic methods.
+    if (backend == Backend.DEX) {
+      return;
+    }
+    test("-dontshrink", "-dontoptimize");
+  }
+
+  @Test
+  public void testDontShrinkAndDontObfuscate() throws Exception {
+    test("-dontshrink", "-dontobfuscate");
+  }
+
+  @Test
   public void testDontShrink() throws Exception {
-    // TODO(b/122819537)
+    // TODO(b/122819537): need to trace kotlinc-generated synthetic methods.
     if (backend == Backend.DEX) {
       return;
     }
-    testForR8(backend)
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar())
-        .addKeepRules("-dontshrink")
-        .compile();
+    test("-dontshrink");
+  }
+
+  @Test
+  public void testDontOptimize() throws Exception {
+    test("-dontoptimize");
   }
 
   @Test
   public void testDontObfuscate() throws Exception {
-    testForR8(backend)
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar())
-        .addKeepRules("-dontobfuscate")
-        .compile();
+    test("-dontobfuscate");
   }
 
 }
diff --git a/src/test/java/com/android/tools/r8/shaking/synthetic/KotlinCollectionDump.java b/src/test/java/com/android/tools/r8/shaking/synthetic/KotlinCollectionDump.java
new file mode 100644
index 0000000..d104272
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/synthetic/KotlinCollectionDump.java
@@ -0,0 +1,113 @@
+// Copyright (c) 2019, 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.shaking.synthetic;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+// Generated by running tools/asmifier.py on the following code snippet:
+//
+//  class Base {
+//    public static void foo() {
+//      System.out.println("Base::foo");
+//    }
+//    static void bar() {
+//      Sub.foo();
+//    }
+//  }
+//
+// then make bar _synthetic_ as `kotlinc` does.
+class Base implements Opcodes {
+
+  public static byte[] dump () throws Exception {
+
+    ClassWriter classWriter = new ClassWriter(0);
+    MethodVisitor methodVisitor;
+
+    classWriter.visit(V1_8, ACC_SUPER, "Base", null, "java/lang/Object", null);
+
+    classWriter.visitSource("Arrays.kt", null);
+
+    {
+      methodVisitor = classWriter.visitMethod(0, "<init>", "()V", null, null);
+      methodVisitor.visitCode();
+      Label label0 = new Label();
+      methodVisitor.visitLabel(label0);
+      methodVisitor.visitLineNumber(3, label0);
+      methodVisitor.visitVarInsn(ALOAD, 0);
+      methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+      methodVisitor.visitInsn(RETURN);
+      methodVisitor.visitMaxs(1, 1);
+      methodVisitor.visitEnd();
+    }
+    {
+      methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, "foo", "()V", null, null);
+      methodVisitor.visitCode();
+      Label label0 = new Label();
+      methodVisitor.visitLabel(label0);
+      methodVisitor.visitLineNumber(5, label0);
+      methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+      methodVisitor.visitLdcInsn("Base::foo");
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
+      Label label1 = new Label();
+      methodVisitor.visitLabel(label1);
+      methodVisitor.visitLineNumber(6, label1);
+      methodVisitor.visitInsn(RETURN);
+      methodVisitor.visitMaxs(2, 0);
+      methodVisitor.visitEnd();
+    }
+    {
+      methodVisitor = classWriter.visitMethod(ACC_STATIC | ACC_SYNTHETIC, "bar", "()V", null, null);
+      methodVisitor.visitCode();
+      Label label0 = new Label();
+      methodVisitor.visitLabel(label0);
+      methodVisitor.visitLineNumber(9, label0);
+      methodVisitor.visitMethodInsn(INVOKESTATIC, "Sub", "foo", "()V", false);
+      Label label1 = new Label();
+      methodVisitor.visitLabel(label1);
+      methodVisitor.visitLineNumber(10, label1);
+      methodVisitor.visitInsn(RETURN);
+      methodVisitor.visitMaxs(0, 0);
+      methodVisitor.visitEnd();
+    }
+    classWriter.visitEnd();
+
+    return classWriter.toByteArray();
+  }
+}
+
+// Generated by running tools/asmifier.py on the following code snippet:
+//  class Sub extends Base {}
+class Sub implements Opcodes {
+
+  public static byte[] dump () throws Exception {
+
+    ClassWriter classWriter = new ClassWriter(0);
+    MethodVisitor methodVisitor;
+
+    classWriter.visit(V1_8, ACC_SUPER, "Sub", null, "Base", null);
+
+    classWriter.visitSource("Arrays.kt", null);
+
+    {
+      methodVisitor = classWriter.visitMethod(0, "<init>", "()V", null, null);
+      methodVisitor.visitCode();
+      Label label0 = new Label();
+      methodVisitor.visitLabel(label0);
+      methodVisitor.visitLineNumber(13, label0);
+      methodVisitor.visitVarInsn(ALOAD, 0);
+      methodVisitor.visitMethodInsn(INVOKESPECIAL, "Base", "<init>", "()V", false);
+      methodVisitor.visitInsn(RETURN);
+      methodVisitor.visitMaxs(1, 1);
+      methodVisitor.visitEnd();
+    }
+    classWriter.visitEnd();
+
+    return classWriter.toByteArray();
+  }
+}
+
diff --git a/src/test/java/com/android/tools/r8/shaking/synthetic/StaticCallInSyntheticMethodAsmTest.java b/src/test/java/com/android/tools/r8/shaking/synthetic/StaticCallInSyntheticMethodAsmTest.java
new file mode 100644
index 0000000..cad2410
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/synthetic/StaticCallInSyntheticMethodAsmTest.java
@@ -0,0 +1,46 @@
+// Copyright (c) 2019, 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.shaking.synthetic;
+
+import com.android.tools.r8.AsmTestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class StaticCallInSyntheticMethodAsmTest extends AsmTestBase {
+  private final Backend backend;
+
+  @Parameterized.Parameters(name = "backend: {0}")
+  public static Backend[] data() {
+    return Backend.values();
+  }
+
+  public StaticCallInSyntheticMethodAsmTest(Backend backend) {
+    this.backend = backend;
+  }
+
+  // class Base {
+  //   static void foo() { ... }
+  //   static synthetic void bar() { Sub.foo(); }
+  // }
+  // class Sub extends Base {}
+  //
+  // As per b/120971047, we do not add synthetic methods to the root set.
+  // When running the above example with -dontshrink, the static call in the synthetic method is not
+  // traced, so no chance to rebind that call to Base#foo. Then, at the end of dex writing, it hits
+  // assertion error in the naming lense that checks if call targets are eligible for renaming.
+  @Test
+  public void test() throws Exception {
+    // TODO(b/122819537): need to trace kotlinc-generated synthetic methods.
+    if (backend == Backend.DEX) {
+      return;
+    }
+    testForR8(backend)
+        .addProgramClassFileData(Base.dump(), Sub.dump())
+        .addKeepRules("-dontshrink")
+        .compile();
+  }
+
+}