Check for inner class attribute before writing kotlin class name
Bug: 188690067
Change-Id: I5affa3cff124a800934177e39632076e1b853c6c
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
index e440049..5b10234 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.Reporter;
@@ -221,14 +222,24 @@
// Set potentially renamed class name.
DexString originalDescriptor = clazz.type.descriptor;
DexString rewrittenDescriptor = namingLens.lookupDescriptor(clazz.type);
- // If the original descriptor equals the rewritten descriptor, we pick the original name
- // to preserve potential errors in the original name. As an example, the kotlin stdlib has
- // name: .kotlin/collections/CollectionsKt___CollectionsKt$groupingBy$1, which seems incorrect.
- boolean rewritten = !originalDescriptor.equals(rewrittenDescriptor);
- kmClass.setName(
- !rewritten
- ? this.name
- : DescriptorUtils.getBinaryNameFromDescriptor(rewrittenDescriptor.toString()));
+ String rewrittenName = null;
+ // When the class has an anonymousObjectOrigin and the name equals the identifier there, we
+ // keep the name tied to the anonymousObjectOrigin.
+ if (anonymousObjectOrigin != null
+ && name.equals(anonymousObjectOrigin.toKotlinClassifier(true))) {
+ Box<String> rewrittenOrigin = new Box<>();
+ anonymousObjectOrigin.toRenamedBinaryNameOrDefault(
+ rewrittenOrigin::set, appView, namingLens, null);
+ if (rewrittenOrigin.isSet()) {
+ rewrittenName = "." + rewrittenOrigin.get();
+ }
+ }
+ if (rewrittenName == null) {
+ rewrittenName = KotlinMetadataUtils.getKotlinClassName(clazz, rewrittenDescriptor.toString());
+ }
+ kmClass.setName(rewrittenName);
+ boolean rewritten =
+ !originalDescriptor.equals(rewrittenDescriptor) || !name.equals(rewrittenName);
// Find a companion object.
for (DexEncodedField field : clazz.fields()) {
if (field.getKotlinInfo().isCompanion()) {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
index 5f5b696..9b2939e 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getKotlinLocalOrAnonymousNameFromDescriptor;
+
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexItemFactory;
@@ -68,13 +70,8 @@
boolean rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens) {
return type.toRenamedDescriptorOrDefault(
descriptor -> {
- // For local or anonymous classes, the classifier is prefixed with '.' and inner classes
- // are separated with '$'.
- if (isLocalOrAnonymous) {
- visitor.visitClass("." + DescriptorUtils.getBinaryNameFromDescriptor(descriptor));
- } else {
- visitor.visitClass(DescriptorUtils.descriptorToKotlinClassifier(descriptor));
- }
+ visitor.visitClass(
+ getKotlinLocalOrAnonymousNameFromDescriptor(descriptor, isLocalOrAnonymous));
},
appView,
namingLens,
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
index 7eb45f6..2d6f39a 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.ProguardConfiguration;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
@@ -201,4 +202,27 @@
// Check if the type is matched
return proguardKeepRule.getClassNames().matches(factory.kotlinMetadataType);
}
+
+ static String getKotlinClassName(DexClass clazz, String descriptor) {
+ InnerClassAttribute innerClassAttribute = clazz.getInnerClassAttributeForThisClass();
+ if (innerClassAttribute != null && innerClassAttribute.getOuter() != null) {
+ return DescriptorUtils.descriptorToKotlinClassifier(descriptor);
+ } else if (clazz.isLocalClass() || clazz.isAnonymousClass()) {
+ return getKotlinLocalOrAnonymousNameFromDescriptor(descriptor, true);
+ } else {
+ // We no longer have an innerclass relationship to maintain and we therefore return a binary
+ // name.
+ return DescriptorUtils.getBinaryNameFromDescriptor(descriptor);
+ }
+ }
+
+ static String getKotlinLocalOrAnonymousNameFromDescriptor(
+ String descriptor, boolean isLocalOrAnonymous) {
+ // For local or anonymous classes, the classifier is prefixed with '.' and inner classes
+ // are separated with '$'.
+ if (isLocalOrAnonymous) {
+ return "." + DescriptorUtils.getBinaryNameFromDescriptor(descriptor);
+ }
+ return DescriptorUtils.descriptorToKotlinClassifier(descriptor);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
index 4d0d990..c166103 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getKotlinLocalOrAnonymousNameFromDescriptor;
+
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexItemFactory;
@@ -81,6 +83,14 @@
return !known.toDescriptorString().equals(renamedString);
}
+ String toKotlinClassifier(boolean isLocalOrAnonymous) {
+ if (known == null) {
+ return unknown;
+ }
+ return getKotlinLocalOrAnonymousNameFromDescriptor(
+ known.toDescriptorString(), isLocalOrAnonymous);
+ }
+
boolean toRenamedBinaryNameOrDefault(
Consumer<String> rewrittenConsumer,
AppView<?> appView,
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInnerClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInnerClassTest.java
index c38a3d7..48007f1 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInnerClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInnerClassTest.java
@@ -26,17 +26,19 @@
@RunWith(Parameterized.class)
public class MetadataRewriteInnerClassTest extends KotlinMetadataTestBase {
+ private static final String PKG_NESTED_REFLECT = PKG + ".nested_reflect";
private static final String EXPECTED =
StringUtils.lines(
- "fun <init>(kotlin.Int):"
- + " com.android.tools.r8.kotlin.metadata.nested_reflect.Outer.Nested",
- "fun com.android.tools.r8.kotlin.metadata.nested_reflect.Outer.Inner.<init>(kotlin.Int):"
- + " com.android.tools.r8.kotlin.metadata.nested_reflect.Outer.Inner");
+ "fun <init>(kotlin.Int): " + PKG_NESTED_REFLECT + ".Outer.Nested",
+ "fun "
+ + PKG_NESTED_REFLECT
+ + ".Outer.Inner.<init>(kotlin.Int): "
+ + PKG_NESTED_REFLECT
+ + ".Outer.Inner");
private static final String EXPECTED_OUTER_RENAMED =
StringUtils.lines(
- "fun <init>(kotlin.Int): com.android.tools.r8.kotlin.metadata.nested_reflect.Nested",
- "fun <init>(kotlin.Int): com.android.tools.r8.kotlin.metadata.nested_reflect.Inner");
- private static final String PKG_NESTED_REFLECT = PKG + ".nested_reflect";
+ "fun <init>(kotlin.Int): " + PKG_NESTED_REFLECT + ".`Outer$Nested`",
+ "fun <init>(kotlin.Int): " + PKG_NESTED_REFLECT + ".`Outer$Inner`");
private final TestParameters parameters;
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
index 605b16c..2c378c6 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
@@ -93,7 +93,10 @@
.addProgramFiles(kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
.addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
.addKeepAllClassesRule()
- .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+ .addKeepAttributes(
+ ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS,
+ ProguardKeepAttributes.INNER_CLASSES,
+ ProguardKeepAttributes.ENCLOSING_METHOD)
.compile()
.inspect(this::inspect)
.writeToZip();
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
index 80578a3..44092e7 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
@@ -77,7 +77,10 @@
.setMinApi(parameters.getApiLevel())
.addKeepAllClassesRule()
.addKeepKotlinMetadata()
- .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+ .addKeepAttributes(
+ ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS,
+ ProguardKeepAttributes.INNER_CLASSES,
+ ProguardKeepAttributes.ENCLOSING_METHOD)
.allowDiagnosticWarningMessages()
.compile()
.assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))