Fix R8 support for Kotlin property syntheticMethodForDelegate

This CL adds full support for Kotlin property delegated methods
(`syntheticMethodForDelegate`) inside the R8 compiler's property model.

R8 was previously missing the tracking and parsing of delegated methods
in `KmPropertyProcessor`. Consequently, R8's tree shaker pruned these
synthetic delegate methods under minification and ignored updating their
signatures in the rewritten Kotlin metadata. This caused a metadata
resolution failure in `kotlin-reflect` >= 2.3.20 when using map delegation,
manifesting as a NullPointerException or KotlinReflectionInternalError at runtime.

Bug: b/510830974
Change-Id: I43efc3c98e964febf73d5fd774ce8c828ecc942e
diff --git a/src/main/java/com/android/tools/r8/kotlin/ConcreteKotlinPropertyInfo.java b/src/main/java/com/android/tools/r8/kotlin/ConcreteKotlinPropertyInfo.java
index 8816001..78a6900 100644
--- a/src/main/java/com/android/tools/r8/kotlin/ConcreteKotlinPropertyInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/ConcreteKotlinPropertyInfo.java
@@ -113,7 +113,7 @@
 
   @Override
   public boolean rewriteNoBacking(Consumer<KmProperty> consumer, AppView<?> appView) {
-    return rewrite(consumer, null, null, null, null, appView);
+    return rewrite(consumer, null, null, null, null, null, appView);
   }
 
   @Override
@@ -123,6 +123,7 @@
       DexEncodedMethod getter,
       DexEncodedMethod setter,
       DexEncodedMethod syntheticMethodForAnnotationsMethod,
+      DexEncodedMethod syntheticMethodForDelegateMethod,
       AppView<?> appView) {
     KmProperty rewrittenKmProperty = new KmProperty(kmProperty.getName());
     consumer.accept(rewrittenKmProperty);
@@ -190,13 +191,14 @@
               syntheticMethodForAnnotationsMethod,
               appView);
     }
-    rewritten |=
-        rewriteIfNotNull(
-            appView,
-            syntheticMethodForDelegate,
-            newMethod ->
-                JvmExtensionsKt.setSyntheticMethodForDelegate(rewrittenKmProperty, newMethod),
-            KotlinJvmMethodSignatureInfo::rewriteNoBacking);
+    if (syntheticMethodForDelegate != null) {
+      rewritten |=
+          syntheticMethodForDelegate.rewrite(
+              newSignature ->
+                  JvmExtensionsKt.setSyntheticMethodForDelegate(rewrittenKmProperty, newSignature),
+              syntheticMethodForDelegateMethod,
+              appView);
+    }
     return rewritten;
   }
 
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
index 58eb8ed..b1b9e4c 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
@@ -144,6 +144,19 @@
           originalAssignmentTracker.add(method.getReference());
         }
       }
+      if (propertyProcessor.syntheticMethodForDelegateSignature() != null) {
+        DexEncodedMethod method =
+            methodSignatureMap.get(
+                propertyProcessor.syntheticMethodForDelegateSignature().toString());
+        if (method != null) {
+          hasBacking = true;
+          memberInfoConsumer.accept(
+              method,
+              new KotlinPropertyInfoDelegate(
+                  kotlinPropertyInfo, PropertyType.SYNTHETIC_METHOD_FOR_DELEGATE));
+          originalAssignmentTracker.add(method.getReference());
+        }
+      }
       if (!hasBacking) {
         notBackedProperties.add(kotlinPropertyInfo);
       }
@@ -256,6 +269,9 @@
         case SYNTHETIC_METHOD_FOR_ANNOTATIONS:
           kotlinPropertyGroup.setSyntheticMethodForAnnotations(method);
           break;
+        case SYNTHETIC_METHOD_FOR_DELEGATE:
+          kotlinPropertyGroup.setSyntheticMethodForDelegate(method);
+          break;
         default:
           // Do nothing.
       }
@@ -269,6 +285,7 @@
               kotlinPropertyGroup.getter,
               kotlinPropertyGroup.setter,
               kotlinPropertyGroup.syntheticMethodForAnnotations,
+              kotlinPropertyGroup.syntheticMethodForDelegate,
               appView);
     }
     // Add all not backed functions and properties.
@@ -300,6 +317,7 @@
     private DexEncodedMethod setter = null;
     private DexEncodedMethod getter = null;
     private DexEncodedMethod syntheticMethodForAnnotations = null;
+    private DexEncodedMethod syntheticMethodForDelegate = null;
 
     void setBackingField(DexEncodedField backingField) {
       assert this.backingField == null;
@@ -320,5 +338,10 @@
       assert this.syntheticMethodForAnnotations == null;
       this.syntheticMethodForAnnotations = syntheticMethodForAnnotations;
     }
+
+    public void setSyntheticMethodForDelegate(DexEncodedMethod syntheticMethodForDelegate) {
+      assert this.syntheticMethodForDelegate == null;
+      this.syntheticMethodForDelegate = syntheticMethodForDelegate;
+    }
   }
 }
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 8415811..237bd47 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
@@ -135,6 +135,7 @@
     // Custom getter via @set:JvmName("..."). Otherwise, null.
     private final JvmMethodSignature setterSignature;
     private final JvmMethodSignature syntheticMethodForAnnotationsSignature;
+    private final JvmMethodSignature syntheticMethodForDelegateSignature;
 
     KmPropertyProcessor(KmProperty kmProperty) {
       fieldSignature = JvmExtensionsKt.getFieldSignature(kmProperty);
@@ -142,6 +143,8 @@
       setterSignature = JvmExtensionsKt.getSetterSignature(kmProperty);
       syntheticMethodForAnnotationsSignature =
           JvmExtensionsKt.getSyntheticMethodForAnnotations(kmProperty);
+      syntheticMethodForDelegateSignature =
+          JvmExtensionsKt.getSyntheticMethodForDelegate(kmProperty);
     }
 
     JvmFieldSignature fieldSignature() {
@@ -159,6 +162,10 @@
     public JvmMethodSignature syntheticMethodForAnnotationsSignature() {
       return syntheticMethodForAnnotationsSignature;
     }
+
+    public JvmMethodSignature syntheticMethodForDelegateSignature() {
+      return syntheticMethodForDelegateSignature;
+    }
   }
 
   static boolean isValidMethodDescriptor(String methodDescriptor) {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
index 237a877..9fa8a28 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
@@ -535,7 +535,7 @@
               sb,
               Objects.toString(syntheticMethodForAnnotations));
           JvmMethodSignature syntheticMethodForDelegate =
-              JvmExtensionsKt.getSyntheticMethodForAnnotations(kmProperty);
+              JvmExtensionsKt.getSyntheticMethodForDelegate(kmProperty);
           appendKeyValue(
               newIndent,
               "syntheticMethodForDelegate",
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java
index 1e66fbd..f933324 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java
@@ -45,5 +45,6 @@
       DexEncodedMethod getter,
       DexEncodedMethod setter,
       DexEncodedMethod syntheticMethodForAnnotationsMethod,
+      DexEncodedMethod syntheticMethodForDelegateMethod,
       AppView<?> appView);
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfoDelegate.java b/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfoDelegate.java
index fc11196..5b690d8 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfoDelegate.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfoDelegate.java
@@ -34,6 +34,7 @@
     SETTER,
     GETTER,
     SYNTHETIC_METHOD_FOR_ANNOTATIONS,
+    SYNTHETIC_METHOD_FOR_DELEGATE,
     UNKNOWN
   }
 
@@ -64,9 +65,16 @@
       DexEncodedMethod getter,
       DexEncodedMethod setter,
       DexEncodedMethod syntheticMethodForAnnotationsMethod,
+      DexEncodedMethod syntheticMethodForDelegateMethod,
       AppView<?> appView) {
     return delegate.rewrite(
-        consumer, field, getter, setter, syntheticMethodForAnnotationsMethod, appView);
+        consumer,
+        field,
+        getter,
+        setter,
+        syntheticMethodForAnnotationsMethod,
+        syntheticMethodForDelegateMethod,
+        appView);
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
index 1e96f35..a1eb94b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
@@ -15,7 +15,6 @@
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.kotlin.KotlinMetadataWriter;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -23,6 +22,10 @@
 import com.android.tools.r8.utils.internal.StringUtils;
 import java.nio.file.Path;
 import java.util.Collection;
+import kotlin.metadata.KmClass;
+import kotlin.metadata.KmProperty;
+import kotlin.metadata.jvm.JvmExtensionsKt;
+import kotlin.metadata.jvm.JvmMethodSignature;
 import kotlin.metadata.jvm.KotlinClassMetadata;
 import org.junit.Assert;
 import org.junit.Test;
@@ -147,7 +150,18 @@
     assertThat(clazz, isPresent());
     KotlinClassMetadata kotlinClassMetadata = clazz.getKotlinClassMetadata();
     Assert.assertNotNull(kotlinClassMetadata);
-    String metadataAsString = KotlinMetadataWriter.kotlinMetadataToString("", kotlinClassMetadata);
-    assertThat(metadataAsString, containsString("syntheticMethodForDelegate:"));
+    Assert.assertTrue(kotlinClassMetadata instanceof KotlinClassMetadata.Class);
+    KmClass kmClass = ((KotlinClassMetadata.Class) kotlinClassMetadata).getKmClass();
+    KmProperty property =
+        kmClass.getProperties().stream()
+            .filter(p -> p.getName().equals("oldName"))
+            .findFirst()
+            .orElse(null);
+    Assert.assertNotNull(property);
+    JvmMethodSignature delegateSignature = JvmExtensionsKt.getSyntheticMethodForDelegate(property);
+    Assert.assertNotNull(delegateSignature);
+    Assert.assertEquals(
+        "getOldName$delegate(Lcom/android/tools/r8/kotlin/metadata/delegated_property_lib/MyDelegatedProperty;)Ljava/lang/Object;",
+        delegateSignature.toString());
   }
 }