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");