Add test and fix for kotlin property with type-parameter

Bug: 153050655
Bug: 152715309
Change-Id: I74ef5bbc1b83da7d88c52845682792683f691833
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
new file mode 100644
index 0000000..c7c3701
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
@@ -0,0 +1,49 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.kotlin;
+
+import kotlinx.metadata.KmClassifier;
+
+// Provides access to information about a kotlin classifier
+public class KotlinClassifierInfo {
+
+  private static boolean isClass(KmClassifier classifier) {
+    return classifier instanceof KmClassifier.Class;
+  }
+
+  private static KmClassifier.Class getClassClassifier(KmClassifier classifier) {
+    return (KmClassifier.Class) classifier;
+  }
+
+  private static boolean isTypeAlias(KmClassifier classifier) {
+    return classifier instanceof KmClassifier.TypeAlias;
+  }
+
+  private static KmClassifier.TypeAlias getTypeAlias(KmClassifier classifier) {
+    return (KmClassifier.TypeAlias) classifier;
+  }
+
+  private static boolean isTypeParameter(KmClassifier classifier) {
+    return classifier instanceof KmClassifier.TypeParameter;
+  }
+
+  private static KmClassifier.TypeParameter getTypeParameter(KmClassifier classifier) {
+    return (KmClassifier.TypeParameter) classifier;
+  }
+
+  public static boolean equals(KmClassifier one, KmClassifier other) {
+    if (isClass(one)) {
+      return isClass(other)
+          && getClassClassifier(one).getName().equals(getClassClassifier(other).getName());
+    }
+    if (isTypeAlias(one)) {
+      return isTypeAlias(other)
+          && getTypeAlias(one).getName().equals(getTypeAlias(other).getName());
+    }
+    assert isTypeParameter(one);
+    return isTypeParameter(other)
+        && getTypeParameter(one).getId() == getTypeParameter(other).getId();
+  }
+}
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 65d7f7e..bed05c0 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
@@ -10,7 +10,6 @@
 import static com.android.tools.r8.kotlin.KotlinMetadataSynthesizerUtils.toClassifier;
 import static com.android.tools.r8.utils.DescriptorUtils.descriptorToKotlinClassifier;
 import static com.android.tools.r8.utils.DescriptorUtils.getBinaryNameFromDescriptor;
-import static com.android.tools.r8.utils.DescriptorUtils.getDescriptorFromKmType;
 import static kotlinx.metadata.Flag.Property.IS_VAR;
 import static kotlinx.metadata.FlagsKt.flagsOf;
 
@@ -599,8 +598,8 @@
           synthesizer.toRenamedKmType(receiverType, receiverSignature, null, typeParameters);
       if (kmProperty.getReceiverParameterType() != null) {
         // If the receiver type for the extension property is set already make sure it's consistent.
-        return getDescriptorFromKmType(kmReceiverType)
-            .equals(getDescriptorFromKmType(kmProperty.getReceiverParameterType()));
+        return KotlinMetadataSynthesizerUtils.hasEqualClassifier(
+            kmReceiverType, kmProperty.getReceiverParameterType());
       }
       kmProperty.setReceiverParameterType(kmReceiverType);
       return true;
@@ -644,8 +643,8 @@
       if (kmProperty.getReturnType() == defaultPropertyType) {
         // The property type is not set yet.
         kmProperty.setReturnType(kmPropertyType);
-      } else if (!getDescriptorFromKmType(kmPropertyType)
-          .equals(getDescriptorFromKmType(kmProperty.getReturnType()))) {
+      } else if (!KotlinMetadataSynthesizerUtils.hasEqualClassifier(
+          kmPropertyType, kmProperty.getReturnType())) {
         // If property type is set already (via backing field), make sure it's consistent.
         return null;
       }
@@ -700,8 +699,8 @@
         kmProperty.setReturnType(kmPropertyType);
       } else {
         // If property type is set already make sure it's consistent.
-        if (!getDescriptorFromKmType(kmPropertyType)
-            .equals(getDescriptorFromKmType(kmProperty.getReturnType()))) {
+        if (!KotlinMetadataSynthesizerUtils.hasEqualClassifier(
+            kmPropertyType, kmProperty.getReturnType())) {
           return null;
         }
       }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizerUtils.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizerUtils.java
index 3b04e91..e773cef 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizerUtils.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizerUtils.java
@@ -20,6 +20,7 @@
 import java.util.List;
 import java.util.function.Consumer;
 import java.util.function.Function;
+import kotlinx.metadata.KmType;
 import kotlinx.metadata.KmTypeParameter;
 import kotlinx.metadata.KmTypeVisitor;
 import kotlinx.metadata.KmVariance;
@@ -276,4 +277,14 @@
         factory,
         AddKotlinAnyType.DISREGARD);
   }
+
+  public static boolean hasEqualClassifier(KmType one, KmType other) {
+    if (one == null && other == null) {
+      return true;
+    }
+    if (one == null || other == null) {
+      return false;
+    }
+    return KotlinClassifierInfo.equals(one.classifier, other.classifier);
+  }
 }
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 6aca533..de25a3b 100644
--- a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
@@ -17,8 +17,6 @@
 import java.io.File;
 import java.nio.file.Path;
 import java.util.Map;
-import kotlinx.metadata.KmType;
-import kotlinx.metadata.KmTypeVisitor;
 
 public class DescriptorUtils {
 
@@ -379,36 +377,6 @@
   }
 
   /**
-   * Get a fully qualified name from a classifier in Kotlin metadata.
-   * @param kmType where classifier contains Kotlin internal name, like "org/foo/bar/Baz.Nested"
-   * @return a class descriptor like "Lorg/foo/bar/Baz$Nested;"
-   */
-  public static String getDescriptorFromKmType(KmType kmType) {
-    if (kmType == null) {
-      return null;
-    }
-    Box<String> descriptor = new Box<>(null);
-    kmType.accept(new KmTypeVisitor() {
-      @Override
-      public void visitClass(String name) {
-        // TODO(b/151195430): Remove this if metadata lib is resilient to namespace relocation.
-        //  See b/70169921#comment25 for more details.
-        assert descriptor.get() == null : descriptor.get();
-        descriptor.set(getDescriptorFromKotlinClassifier(backwardRelocatedName(name)));
-      }
-
-      @Override
-      public void visitTypeAlias(String name) {
-        // TODO(b/151195430): Remove this if metadata lib is resilient to namespace relocation.
-        //  See b/70169921#comment25 for more details.
-        assert descriptor.get() == null : descriptor.get();
-        descriptor.set(getDescriptorFromKotlinClassifier(backwardRelocatedName(name)));
-      }
-    });
-    return descriptor.get();
-  }
-
-  /**
    * Get unqualified class name from its binary name.
    *
    * @param classBinaryName a class binary name i.e. "java/lang/Object" or "a/b/C$Inner"
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
index 365bcb1..a158b99 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
@@ -74,7 +74,9 @@
           "3",
           "7",
           "9",
-          "42");
+          "42",
+          "42",
+          "7");
 
   private final TestParameters parameters;
 
@@ -131,6 +133,7 @@
             .addKeepRules("-keep,allowobfuscation class **ClassThatWillBeObfuscated")
             .addKeepRules("-keepclassmembers class **ClassThatWillBeObfuscated { *; }")
             // Keep all other classes.
+            .addKeepRules("-keep class **typeargument_lib.PlainBox { *; }")
             .addKeepRules("-keep class **typeargument_lib.SomeClass { *; }")
             .addKeepRules("-keep class **typeargument_lib.CoVariant { *; }")
             .addKeepRules("-keep class **typeargument_lib.ContraVariant { *; }")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/typeargument_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/typeargument_app/main.kt
index e94ab44..2129081 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/typeargument_app/main.kt
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/typeargument_app/main.kt
@@ -7,6 +7,7 @@
 import com.android.tools.r8.kotlin.metadata.typeargument_lib.CoVariant
 import com.android.tools.r8.kotlin.metadata.typeargument_lib.ContraVariant
 import com.android.tools.r8.kotlin.metadata.typeargument_lib.Invariant
+import com.android.tools.r8.kotlin.metadata.typeargument_lib.PlainBox
 import com.android.tools.r8.kotlin.metadata.typeargument_lib.SomeClass
 import com.android.tools.r8.kotlin.metadata.typeargument_lib.asList
 import com.android.tools.r8.kotlin.metadata.typeargument_lib.asListWithVarargs
@@ -60,9 +61,17 @@
   println(CoVariant(42).asStar().t)
 }
 
+fun testPlainBox() {
+  var plainBox = PlainBox(42)
+  println(plainBox.plainBox)
+  plainBox.plainBox = 7
+  println(plainBox.plainBox)
+}
+
 fun main() {
   testInvariant()
   testCoVariant()
   testContraVariant();
   testExtension()
+  testPlainBox()
 }
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/typeargument_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/typeargument_lib/lib.kt
index 85af523..d9d3bea 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/typeargument_lib/lib.kt
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/typeargument_lib/lib.kt
@@ -6,6 +6,8 @@
 
 open class SomeClass
 
+class PlainBox<T>(var plainBox : T)
+
 class ClassThatWillBeObfuscated(val x : Int)
 
 class Invariant<T, C> {