Version 1.5.24

Cherry-pick: Rename anonymous classes if not reserved.
CL: https://r8-review.googlesource.com/c/r8/+/37980

Bug: 131810441, 131210377
Change-Id: I3fdcd1f7659c2b2bd9f0eb9947e0d6896293eae5
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 35cb73f..43fff83 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 = "1.5.23";
+  public static final String LABEL = "1.5.24";
 
   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 04cc0ba..d707108 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -25,6 +25,7 @@
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
 import com.android.tools.r8.utils.Timing;
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
@@ -113,16 +114,19 @@
 
     timing.begin("rename-classes");
     for (DexClass clazz : classes) {
-      // Let anonymous classes be as-is.
-      if (clazz.isAnonymousClass()) {
-        continue;
-      }
       if (!renaming.containsKey(clazz.type)) {
+        boolean wasAnonymous = clazz.isAnonymousClass();
         // TreePruner already removed inner-class / enclosing-method attributes for local classes.
         assert !clazz.isLocalClass();
         clazz.annotations = clazz.annotations.keepIf(this::isNotKotlinMetadata);
         DexString renamed = computeName(clazz.type);
         renaming.put(clazz.type, renamed);
+        // Then-anonymous class is no longer anonymous after minification. Remaining attributes
+        // may make the computation of simple name fail on JVM prior to JDK 9.
+        if (wasAnonymous) {
+          clazz.removeEnclosingMethod(Predicates.alwaysTrue());
+          clazz.removeInnerClasses(attr -> attr.getInner() == clazz.type);
+        }
         // If the class is a member class and it has used $ separator, its renamed name should have
         // the same separator (as long as inner-class attribute is honored).
         assert !keepInnerClassStructure
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index 5b7b182..1671197 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -119,12 +119,11 @@
     if (reachableStaticFields != null) {
       clazz.setStaticFields(reachableStaticFields);
     }
-    // If the class is a local class, it'll become an ordinary class by renaming.
+    // If the class is local, it'll become an ordinary class by renaming.
     // Invalidate its inner-class / enclosing-method attributes early.
     if (appView.options().isMinifying()
         && appView.rootSet().mayBeMinified(clazz.type, appView)
         && clazz.isLocalClass()) {
-      assert clazz.getEnclosingMethod() != null;
       assert clazz.getInnerClassAttributeForThisClass() != null;
       clazz.removeEnclosingMethod(Predicates.alwaysTrue());
       InnerClassAttribute innerClassAttribute =
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
index 710e592..de5dd77 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
@@ -135,12 +135,12 @@
       "Outer$Inner"
   );
   private static final String RENAMED_OUTPUT = StringUtils.lines(
-      "c",
+      "d",
       "a",
       "a",
       "a",
+      "c[][][]",
       "b[][][]",
-      "[][][]",
       "a",
       "a"
   );
@@ -215,7 +215,7 @@
             .addKeepMainRule(MAIN)
             .addKeepRules("-keep class **.ClassGetSimpleName*")
             .addKeepRules("-keep class **.Outer*")
-            .addKeepRules("-keepattributes InnerClasses,EnclosingMethod")
+            .addKeepAttributes("InnerClasses", "EnclosingMethod")
             .addKeepRules("-printmapping " + createNewMappingPath().toAbsolutePath().toString())
             .minification(enableMinification)
             .setMinApi(parameters.getRuntime())
@@ -238,7 +238,7 @@
             // Comment out the following line to reproduce b/120130435
             // then use OUTPUT_WITH_SHRUNK_ATTRIBUTES
             .addKeepRules("-keep,allowobfuscation class **.Outer*")
-            .addKeepRules("-keepattributes InnerClasses,EnclosingMethod")
+            .addKeepAttributes("InnerClasses", "EnclosingMethod")
             .addKeepRules("-printmapping " + createNewMappingPath().toAbsolutePath().toString())
             .minification(enableMinification)
             .setMinApi(parameters.getRuntime())
diff --git a/src/test/java/com/android/tools/r8/naming/b131810441/AnonymousClassRenamingTest.java b/src/test/java/com/android/tools/r8/naming/b131810441/AnonymousClassRenamingTest.java
new file mode 100644
index 0000000..66c21f6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/b131810441/AnonymousClassRenamingTest.java
@@ -0,0 +1,65 @@
+// 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.naming.b131810441;
+
+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.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.naming.b131810441.sub.Outer;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+class TestMain {
+  public static void main(String... args) {
+    Outer o = Outer.create(8);
+    o.trigger();
+  }
+}
+
+@RunWith(Parameterized.class)
+public class AnonymousClassRenamingTest extends TestBase {
+  private static final String EXPECTED_OUTPUT = StringUtils.lines("Outer#<init>(8)");
+
+  private final TestParameters parameters;
+  private final boolean enableMinification;
+
+  @Parameterized.Parameters(name = "{0} minification: {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimes().build(),
+        BooleanUtils.values());
+  }
+
+  public AnonymousClassRenamingTest(TestParameters parameters, boolean enableMinification) {
+    this.parameters = parameters;
+    this.enableMinification = enableMinification;
+  }
+
+  @Test
+  public void b131810441() throws Exception {
+    testForR8Compat(parameters.getBackend())
+        .addProgramClasses(TestMain.class)
+        .addProgramClassesAndInnerClasses(Outer.class)
+        .addKeepMainRule(TestMain.class)
+        .addKeepAttributes("InnerClasses", "EnclosingMethod")
+        .enableInliningAnnotations()
+        .minification(enableMinification)
+        .setMinApi(parameters.getRuntime())
+        .run(parameters.getRuntime(), TestMain.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT)
+        .inspect(inspector -> {
+          ClassSubject anonymous = inspector.clazz(Outer.class.getName() + "$1");
+          assertThat(anonymous, isPresent());
+          assertEquals(enableMinification, anonymous.isRenamed());
+        });
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/b131810441/sub/Outer.java b/src/test/java/com/android/tools/r8/naming/b131810441/sub/Outer.java
new file mode 100644
index 0000000..cecd4a7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/b131810441/sub/Outer.java
@@ -0,0 +1,28 @@
+// 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.naming.b131810441.sub;
+
+import com.android.tools.r8.NeverInline;
+
+public class Outer {
+  private Runnable runner;
+
+  private Outer(int x) {
+    runner = new Runnable() {
+      @Override
+      public void run() {
+        System.out.println("Outer#<init>(" + x + ")");
+      }
+    };
+  }
+
+  public static Outer create(int x) {
+    return new Outer(x);
+  }
+
+  @NeverInline
+  public void trigger() {
+    runner.run();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/attributes/MissingEnclosingMethodTest.java b/src/test/java/com/android/tools/r8/shaking/attributes/MissingEnclosingMethodTest.java
index 8c0157f..69f5662 100644
--- a/src/test/java/com/android/tools/r8/shaking/attributes/MissingEnclosingMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/attributes/MissingEnclosingMethodTest.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.shaking.attributes;
 
-import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.R8CompatTestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.errors.Unreachable;
@@ -74,7 +74,7 @@
     DUMP_18,
     DUMP_16;
 
-    public void addInnerClasses(R8FullTestBuilder builder) throws IOException {
+    public void addInnerClasses(R8CompatTestBuilder builder) throws IOException {
       switch (this) {
         case CLASS:
           builder.addInnerClasses(DataClass.class);
@@ -101,7 +101,8 @@
         BooleanUtils.values());
   }
 
-  public MissingEnclosingMethodTest(TestParameters parameters, TestConfig config, boolean enableMinification) {
+  public MissingEnclosingMethodTest(
+      TestParameters parameters, TestConfig config, boolean enableMinification) {
     this.parameters = parameters;
     this.config = config;
     this.enableMinification = enableMinification;
@@ -109,14 +110,13 @@
 
   @Test
   public void b131210377() throws Exception {
-    R8FullTestBuilder builder =
-        testForR8(parameters.getBackend())
+    R8CompatTestBuilder builder =
+        testForR8Compat(parameters.getBackend())
             .addProgramClasses(DataClass.class, DataClassUser.class);
     config.addInnerClasses(builder);
     builder
         .addKeepMainRule(DataClassUser.class)
-        .addKeepRules("-keepattributes Signature,InnerClasses,EnclosingMethod")
-        .addOptionsModification(o -> o.forceProguardCompatibility = true)
+        .addKeepAttributes("Signature", "InnerClasses", "EnclosingMethod")
         .minification(enableMinification)
         .setMinApi(parameters.getRuntime())
         .run(parameters.getRuntime(), DataClassUser.class)
diff --git a/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingAnnotationremovalTest.java b/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingAnnotationremovalTest.java
index 2f97b0c..0a21b8c 100644
--- a/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingAnnotationremovalTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingAnnotationremovalTest.java
@@ -96,7 +96,7 @@
     Assert.assertFalse(inner.isLocalClass());
     ClassSubject anonymous = inspector.clazz("annotationremoval.OuterClass$1");
     Assert.assertTrue(anonymous.isPresent());
-    Assert.assertTrue(anonymous.isAnonymousClass());
+    Assert.assertEquals(!getMinify().isMinify(), anonymous.isAnonymousClass());
     Assert.assertFalse(anonymous.isMemberClass());
     Assert.assertFalse(anonymous.isLocalClass());
     ClassSubject local = inspector.clazz("annotationremoval.OuterClass$1LocalMagic");