Fix incorrect split on $ in DescriptorUtils#getSimpleClassNameFromDescriptor.
Bug: 120811478
Change-Id: Icee657bcb359a60970917425d8dda5954d8dacaa
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
index 1245520..1c345a2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
@@ -629,8 +629,9 @@
if (dexMethod != null) {
return dexMethod;
}
- String clazzDescriptor = DescriptorUtils.getSimpleClassNameFromDescriptor(clazz.toString());
- String postFix = "$" + clazzDescriptor + "$" + method + "$" + proto.shorty.toString();
+ String unqualifiedName =
+ DescriptorUtils.getUnqualifiedClassNameFromDescriptor(clazz.toString());
+ String postFix = "$" + unqualifiedName + "$" + method + "$" + proto.shorty.toString();
DexType clazz = factory.createType(UTILITY_CLASS_DESCRIPTOR_PREFIX + postFix + ";");
dexMethod = factory.createMethod(clazz, proto, method);
return dexMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
index e78280f..d61758b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
@@ -6,7 +6,7 @@
import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
import static com.android.tools.r8.utils.DescriptorUtils.getCanonicalNameFromDescriptor;
import static com.android.tools.r8.utils.DescriptorUtils.getClassNameFromDescriptor;
-import static com.android.tools.r8.utils.DescriptorUtils.getSimpleClassNameFromDescriptor;
+import static com.android.tools.r8.utils.DescriptorUtils.getUnqualifiedClassNameFromDescriptor;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
@@ -195,7 +195,7 @@
if (!renamed && needsToRetrieveInnerName) {
name = holder.getInnerClassAttributeForThisClass().getInnerName().toString();
} else {
- name = getSimpleClassNameFromDescriptor(descriptor);
+ name = getUnqualifiedClassNameFromDescriptor(descriptor);
}
if (arrayDepth > 0) {
name = name + Strings.repeat("[]", arrayDepth);
diff --git a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
index a30860f..c40fbc3 100644
--- a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
@@ -65,8 +65,8 @@
}
// The Java reflection library assumes that that inner-class names are separated by a $ and
// thus we allow the mapping of an inner name to rely on that too. If the dollar is not
- // present after pulling off the original inner-name, then we revert to using the simple name
- // of the inner class as its name.
+ // present after pulling off the original inner-name, then we revert to using the unqualified
+ // name of the inner class as its name.
DexType innerType = attribute.getInner();
String inner = DescriptorUtils.descriptorToInternalName(innerType.descriptor.toString());
String innerName = attribute.getInnerName().toString();
@@ -74,7 +74,9 @@
if (lengthOfPrefix < 0
|| inner.lastIndexOf(DescriptorUtils.INNER_CLASS_SEPARATOR, lengthOfPrefix - 1) < 0
|| !inner.endsWith(innerName)) {
- return lookupSimpleName(innerType, options.itemFactory);
+ String descriptor = lookupDescriptor(innerType).toString();
+ return options.itemFactory.createString(
+ DescriptorUtils.getUnqualifiedClassNameFromDescriptor(descriptor));
}
// At this point we assume the input was of the form: <OuterType>$<index><InnerName>
@@ -90,7 +92,9 @@
// Hitting means we have converted a proper Outer$Inner relationship to an invalid one.
assert !options.testing.allowFailureOnInnerClassErrors
: "Outer$Inner class was remapped without keeping the dollar separator";
- return lookupSimpleName(innerType, options.itemFactory);
+ String descriptor = lookupDescriptor(innerType).toString();
+ return options.itemFactory.createString(
+ DescriptorUtils.getUnqualifiedClassNameFromDescriptor(descriptor));
}
return options.itemFactory.createString(innerTypeMapped.substring(index + 1));
}
diff --git a/src/main/java/com/android/tools/r8/naming/NamingLens.java b/src/main/java/com/android/tools/r8/naming/NamingLens.java
index 8488f09..54a7e31 100644
--- a/src/main/java/com/android/tools/r8/naming/NamingLens.java
+++ b/src/main/java/com/android/tools/r8/naming/NamingLens.java
@@ -3,9 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
-import static com.android.tools.r8.utils.DescriptorUtils.DESCRIPTOR_PACKAGE_SEPARATOR;
-import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
-
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -48,15 +45,6 @@
public abstract DexString lookupDescriptor(DexType type);
- public DexString lookupSimpleName(DexType type, DexItemFactory factory) {
- String descriptor = lookupDescriptor(type).toString();
- int lastSeparator = descriptor.lastIndexOf(DESCRIPTOR_PACKAGE_SEPARATOR);
- String simpleName =
- descriptor.substring(lastSeparator > 0 ? lastSeparator + 1 : 1, descriptor.length() - 1);
- // TODO(b/120811478): Replace by DescriptorUtils.getSimpleClassNameFromDescriptor once fixed.
- return factory.createString(simpleName);
- }
-
public abstract DexString lookupInnerName(InnerClassAttribute attribute, InternalOptions options);
public abstract DexString lookupName(DexMethod method);
@@ -68,7 +56,7 @@
public final DexString lookupName(DexReference reference, DexItemFactory dexItemFactory) {
if (reference.isDexType()) {
DexString renamed = lookupDescriptor(reference.asDexType());
- return dexItemFactory.createString(descriptorToJavaType(renamed.toString()));
+ return dexItemFactory.createString(DescriptorUtils.descriptorToJavaType(renamed.toString()));
}
if (reference.isDexMethod()) {
return lookupName(reference.asDexMethod());
diff --git a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
index 2499ccb..09b0e54 100644
--- a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
@@ -207,13 +207,13 @@
}
/**
- * Get simple class name from its descriptor.
+ * Get unqualified class name from its descriptor.
*
- * @param classDescriptor a class descriptor i.e. "Ljava/lang/Object;"
- * @return class name i.e. "Object"
+ * @param classDescriptor a class descriptor i.e. "Ljava/lang/Object;" or "La/b/C$D;"
+ * @return class name i.e. "Object" or "C$D" (not "D")
*/
- public static String getSimpleClassNameFromDescriptor(String classDescriptor) {
- return getSimpleClassNameFromBinaryName(getClassBinaryNameFromDescriptor(classDescriptor));
+ public static String getUnqualifiedClassNameFromDescriptor(String classDescriptor) {
+ return getUnqualifiedClassNameFromBinaryName(getClassBinaryNameFromDescriptor(classDescriptor));
}
/**
@@ -293,16 +293,18 @@
}
/**
- * Get class name from its binary name.
+ * Get unqualified class name from its binary name.
*
* @param classBinaryName a class binary name i.e. "java/lang/Object" or "a/b/C$Inner"
- * @return class name i.e. "Object" or "Inner"
+ * @return class name i.e. "Object" or "C$Inner" (not "Inner")
+ *
+ * Note that we cannot rely on $ separator in binary name or descriptor because a class, which is
+ * not a member or local class, can still contain $ in its name. For the correct retrieval of the
+ * simple name of member or local classes, use the inner name in the inner-class attribute (or
+ * refer to ReflectionOptimizer#computeClassName as an example).
*/
- public static String getSimpleClassNameFromBinaryName(String classBinaryName) {
- int simpleNameIndex = classBinaryName.lastIndexOf(INNER_CLASS_SEPARATOR);
- if (simpleNameIndex < 0) {
- simpleNameIndex = classBinaryName.lastIndexOf(DESCRIPTOR_PACKAGE_SEPARATOR);
- }
+ public static String getUnqualifiedClassNameFromBinaryName(String classBinaryName) {
+ int simpleNameIndex = classBinaryName.lastIndexOf(DESCRIPTOR_PACKAGE_SEPARATOR);
return (simpleNameIndex < 0) ? classBinaryName : classBinaryName.substring(simpleNameIndex + 1);
}
diff --git a/src/test/java/com/android/tools/r8/naming/AvoidRTest.java b/src/test/java/com/android/tools/r8/naming/AvoidRTest.java
index 2eda1cd..5c2d882 100644
--- a/src/test/java/com/android/tools/r8/naming/AvoidRTest.java
+++ b/src/test/java/com/android/tools/r8/naming/AvoidRTest.java
@@ -3,14 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
-import static com.android.tools.r8.utils.DescriptorUtils.getSimpleClassNameFromDescriptor;
+import static com.android.tools.r8.utils.DescriptorUtils.getUnqualifiedClassNameFromDescriptor;
import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.R8FullTestBuilder;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.jasmin.JasminBuilder;
import com.android.tools.r8.jasmin.JasminTestBase;
import com.android.tools.r8.utils.FileUtils;
@@ -26,15 +27,15 @@
@RunWith(Parameterized.class)
public class AvoidRTest extends JasminTestBase {
- private Backend backend;
+ private final TestParameters parameters;
- @Parameters(name = "Backend: {0}")
- public static Backend[] data() {
- return ToolHelper.getBackends();
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().build();
}
- public AvoidRTest(Backend backend) {
- this.backend = backend;
+ public AvoidRTest(TestParameters parameters) {
+ this.parameters = parameters;
}
@Test
@@ -44,7 +45,7 @@
Set<String> expectedNames = ImmutableSet.of("P", "Q", "S", "T");
JasminBuilder jasminBuilder = new JasminBuilder();
- R8FullTestBuilder builder = testForR8(backend);
+ R8FullTestBuilder builder = testForR8(parameters.getBackend());
for (int i = 0; i < 4; i++) {
jasminBuilder.addClass("TopLevel" + Integer.toString(i));
}
@@ -67,8 +68,9 @@
assertThat(classSubject, isRenamed());
String renamedDescriptor = classSubject.getFinalDescriptor();
assertTrue(usedDescriptors.add(renamedDescriptor));
- assertNotEquals("R", getSimpleClassNameFromDescriptor(renamedDescriptor));
- assertTrue(expectedNames.contains(getSimpleClassNameFromDescriptor(renamedDescriptor)));
+ assertNotEquals("R", getUnqualifiedClassNameFromDescriptor(renamedDescriptor));
+ assertTrue(expectedNames.contains(
+ getUnqualifiedClassNameFromDescriptor(renamedDescriptor)));
});
});
}
@@ -76,7 +78,7 @@
@Test
public void test_withoutPackageHierarchy() throws Exception {
JasminBuilder jasminBuilder = new JasminBuilder();
- R8FullTestBuilder builder = testForR8(backend);
+ R8FullTestBuilder builder = testForR8(parameters.getBackend());
for (int i = 0; i < 26 * 2; i++) {
jasminBuilder.addClass("TestClass" + Integer.toString(i));
}
@@ -96,7 +98,7 @@
}
private void test_withPackageHierarchy(String keepRule) throws Exception {
- R8FullTestBuilder builder = testForR8(backend);
+ R8FullTestBuilder builder = testForR8(parameters.getBackend());
JasminBuilder jasminBuilder = new JasminBuilder();
for (int i = 0; i < 26 * 2; i++) {
jasminBuilder.addClass("TopLevel" + Integer.toString(i));
@@ -120,7 +122,7 @@
assertThat(classSubject, isRenamed());
String renamedDescriptor = classSubject.getFinalDescriptor();
assertTrue(usedDescriptors.add(renamedDescriptor));
- assertNotEquals("R", getSimpleClassNameFromDescriptor(renamedDescriptor));
+ assertNotEquals("R", getUnqualifiedClassNameFromDescriptor(renamedDescriptor));
});
});
}
diff --git a/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking1Test.java b/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking1Test.java
index 044d21d..6189f73 100644
--- a/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking1Test.java
+++ b/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking1Test.java
@@ -170,7 +170,7 @@
String descriptor = clazz.getFinalDescriptor();
Assert.assertTrue(
descriptor,
- DescriptorUtils.getSimpleClassNameFromDescriptor(descriptor).equals("Shaking")
+ DescriptorUtils.getUnqualifiedClassNameFromDescriptor(descriptor).equals("Shaking")
|| DescriptorUtils.getPackageNameFromDescriptor(descriptor).equals("repackaged"));
});
}
diff --git a/src/test/java/com/android/tools/r8/utils/DescriptorUtilsTest.java b/src/test/java/com/android/tools/r8/utils/DescriptorUtilsTest.java
index 7ad9163..badc5c4 100644
--- a/src/test/java/com/android/tools/r8/utils/DescriptorUtilsTest.java
+++ b/src/test/java/com/android/tools/r8/utils/DescriptorUtilsTest.java
@@ -7,15 +7,13 @@
import static org.junit.Assert.assertEquals;
import java.io.File;
-import java.io.IOException;
-import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.Test;
public class DescriptorUtilsTest {
@Test
- public void toShorty() throws IOException {
+ public void toShorty() {
assertEquals("Z", DescriptorUtils.javaTypeToShorty("boolean"));
assertEquals("B", DescriptorUtils.javaTypeToShorty("byte"));
assertEquals("S", DescriptorUtils.javaTypeToShorty("short"));
@@ -31,7 +29,7 @@
}
@Test
- public void toDescriptor() throws IOException {
+ public void toDescriptor() {
assertEquals("Z", DescriptorUtils.javaTypeToDescriptor("boolean"));
assertEquals("B", DescriptorUtils.javaTypeToDescriptor("byte"));
assertEquals("S", DescriptorUtils.javaTypeToDescriptor("short"));
@@ -47,16 +45,16 @@
}
@Test
- public void fromDescriptor() throws IOException {
+ public void fromDescriptor() {
String obj = "Ljava/lang/Object;";
- assertEquals("Object", DescriptorUtils.getSimpleClassNameFromDescriptor(obj));
+ assertEquals("Object", DescriptorUtils.getUnqualifiedClassNameFromDescriptor(obj));
assertEquals("java.lang.Object", DescriptorUtils.getClassNameFromDescriptor(obj));
assertEquals("java.lang", DescriptorUtils.getPackageNameFromDescriptor(obj));
assertEquals("java/lang/Object", DescriptorUtils.getClassBinaryNameFromDescriptor(obj));
}
@Test
- public void toJavaType() throws IOException {
+ public void toJavaType() {
assertEquals("boolean", DescriptorUtils.descriptorToJavaType("Z"));
assertEquals("byte", DescriptorUtils.descriptorToJavaType("B"));
assertEquals("short", DescriptorUtils.descriptorToJavaType("S"));