Desugared lib keep rules generation bug

- Now records correctly keep class on
  emulated interfaces.
- More tests are now testing desugared
  library shrunk and non shrunk instead
  of only non shrunk.


Bug: 134732760
Change-Id: I5aee500e962377c8ae0800bceb0478a44bd06fb3
diff --git a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
index c836e98..8aa69a3 100644
--- a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
+++ b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
@@ -21,16 +21,19 @@
 public abstract class CodeToKeep {
 
   static CodeToKeep createCodeToKeep(InternalOptions options, NamingLens namingLens) {
-    if (!namingLens.hasPrefixRewritingLogic() || options.coreLibraryCompilation) {
+    if ((!namingLens.hasPrefixRewritingLogic() && options.emulateLibraryInterface.isEmpty())
+        || options.coreLibraryCompilation) {
       return new NopCodeToKeep();
     }
-    return new DesugaredLibraryCodeToKeep(namingLens);
+    return new DesugaredLibraryCodeToKeep(namingLens, options);
   }
 
   abstract void recordMethod(DexMethod method);
 
   abstract void recordField(DexField field);
 
+  abstract void recordClass(DexType type);
+
   abstract boolean isNop();
 
   abstract void generateKeepRules(InternalOptions options);
@@ -38,15 +41,25 @@
   public static class DesugaredLibraryCodeToKeep extends CodeToKeep {
 
     private final NamingLens namingLens;
+    private final Set<DexType> emulatedInterfaces = Sets.newIdentityHashSet();
     private final Map<DexType, Pair<Set<DexField>, Set<DexMethod>>> toKeep =
         new ConcurrentHashMap<>();
 
-    public DesugaredLibraryCodeToKeep(NamingLens namingLens) {
+    public DesugaredLibraryCodeToKeep(NamingLens namingLens, InternalOptions options) {
+      // Any class implementing one interface should implement the other one.
+      // Interface method desugaring should have created the types if emulatedLibraryInterfaces
+      // are set.
+      for (String rewrittenName : options.emulateLibraryInterface.values()) {
+        emulatedInterfaces.add(
+            options.itemFactory.lookupType(
+                options.itemFactory.lookupString(
+                    DescriptorUtils.javaTypeToDescriptor(rewrittenName))));
+      }
       this.namingLens = namingLens;
     }
 
     private boolean shouldKeep(DexType type) {
-      return namingLens.prefixRewrittenType(type) != null;
+      return namingLens.prefixRewrittenType(type) != null || emulatedInterfaces.contains(type);
     }
 
     @Override
@@ -76,6 +89,13 @@
       }
     }
 
+    @Override
+    void recordClass(DexType type) {
+      if (shouldKeep(type)) {
+        keepClass(type);
+      }
+    }
+
     private void keepClass(DexType type) {
       toKeep.putIfAbsent(
           type, new Pair<>(Sets.newConcurrentHashSet(), Sets.newConcurrentHashSet()));
@@ -143,6 +163,9 @@
     void recordField(DexField field) {}
 
     @Override
+    void recordClass(DexType type) {}
+
+    @Override
     boolean isNop() {
       return true;
     }
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index 59a2f55..6920e83 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -622,6 +622,10 @@
 
   private void writeClassData(DexProgramClass clazz) {
     assert clazz.hasMethodsOrFields();
+    desugaredLibraryCodeToKeep.recordClass(clazz.superType);
+    for (DexType itf : clazz.interfaces.values) {
+      desugaredLibraryCodeToKeep.recordClass(itf);
+    }
     mixedSectionOffsets.setOffsetFor(clazz, dest.position());
     dest.putUleb128(clazz.staticFields().size());
     dest.putUleb128(clazz.instanceFields().size());
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index 8b303ad..3adf685 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.TriFunction;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.google.common.collect.ImmutableList;
@@ -172,6 +173,17 @@
     return self();
   }
 
+  public CR addDesugaredCoreLibraryRunClassPath(
+      TriFunction<AndroidApiLevel, String, Boolean, Path> classPathSupplier,
+      AndroidApiLevel minAPILevel,
+      String keepRules,
+      boolean shrink) {
+    if (minAPILevel.getLevel() < AndroidApiLevel.P.getLevel()) {
+      addRunClasspathFiles(classPathSupplier.apply(minAPILevel, keepRules, shrink));
+    }
+    return self();
+  }
+
   public CR enableRuntimeAssertions() {
     assert getBackend() == Backend.CF;
     if (!this.vmArguments.contains("-ea")) {
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java b/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
index ab28e74..9f708ce 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
@@ -26,6 +26,7 @@
   private static Map<CacheEntry, TestCompileResult> computedLibraryCache =
       new ConcurrentHashMap<>();
 
+  @Deprecated
   protected boolean requiresCoreLibDesugaring(TestParameters parameters) {
     // TODO(b/134732760): Use the two other APIS instead.
     return requiresEmulatedInterfaceCoreLibDesugaring(parameters)
@@ -40,6 +41,10 @@
     return parameters.getApiLevel().getLevel() < AndroidApiLevel.P.getLevel();
   }
 
+  protected boolean requiresAnyCoreLibDesugaring(TestParameters parameters) {
+    return requiresRetargetCoreLibMemberDesugaring(parameters);
+  }
+
   protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel) throws RuntimeException {
     return buildDesugaredLibrary(apiLevel, "", false);
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
index 445b1dd..5682d45 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
@@ -9,7 +9,8 @@
 
 import com.android.tools.r8.D8TestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode;
@@ -22,18 +23,22 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class CustomCollectionTest extends CoreLibDesugarTestBase {
 
   private final TestParameters parameters;
+  private final boolean shrinkCoreLibrary;
 
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+  @Parameters(name = "{1}, shrinkCoreLibrary: {0}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
   }
 
-  public CustomCollectionTest(TestParameters parameters) {
+  public CustomCollectionTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+    this.shrinkCoreLibrary = shrinkDesugaredLibrary;
     this.parameters = parameters;
   }
 
@@ -42,15 +47,23 @@
 
   @Test
   public void testCustomCollection() throws Exception {
+    Box<String> keepRulesHolder = new Box<>("");
     D8TestRunResult d8TestRunResult =
         testForD8()
             .addInnerClasses(CustomCollectionTest.class)
             .setMinApi(parameters.getApiLevel())
+            .addOptionsModification(
+                options ->
+                    options.testing.desugaredLibraryKeepRuleConsumer =
+                        (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
             .enableCoreLibraryDesugaring(parameters.getApiLevel())
             .compile()
             .inspect(this::assertCustomCollectionCallsCorrect)
             .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary, parameters.getApiLevel())
+                this::buildDesugaredLibrary,
+                parameters.getApiLevel(),
+                keepRulesHolder.get(),
+                shrinkCoreLibrary)
             .run(parameters.getRuntime(), EXECUTOR)
             .assertSuccess();
     if (requiresEmulatedInterfaceCoreLibDesugaring(parameters)) {
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/DesugaredLibraryContentTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/DesugaredLibraryContentTest.java
index 20d4868..b130ee9 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/DesugaredLibraryContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/DesugaredLibraryContentTest.java
@@ -7,18 +7,11 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static junit.framework.TestCase.assertTrue;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
-import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
-import com.android.tools.r8.utils.codeinspector.InstructionSubject;
-import com.google.common.collect.ImmutableSet;
-import java.util.stream.Collectors;
 import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -39,8 +32,8 @@
   }
 
   @Test
-  public void test() throws Exception {
-    Assume.assumeTrue(requiresCoreLibDesugaring(parameters));
+  public void testDesugaredLibraryContent() throws Exception {
+    Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
     CodeInspector inspector = new CodeInspector(buildDesugaredLibrary(parameters.getApiLevel()));
     assertThat(inspector.clazz("j$.util.Optional"), isPresent());
     assertThat(inspector.clazz("j$.util.OptionalInt"), isPresent());
@@ -48,82 +41,14 @@
     assertThat(inspector.clazz("j$.util.OptionalDouble"), isPresent());
     assertThat(inspector.clazz("j$.util.function.Function"), isPresent());
     assertThat(inspector.clazz("j$.time.Clock"), isPresent());
-
-    ImmutableSet interfaces =
-        ImmutableSet.of(
-            "java.util.List",
-            "java.util.concurrent.TransferQueue",
-            "java.util.concurrent.ConcurrentMap",
-            "java.util.Queue",
-            "java.util.concurrent.ConcurrentNavigableMap",
-            "java.util.NavigableMap",
-            "java.util.ListIterator",
-            "java.util.SortedMap",
-            "java.util.Set",
-            "java.util.List",
-            "java.util.NavigableSet",
-            "java.util.SortedSet",
-            "java.util.Deque",
-            "java.util.concurrent.BlockingDeque",
-            "java.util.concurrent.BlockingQueue");
-
-    // TODO(134732760): Remove this debugging code.
     inspector
         .allClasses()
         .forEach(
-            clazz -> {
-              if (clazz.getOriginalName().startsWith("java.")
-                  && !interfaces.contains(clazz.getOriginalName())) {
-                System.out.println(clazz.getOriginalName());
-              }
-            });
-
-    if (requiresCoreLibDesugaring(parameters)) {
-      InstructionSubject long8Invoke =
-          inspector
-              .clazz("j$.util.stream.LongStream$-CC")
-              .uniqueMethodWithName("range")
-              .streamInstructions()
-              .filter(InstructionSubject::isInvokeStatic)
-              .collect(Collectors.toList())
-              .get(1);
-      assertFalse(long8Invoke.toString().contains("Long8;->"));
-      assertTrue(long8Invoke.toString().contains("backportedMethods"));
-      for (FoundClassSubject clazz : inspector.allClasses()) {
-        if (!(clazz.getOriginalName().equals("j$.lang.Long8")
-            || clazz.getOriginalName().equals("j$.lang.Integer8")
-            || clazz.getOriginalName().equals("j$.lang.Double8"))) {
-          for (FoundMethodSubject method : clazz.allMethods()) {
-            if (!method.isAbstract()) {
-              assertTrue(method.streamInstructions().noneMatch(instr -> instr.isInvoke() && (
-                  instr.toString().contains("Double8")
-                      || instr.toString().contains("Integer8")
-                      || instr.toString().contains("Long8"))
-              ));
-            }
-          }
-        }
-      }
-    }
-
-    // TODO(134732760): This should be a 0 count.
-    assertEquals(
-        requiresCoreLibDesugaring(parameters) ? 0 : 5,
-        inspector.allClasses().stream()
-            .map(ClassSubject::getOriginalName)
-            .filter(name -> name.startsWith("java."))
-            .filter(name -> !interfaces.contains(name))
-            .count());
-
-    // TODO(134732760): Remove this when above is a 0 count.
-    assertEquals(
-        requiresCoreLibDesugaring(parameters) ? 0 : 5,
-        inspector.allClasses().stream()
-            .map(ClassSubject::getOriginalName)
-            .filter(name -> name.startsWith("java."))
-            .filter(name -> !interfaces.contains(name))
-            .filter(name -> !name.contains("$-CC"))
-            .filter(name -> !name.contains("-$$Lambda"))
-            .count());
+            clazz ->
+                assertTrue(
+                    clazz.getOriginalName().startsWith("j$.")
+                        || clazz
+                            .getOriginalName()
+                            .contains(BackportedMethodRewriter.UTILITY_CLASS_NAME_PREFIX)));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/EmulatedInterfacesTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/EmulatedInterfacesTest.java
index cc3a1b0..5e241bb 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/EmulatedInterfacesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/EmulatedInterfacesTest.java
@@ -44,7 +44,7 @@
 
   @Test
   public void testEmulatedInterface() throws Exception {
-    Assume.assumeTrue((requiresCoreLibDesugaring(parameters)));
+    Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
     CodeInspector inspector =
         new CodeInspector(
             buildDesugaredLibrary(