Wrapper merge support

Bug: 142451915
Change-Id: I3ec30da28d53a9bbce0b171e1ca5bc04ed4d56c0
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
index 95db2cf..2bf43f2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
@@ -95,6 +95,7 @@
 public class DesugaredLibraryWrapperSynthesizer {
 
   public static final String WRAPPER_PREFIX = "$r8$wrapper$";
+  public static final String WRAPPER_DESCRIPTOR_PREFIX = "L" + WRAPPER_PREFIX;
   public static final String TYPE_WRAPPER_SUFFIX = "$-WRP";
   public static final String VIVIFIED_TYPE_WRAPPER_SUFFIX = "$-V-WRP";
 
@@ -118,6 +119,10 @@
     this.converter = converter;
   }
 
+  public static boolean isSynthesizedWrapper(DexType clazz) {
+    return clazz.descriptor.toString().startsWith(WRAPPER_DESCRIPTOR_PREFIX);
+  }
+
   boolean hasSynthesized(DexType type) {
     return generatedWrappers.contains(type);
   }
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
index 1aef50b..21f78a7 100644
--- a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
+import com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer;
 import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
 import com.android.tools.r8.ir.desugar.LambdaRewriter;
 import com.android.tools.r8.ir.desugar.NestBasedAccessDesugaring;
@@ -85,6 +86,7 @@
         || BackportedMethodRewriter.hasRewrittenMethodPrefix(a.type)
         || InterfaceMethodRewriter.hasDispatchClassSuffix(a.type)
         || NestBasedAccessDesugaring.isNestConstructor(a.type)
+        || DesugaredLibraryWrapperSynthesizer.isSynthesizedWrapper(a.type)
         || a.type.descriptor.toString().equals(TwrCloseResourceRewriter.UTILITY_CLASS_DESCRIPTOR);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/conversionTests/WrapperMergeTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/conversionTests/WrapperMergeTest.java
new file mode 100644
index 0000000..c4d1880
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/conversionTests/WrapperMergeTest.java
@@ -0,0 +1,71 @@
+// 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.desugar.corelib.conversionTests;
+
+import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.TestRuntime.DexRuntime;
+import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
+import java.util.Arrays;
+import org.junit.Test;
+
+public class WrapperMergeTest extends APIConversionTestBase {
+
+  @Test
+  public void testWrapperMerge() throws Exception {
+    // Multiple wrapper classes have to be merged here.
+    Path path1 = testForD8()
+        .addProgramClasses(Executor1.class)
+        .setMinApi(AndroidApiLevel.B)
+        .enableCoreLibraryDesugaring(AndroidApiLevel.B)
+        .compile()
+        .inspect(this::assertWrappers)
+        .writeToZip();
+    Path path2 = testForD8()
+        .addProgramClasses(Executor2.class)
+        .setMinApi(AndroidApiLevel.B)
+        .enableCoreLibraryDesugaring(AndroidApiLevel.B)
+        .compile()
+        .inspect(this::assertWrappers)
+        .writeToZip();
+    testForD8()
+        .addProgramFiles(path1,path2)
+        .compile()
+        .addDesugaredCoreLibraryRunClassPath(
+            this::buildDesugaredLibraryWithConversionExtension, AndroidApiLevel.B)
+        .run(new DexRuntime(DexVm.ART_9_0_0_HOST), Executor1.class)
+        .assertSuccessWithOutput(
+            StringUtils.lines("[1, 2, 3]"));
+
+  }
+
+  private void assertWrappers(CodeInspector inspector) {
+    assertEquals(2,inspector.allClasses().stream().filter(c -> c.getOriginalName().contains(
+        DesugaredLibraryWrapperSynthesizer.WRAPPER_PREFIX)).count());
+  }
+
+  static class Executor1 {
+
+    public static void main(String[] args) {
+      int[] ints = new int[3];
+      Arrays.setAll(ints,x->x+1);
+      System.out.println(Arrays.toString(ints));
+    }
+  }
+
+  static class Executor2 {
+
+    public static void main(String[] args) {
+      int[] ints = new int[3];
+      Arrays.setAll(ints,x->x+2);
+      System.out.println(Arrays.toString(ints));
+    }
+  }
+
+}