Revise renaming of the name and Jvm*Signature in Kotlin property. Bug: 70169921 Change-Id: I91456bcb89ce329719654ae1bfb6cdfcfb5937aa
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java index 4935c24..6e959b6 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
@@ -329,18 +329,26 @@ KmType kmPropertyType = null; KmType kmReceiverType = null; + // A flag to indicate we can rename the property name. This will become false if any member + // is pinned. Then, we conservatively assume that users want the property to be pinned too. + // That is, we won't rename the property even though some other members could be renamed. + boolean canChangePropertyName = true; + // A candidate property name. Not overwritten by the following members, hence the order of + // preference: a backing field, getter, and setter. + String renamedPropertyName = name; if (field != null) { - DexField renamedField = lens.lookupField(field.field, appView.dexItemFactory()); - if (renamedField == null) { - // Bail out if we can't find a renamed backing field. - return null; + if (appView.appInfo().isPinned(field.field)) { + canChangePropertyName = false; } - kmProperty.setName(renamedField.name.toString()); + DexField renamedField = lens.lookupField(field.field, appView.dexItemFactory()); + if (canChangePropertyName && renamedField.name != field.field.name) { + renamedPropertyName = renamedField.name.toString(); + } kmPropertyType = toRenamedKmType(field.field.type, appView, lens); if (kmPropertyType != null) { kmProperty.setReturnType(kmPropertyType); } - JvmExtensionsKt.setFieldSignature(kmProperty, toJvmFieldSignature(field.field)); + JvmExtensionsKt.setFieldSignature(kmProperty, toJvmFieldSignature(renamedField)); } GetterSetterCriteria criteria = checkGetterCriteria(); @@ -374,8 +382,17 @@ return null; } } + if (appView.appInfo().isPinned(getter.method)) { + canChangePropertyName = false; + } + DexMethod renamedGetter = lens.lookupMethod(getter.method, appView.dexItemFactory()); + if (canChangePropertyName + && renamedGetter.name != getter.method.name + && renamedPropertyName.equals(name)) { + renamedPropertyName = renamedGetter.name.toString(); + } kmProperty.setGetterFlags(getter.accessFlags.getAsKotlinFlags()); - JvmExtensionsKt.setGetterSignature(kmProperty, toJvmMethodSignature(getter.method)); + JvmExtensionsKt.setGetterSignature(kmProperty, toJvmMethodSignature(renamedGetter)); } criteria = checkSetterCriteria(); @@ -430,8 +447,17 @@ if (kmValueParameter != null) { kmProperty.setSetterParameter(kmValueParameter); } + if (appView.appInfo().isPinned(setter.method)) { + canChangePropertyName = false; + } + DexMethod renamedSetter = lens.lookupMethod(setter.method, appView.dexItemFactory()); + if (canChangePropertyName + && renamedSetter.name != setter.method.name + && renamedPropertyName.equals(name)) { + renamedPropertyName = renamedSetter.name.toString(); + } kmProperty.setSetterFlags(setter.accessFlags.getAsKotlinFlags()); - JvmExtensionsKt.setSetterSignature(kmProperty, toJvmMethodSignature(setter.method)); + JvmExtensionsKt.setSetterSignature(kmProperty, toJvmMethodSignature(renamedSetter)); } // If the property type remains null at the end, bail out to synthesize this property. @@ -442,6 +468,11 @@ if (isExtension && kmReceiverType == null) { return null; } + // Rename the property name if and only if none of participating members is pinned, and + // any of them is indeed renamed (to a new name). + if (canChangePropertyName && !renamedPropertyName.equals(name)) { + kmProperty.setName(renamedPropertyName); + } return kmProperty; }
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java index 16385b4..f77cdb9 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
@@ -94,6 +94,8 @@ .addProgramFiles(companionLibJarMap.get(targetVersion)) // Keep the B class and its interface (which has the doStuff method). .addKeepRules("-keep class **.B") + // Property in companion with @JvmField is defined in the host class, without accessors. + .addKeepRules("-keepclassmembers class **.B { *** elt2; }") .addKeepRules("-keep class **.I { <methods>; }") // Keep getters for B$Companion.(eltN|foo) which will be referenced at the app. .addKeepRules("-keepclassmembers class **.B$* { *** get*(...); }")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java index d8b230d..34abe12 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
@@ -9,6 +9,8 @@ import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -18,8 +20,10 @@ import com.android.tools.r8.shaking.ProguardKeepAttributes; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; +import com.android.tools.r8.utils.codeinspector.FieldSubject; import com.android.tools.r8.utils.codeinspector.KmClassSubject; import com.android.tools.r8.utils.codeinspector.KmPropertySubject; +import com.android.tools.r8.utils.codeinspector.MethodSubject; import java.nio.file.Path; import java.util.Collection; import java.util.HashMap; @@ -85,7 +89,7 @@ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar) .addClasspath(output) .run(parameters.getRuntime(), PKG + ".fragile_property_only_getter.Getter_userKt") - .assertSuccessWithOutputLines("true", "false", "Hey"); + .assertSuccessWithOutputLines("true", "false", "Hey Jude"); } private void inspectGetterOnly(CodeInspector inspector) { @@ -94,6 +98,14 @@ assertThat(person, isPresent()); assertThat(person, not(isRenamed())); + FieldSubject backingField = person.uniqueFieldWithName("name"); + assertThat(backingField, isRenamed()); + MethodSubject getterForName = person.uniqueMethodWithName("getName"); + assertThat(getterForName, isPresent()); + assertThat(getterForName, not(isRenamed())); + MethodSubject setterForName = person.uniqueMethodWithName("setName"); + assertThat(setterForName, not(isPresent())); + // API entry is kept, hence the presence of Metadata. KmClassSubject kmClass = person.getKmClass(); assertThat(kmClass, isPresent()); @@ -101,8 +113,12 @@ KmPropertySubject name = kmClass.kmPropertyWithUniqueName("name"); assertThat(name, isPresent()); assertThat(name, not(isExtensionProperty())); + // Property name is not renamed, due to the kept getter. + assertEquals("name", name.name()); assertNotNull(name.fieldSignature()); + assertEquals(backingField.getJvmFieldSignatureAsString(), name.fieldSignature().asString()); assertNotNull(name.getterSignature()); + assertEquals(getterForName.getJvmMethodSignatureAsString(), name.getterSignature().asString()); assertNull(name.setterSignature()); KmPropertySubject familyName = kmClass.kmPropertyWithUniqueName("familyName"); @@ -159,6 +175,7 @@ ClassSubject person = inspector.clazz(personClassName); assertThat(person, isPresent()); assertThat(person, not(isRenamed())); + // API entry is kept, hence the presence of Metadata. KmClassSubject kmClass = person.getKmClass(); assertThat(kmClass, isPresent());
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/fragile_property_only_getter/getter_user.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/fragile_property_only_getter/getter_user.kt index b85bd2e..b3aba2e 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/fragile_property_only_getter/getter_user.kt +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/fragile_property_only_getter/getter_user.kt
@@ -11,5 +11,5 @@ println(x.canDrink) println(x.married) - println(y.firstName) + println(y.name) } \ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentFieldSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentFieldSubject.java index 20da5d0..f41135f 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentFieldSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentFieldSubject.java
@@ -95,4 +95,9 @@ public AnnotationSubject annotation(String name) { return new AbsentAnnotationSubject(); } + + @Override + public String getJvmFieldSignatureAsString() { + return null; + } }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmPropertySubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmPropertySubject.java index 70f6e52..d9c7d55 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmPropertySubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmPropertySubject.java
@@ -29,6 +29,11 @@ } @Override + public String name() { + return null; + } + + @Override public JvmFieldSignature fieldSignature() { return null; }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java index b3e5eec..e08c9b7 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
@@ -132,4 +132,9 @@ public AnnotationSubject annotation(String name) { return new AbsentAnnotationSubject(); } + + @Override + public String getJvmMethodSignatureAsString() { + return null; + } }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FieldSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FieldSubject.java index dc9940f..957e78a 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/FieldSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FieldSubject.java
@@ -34,4 +34,6 @@ public boolean isFieldSubject() { return true; } + + public abstract String getJvmFieldSignatureAsString(); }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java index 7c40d1e..6494955 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java
@@ -154,4 +154,9 @@ public String toString() { return dexField.toSourceString(); } + + @Override + public String getJvmFieldSignatureAsString() { + return dexField.field.name.toString() + ":" + dexField.field.type.toDescriptorString(); + } }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmPropertySubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmPropertySubject.java index 4f9cc94..3cfe20d 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmPropertySubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmPropertySubject.java
@@ -49,6 +49,11 @@ } @Override + public String name() { + return kmProperty.getName(); + } + + @Override public JvmFieldSignature fieldSignature() { return fieldSignature; }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java index 1051e28..c220f01 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -24,6 +24,7 @@ import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexString; +import com.android.tools.r8.graph.DexType; import com.android.tools.r8.ir.code.IRCode; import com.android.tools.r8.naming.MemberNaming; import com.android.tools.r8.naming.MemberNaming.MethodSignature; @@ -32,9 +33,11 @@ import com.android.tools.r8.references.MethodReference; import com.android.tools.r8.references.Reference; import com.android.tools.r8.utils.InternalOptions; +import com.android.tools.r8.utils.StringUtils; import com.android.tools.r8.utils.codeinspector.LocalVariableTable.LocalVariableTableEntry; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Streams; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import java.util.Arrays; @@ -356,4 +359,15 @@ .collect(Collectors.toList()), Reference.returnTypeFromDescriptor(method.proto.returnType.toDescriptorString())); } + + @Override + public String getJvmMethodSignatureAsString() { + return dexMethod.method.name.toString() + + "(" + + StringUtils.join( + Arrays.stream(dexMethod.method.proto.parameters.values) + .map(DexType::toDescriptorString).collect(Collectors.toList()), "") + + ")" + + dexMethod.method.proto.returnType.toDescriptorString(); + } }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KmPropertySubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmPropertySubject.java index 9fb5a0a..826c1f1 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/KmPropertySubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmPropertySubject.java
@@ -15,6 +15,8 @@ public abstract boolean isExtension(); + public abstract String name(); + public abstract JvmFieldSignature fieldSignature(); public abstract JvmMethodSignature getterSignature();
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java index af6e1a4..50911f3 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -104,4 +104,6 @@ public boolean hasCode() { return getMethod().getCode() != null; } + + public abstract String getJvmMethodSignatureAsString(); }