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();
}