Version 2.1.40

Cherry pick: Add test reproducing lack of signature rewriting when
desugaring
CL: https://r8-review.googlesource.com/52041

Cherry pick: Change GenericSignatureRewriter to use a naming lens
CL: https://r8-review.googlesource.com/52044

Cherry pick: Should not use withLiveness as input to GenericSignatureRewriter
CL: https://r8-review.googlesource.com/52090

Bug: 158124557
Change-Id: I3300ba93b09b514cd2ab19d21d1ddf3c4c6ae9fc
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index c443620..c40d755 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -26,6 +26,7 @@
 import com.android.tools.r8.jar.CfApplicationWriter;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.PrefixRewritingNamingLens;
+import com.android.tools.r8.naming.signature.GenericSignatureRewriter;
 import com.android.tools.r8.origin.CommandLineOrigin;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApp;
@@ -256,6 +257,8 @@
               hasDexResources
                   ? NamingLens.getIdentityLens()
                   : PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView);
+          new GenericSignatureRewriter(appView, namingLens)
+              .run(appView.appInfo().classes(), executor);
         } else {
           // There are both cf and dex inputs in the program, and rewriting is required for
           // desugared library only on cf inputs. We cannot easily rewrite part of the program
@@ -315,6 +318,10 @@
     }
     DexApplication cfApp = app.builder().replaceProgramClasses(nonDexProgramClasses).build();
     ConvertedCfFiles convertedCfFiles = new ConvertedCfFiles();
+    NamingLens prefixRewritingNamingLens =
+        PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView);
+    new GenericSignatureRewriter(appView, prefixRewritingNamingLens)
+        .run(appView.appInfo().classes(), executor);
     new ApplicationWriter(
             cfApp,
             null,
@@ -322,7 +329,7 @@
             null,
             GraphLense.getIdentityLense(),
             InitClassLens.getDefault(),
-            PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView),
+            prefixRewritingNamingLens,
             null,
             convertedCfFiles)
         .write(executor);
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java
index 4ba88f4..4bef8cec 100644
--- a/src/main/java/com/android/tools/r8/L8.java
+++ b/src/main/java/com/android/tools/r8/L8.java
@@ -15,7 +15,9 @@
 import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
 import com.android.tools.r8.jar.CfApplicationWriter;
+import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.PrefixRewritingNamingLens;
+import com.android.tools.r8.naming.signature.GenericSignatureRewriter;
 import com.android.tools.r8.origin.CommandLineOrigin;
 import com.android.tools.r8.shaking.AnnotationRemover;
 import com.android.tools.r8.shaking.L8TreePruner;
@@ -132,13 +134,16 @@
       app = converter.convert(app, executor);
       assert appView.appInfo() == appInfo;
 
+      NamingLens namingLens = PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView);
+      new GenericSignatureRewriter(appView, namingLens).run(appInfo.classes(), executor);
+
       new CfApplicationWriter(
               app,
               appView,
               options,
               options.getMarker(Tool.L8),
               GraphLense.getIdentityLense(),
-              PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView),
+              namingLens,
               null)
           .write(options.getClassFileConsumer());
       options.printWarnings();
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 622224b..c3ad10a 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -803,12 +803,6 @@
         namingLens = new Minifier(appView.withLiveness()).run(executorService, timing);
         timing.end();
       } else {
-        // Rewrite signature annotations for applications that are not minified.
-        if (appView.appInfo().hasLiveness()) {
-          // TODO(b/124726014): Rewrite signature annotations in lens rewriting instead of here?
-          new GenericSignatureRewriter(appView.withLiveness())
-              .run(appView.appInfo().classes(), executorService);
-        }
         namingLens = NamingLens.getIdentityLens();
       }
 
@@ -860,6 +854,12 @@
         options.syntheticProguardRulesConsumer.accept(synthesizedProguardRules);
       }
 
+      NamingLens prefixRewritingNamingLens =
+          PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView, namingLens);
+
+      new GenericSignatureRewriter(appView, prefixRewritingNamingLens)
+          .run(appView.appInfo().classes(), executorService);
+
       // Generate the resulting application resources.
       writeApplication(
           executorService,
@@ -867,7 +867,7 @@
           appView,
           appView.graphLense(),
           appView.initClassLens(),
-          PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView, namingLens),
+          prefixRewritingNamingLens,
           options,
           ProguardMapSupplier.create(classNameMapper, options));
 
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 2111c0d..8778485 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "2.1.39";
+  public static final String LABEL = "2.1.40";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
index 0c223b1..9b659a0 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -17,13 +17,11 @@
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.InnerClassAttribute;
-import com.android.tools.r8.naming.signature.GenericSignatureRewriter;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.ProguardPackageNameList;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
-import com.android.tools.r8.utils.IteratorUtils;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
@@ -146,13 +144,6 @@
     }
     timing.end();
 
-    timing.begin("rename-generic");
-    new GenericSignatureRewriter(appView, renaming)
-        .run(
-            () -> IteratorUtils.filter(classes.iterator(), DexClass::isProgramClass),
-            executorService);
-    timing.end();
-
     timing.begin("rename-arrays");
     appView.dexItemFactory().forAllTypes(this::renameArrayTypeIfNeeded);
     timing.end();
diff --git a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
index eef8234..1f66108 100644
--- a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
+++ b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
@@ -13,14 +13,13 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.ThreadUtils;
-import com.google.common.collect.Maps;
 import java.lang.reflect.GenericSignatureFormatError;
-import java.util.Map;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.function.BiConsumer;
@@ -32,23 +31,24 @@
 public class GenericSignatureRewriter {
 
   private final AppView<?> appView;
-  private final Map<DexType, DexString> renaming;
+  private final NamingLens namingLens;
   private final InternalOptions options;
   private final Reporter reporter;
 
-  public GenericSignatureRewriter(AppView<?> appView) {
-    this(appView, Maps.newIdentityHashMap());
-  }
-
-  public GenericSignatureRewriter(AppView<?> appView, Map<DexType, DexString> renaming) {
+  public GenericSignatureRewriter(AppView<?> appView, NamingLens namingLens) {
     this.appView = appView;
-    this.renaming = renaming;
+    this.namingLens = namingLens;
     this.options = appView.options();
     this.reporter = options.reporter;
   }
 
   public void run(Iterable<? extends DexProgramClass> classes, ExecutorService executorService)
       throws ExecutionException {
+    // Rewrite signature annotations for applications that are minified or if we have liveness
+    // information, since we could have pruned types.
+    if (namingLens.isIdentityLens() && !appView.appInfo().hasLiveness()) {
+      return;
+    }
     // Classes may not be the same as appInfo().classes() if applymapping is used on classpath
     // arguments. If that is the case, the ProguardMapMinifier will pass in all classes that is
     // either ProgramClass or has a mapping. This is then transitively called inside the
@@ -204,7 +204,7 @@
       if (appView.appInfo().hasLiveness() && appView.withLiveness().appInfo().wasPruned(type)) {
         type = appView.dexItemFactory().objectType;
       }
-      DexString renamedDescriptor = renaming.getOrDefault(type, type.descriptor);
+      DexString renamedDescriptor = namingLens.lookupDescriptor(type);
       if (parserPosition == ParserPosition.CLASS_SUPER_OR_INTERFACE_ANNOTATION
           && currentClassContext != null) {
         // We may have merged the type down to the current class type.
@@ -251,16 +251,14 @@
                       getClassBinaryNameFromDescriptor(enclosingDescriptor)
                           + DescriptorUtils.INNER_CLASS_SEPARATOR
                           + name));
-      String enclosingRenamedBinaryName =
-          getClassBinaryNameFromDescriptor(
-              renaming.getOrDefault(enclosingType, enclosingType.descriptor).toString());
       type = appView.graphLense().lookupType(type);
-      DexString renamedDescriptor = renaming.get(type);
-      if (renamedDescriptor != null) {
+      String renamedDescriptor = namingLens.lookupDescriptor(type).toString();
+      if (!renamedDescriptor.equals(type.toDescriptorString())) {
         // TODO(b/147504070): If this is a merged class equal to the class context, do not add.
         // Pick the renamed inner class from the fully renamed binary name.
-        String fullRenamedBinaryName =
-            getClassBinaryNameFromDescriptor(renamedDescriptor.toString());
+        String fullRenamedBinaryName = getClassBinaryNameFromDescriptor(renamedDescriptor);
+        String enclosingRenamedBinaryName =
+            getClassBinaryNameFromDescriptor(namingLens.lookupDescriptor(enclosingType).toString());
         int innerClassPos = enclosingRenamedBinaryName.length() + 1;
         if (innerClassPos < fullRenamedBinaryName.length()) {
           renamedSignature.append(fullRenamedBinaryName.substring(innerClassPos));
diff --git a/src/main/java/com/android/tools/r8/relocator/Relocator.java b/src/main/java/com/android/tools/r8/relocator/Relocator.java
index aaf83b1..1e8420e 100644
--- a/src/main/java/com/android/tools/r8/relocator/Relocator.java
+++ b/src/main/java/com/android/tools/r8/relocator/Relocator.java
@@ -87,8 +87,7 @@
       SimplePackagesRewritingMapper packageRemapper = new SimplePackagesRewritingMapper(appView);
       NamingLens namingLens = packageRemapper.compute(command.getMapping());
 
-      new GenericSignatureRewriter(appView, packageRemapper.getTypeMappings())
-          .run(appInfo.classes(), executor);
+      new GenericSignatureRewriter(appView, namingLens).run(appInfo.classes(), executor);
 
       new CfApplicationWriter(
               app,
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
new file mode 100644
index 0000000..ff07b24
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
@@ -0,0 +1,129 @@
+// 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.desugar.desugaredlibrary;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.BooleanUtils;
+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.time.LocalDate;
+import java.util.List;
+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 DesugaredGenericSignatureTest extends DesugaredLibraryTestBase {
+
+  private final TestParameters parameters;
+  private final boolean shrinkDesugaredLibrary;
+  private static final String EXPECTED = StringUtils.lines("1970", "1", "2");
+
+  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(), BooleanUtils.values());
+  }
+
+  public DesugaredGenericSignatureTest(TestParameters parameters, boolean shrinkDesugaredLibrary) {
+    this.parameters = parameters;
+    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+    testForD8()
+        .addInnerClasses(DesugaredGenericSignatureTest.class)
+        .setMinApi(parameters.getApiLevel())
+        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+        .setIncludeClassesChecksum(true)
+        .compile()
+        .inspect(this::checkRewrittenSignature)
+        .addDesugaredCoreLibraryRunClassPath(
+            this::buildDesugaredLibrary,
+            parameters.getApiLevel(),
+            keepRuleConsumer.get(),
+            shrinkDesugaredLibrary)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+    testForR8(parameters.getBackend())
+        .addInnerClasses(DesugaredGenericSignatureTest.class)
+        .addKeepMainRule(Main.class)
+        .addKeepAllClassesRuleWithAllowObfuscation()
+        .addKeepAttributes(
+            ProguardKeepAttributes.SIGNATURE,
+            ProguardKeepAttributes.INNER_CLASSES,
+            ProguardKeepAttributes.ENCLOSING_METHOD)
+        .enableInliningAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+        .compile()
+        .inspect(this::checkRewrittenSignature)
+        .addDesugaredCoreLibraryRunClassPath(
+            this::buildDesugaredLibrary,
+            parameters.getApiLevel(),
+            keepRuleConsumer.get(),
+            shrinkDesugaredLibrary)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  private void checkRewrittenSignature(CodeInspector inspector) {
+    if (!requiresEmulatedInterfaceCoreLibDesugaring(parameters)) {
+      return;
+    }
+    ClassSubject javaTimeBox = inspector.clazz(JavaTimeDateBox.class);
+    assertThat(javaTimeBox, isPresent());
+    ClassSubject box = inspector.clazz(Box.class);
+    assertThat(box, isPresent());
+    String finalBoxDescriptor = box.getFinalDescriptor();
+    assertEquals(
+        "Ljava/lang/Object;"
+            + finalBoxDescriptor.substring(0, finalBoxDescriptor.length() - 1)
+            + "<Lj$/time/LocalDate;>;",
+        javaTimeBox.getFinalSignatureAttribute());
+  }
+
+  public interface Box<T> {
+    T addOne(T t);
+  }
+
+  public static class JavaTimeDateBox implements Box<java.time.LocalDate> {
+
+    @Override
+    @NeverInline
+    public LocalDate addOne(LocalDate localDate) {
+      return localDate.plusDays(1);
+    }
+  }
+
+  public static class Main {
+
+    public static Box<java.time.LocalDate> bar() {
+      return new JavaTimeDateBox();
+    }
+
+    public static void main(String[] args) {
+      LocalDate localDate = bar().addOne(LocalDate.of(1970, 1, 1));
+      System.out.println(localDate.getYear());
+      System.out.println(localDate.getMonthValue());
+      System.out.println(localDate.getDayOfMonth());
+    }
+  }
+}