Merge "Remove JvmDescriptorUtils's dependency of Types util." into androidx-master-dev
diff --git a/room/compiler/src/main/kotlin/androidx/room/kotlin/JvmDescriptorUtils.kt b/room/compiler/src/main/kotlin/androidx/room/kotlin/JvmDescriptorUtils.kt
index 1020aa2..7757f79 100644
--- a/room/compiler/src/main/kotlin/androidx/room/kotlin/JvmDescriptorUtils.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/kotlin/JvmDescriptorUtils.kt
@@ -21,27 +21,35 @@
import javax.lang.model.element.NestingKind
import javax.lang.model.element.QualifiedNameable
import javax.lang.model.element.TypeElement
+import javax.lang.model.element.VariableElement
import javax.lang.model.type.ArrayType
import javax.lang.model.type.DeclaredType
import javax.lang.model.type.ErrorType
import javax.lang.model.type.ExecutableType
+import javax.lang.model.type.IntersectionType
import javax.lang.model.type.NoType
import javax.lang.model.type.NullType
import javax.lang.model.type.PrimitiveType
import javax.lang.model.type.TypeKind
import javax.lang.model.type.TypeMirror
import javax.lang.model.type.TypeVariable
+import javax.lang.model.type.UnionType
import javax.lang.model.type.WildcardType
-import javax.lang.model.util.AbstractTypeVisitor6
-import javax.lang.model.util.Types
+import javax.lang.model.util.AbstractTypeVisitor8
+
+/**
+ * Returns the method descriptor of this [ExecutableElement].
+ *
+ * For reference, see the [JVM specification, section 4.3.2](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.2)
+ */
+fun VariableElement.descriptor() = "$simpleName:${asType().descriptor()}"
/**
* Returns the method descriptor of this [ExecutableElement].
*
* For reference, see the [JVM specification, section 4.3.3](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3)
*/
-fun ExecutableElement.descriptor(typeUtils: Types) =
- "$simpleName${asType().descriptor(typeUtils)}"
+fun ExecutableElement.descriptor() = "$simpleName${asType().descriptor()}"
/**
* Returns the name of this [TypeElement] in its "internal form".
@@ -84,22 +92,25 @@
else -> error("Unknown primitive type $this")
}
-fun TypeMirror.descriptor(typeUtils: Types): String =
- accept(JvmDescriptorTypeVisitor, typeUtils)
+fun TypeMirror.descriptor(): String = accept(JvmDescriptorTypeVisitor, Unit)
-internal fun WildcardType.descriptor(typeUtils: Types): String =
- typeUtils.erasure(this).descriptor(typeUtils)
+internal fun WildcardType.descriptor(): String = ""
-internal fun TypeVariable.descriptor(typeUtils: Types): String =
- typeUtils.erasure(this).descriptor(typeUtils)
+// The erasure of a type variable is the erasure of its leftmost bound. - JVM Spec Sec 4.6
+internal fun TypeVariable.descriptor(): String = this.upperBound.descriptor()
-internal fun ArrayType.descriptor(typeUtils: Types): String =
- "[" + componentType.descriptor(typeUtils)
+// For a type variable with multiple bounds: "the erasure of a type variable is determined by
+// the first type in its bound" - JVM Spec Sec 4.4
+internal fun IntersectionType.descriptor(): String =
+ this.bounds[0].descriptor()
-internal fun ExecutableType.descriptor(typeUtils: Types): String {
+internal fun ArrayType.descriptor(): String =
+ "[" + componentType.descriptor()
+
+internal fun ExecutableType.descriptor(): String {
val parameterDescriptors =
- parameterTypes.joinToString(separator = "") { it.descriptor(typeUtils) }
- val returnDescriptor = returnType.descriptor(typeUtils)
+ parameterTypes.joinToString(separator = "") { it.descriptor() }
+ val returnDescriptor = returnType.descriptor()
return "($parameterDescriptors)$returnDescriptor"
}
@@ -108,34 +119,34 @@
* + a "field descriptor", for example: `Ljava/lang/Object;`
* + a "method descriptor", for example: `(Ljava/lang/Object;)Z`
*
- * The easiest way to use this is through [TypeMirror.descriptor][JvmDescriptorUtils.descriptor] in [JvmDescriptorUtils].
+ * The easiest way to use this is through [TypeMirror.descriptor]
*
* For reference, see the [JVM specification, section 4.3](http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3).
*/
@Suppress("DEPRECATION")
-internal object JvmDescriptorTypeVisitor : AbstractTypeVisitor6<String, Types>() {
- override fun visitNoType(t: NoType, typeUtils: Types): String = t.descriptor
+internal object JvmDescriptorTypeVisitor : AbstractTypeVisitor8<String, Unit>() {
- override fun visitDeclared(t: DeclaredType, typeUtils: Types): String = t.descriptor
+ override fun visitNoType(t: NoType, u: Unit): String = t.descriptor
- override fun visitPrimitive(t: PrimitiveType, typeUtils: Types): String = t.descriptor
+ override fun visitDeclared(t: DeclaredType, u: Unit): String = t.descriptor
- override fun visitArray(t: ArrayType, typeUtils: Types): String = t.descriptor(typeUtils)
+ override fun visitPrimitive(t: PrimitiveType, u: Unit): String = t.descriptor
- override fun visitWildcard(t: WildcardType, typeUtils: Types): String = t.descriptor(typeUtils)
+ override fun visitArray(t: ArrayType, u: Unit): String = t.descriptor()
- override fun visitExecutable(t: ExecutableType, typeUtils: Types): String =
- t.descriptor(typeUtils)
+ override fun visitWildcard(t: WildcardType, u: Unit): String = t.descriptor()
- override fun visitTypeVariable(t: TypeVariable, typeUtils: Types): String =
- t.descriptor(typeUtils)
+ override fun visitExecutable(t: ExecutableType, u: Unit): String = t.descriptor()
- override fun visitNull(t: NullType, typeUtils: Types): String =
- visitUnknown(t, typeUtils)
+ override fun visitTypeVariable(t: TypeVariable, u: Unit): String = t.descriptor()
- override fun visitError(t: ErrorType, typeUtils: Types): String =
- visitUnknown(t, typeUtils)
+ override fun visitNull(t: NullType, u: Unit): String = visitUnknown(t, u)
- override fun visitUnknown(t: TypeMirror, typeUtils: Types): String =
- error("Unsupported type $t")
+ override fun visitError(t: ErrorType, u: Unit): String = visitUnknown(t, u)
+
+ override fun visitIntersection(t: IntersectionType, u: Unit) = t.descriptor()
+
+ override fun visitUnion(t: UnionType, u: Unit) = visitUnknown(t, u)
+
+ override fun visitUnknown(t: TypeMirror, u: Unit): String = error("Unsupported type $t")
}
\ No newline at end of file
diff --git a/room/compiler/src/main/kotlin/androidx/room/kotlin/KotlinMetadataElement.kt b/room/compiler/src/main/kotlin/androidx/room/kotlin/KotlinMetadataElement.kt
index 82eb235..6d121bc 100644
--- a/room/compiler/src/main/kotlin/androidx/room/kotlin/KotlinMetadataElement.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/kotlin/KotlinMetadataElement.kt
@@ -35,7 +35,7 @@
private val constructorList: List<KmConstructor> by lazy { classMetadata.readConstructors() }
private val ExecutableElement.descriptor: String
- get() = descriptor(context.processingEnv.typeUtils)
+ get() = descriptor()
/**
* Returns the parameter names of the function or constructor if all have names embedded in the
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
index 745c40f..d787416 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
@@ -389,7 +389,7 @@
val primaryConstructor =
kotlinMetadata?.findPrimaryConstructorSignature()?.let { signature ->
goodConstructors.firstOrNull {
- it.element.descriptor(context.processingEnv.typeUtils) == signature
+ it.element.descriptor() == signature
}
}
if (primaryConstructor != null) {
diff --git a/room/compiler/src/test/kotlin/androidx/room/kotlin/JvmDescriptorUtilsTest.kt b/room/compiler/src/test/kotlin/androidx/room/kotlin/JvmDescriptorUtilsTest.kt
index f5f1052..616e42e 100644
--- a/room/compiler/src/test/kotlin/androidx/room/kotlin/JvmDescriptorUtilsTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/kotlin/JvmDescriptorUtilsTest.kt
@@ -26,6 +26,7 @@
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import toJFO
+import javax.lang.model.element.ElementKind
import javax.tools.JavaFileObject
@RunWith(JUnit4::class)
@@ -38,7 +39,7 @@
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
- @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+ @Target({ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})
public @interface Describe { }
""".toJFO("androidx.room.test.Describe")
@@ -57,6 +58,97 @@
) { descriptors ->
assertThat(descriptors.first())
.isEqualTo("emptyMethod()V")
+ }
+ }
+
+ @Test
+ fun descriptor_field() {
+ singleRun(
+ """
+ package androidx.room.test;
+
+ import java.util.List;
+
+ class DummyClass<T> {
+ @Describe
+ int field1;
+
+ @Describe
+ String field2;
+
+ @Describe
+ T field3;
+
+ @Describe
+ List<String> field4;
+ }
+ """.toJFO("androidx.room.test.DummyClass")
+ ) { descriptors ->
+ assertThat(descriptors).isEqualTo(
+ setOf(
+ "field1:I",
+ "field2:Ljava/lang/String;",
+ "field3:Ljava/lang/Object;",
+ "field4:Ljava/util/List;"
+ )
+ )
+ }.compilesWithoutError()
+ }
+
+ @Test
+ fun descriptor_method_erasured() {
+ singleRun(
+ """
+ package androidx.room.test;
+
+ import java.util.ArrayList;
+ import java.util.Collection;
+ import java.util.List;
+ import java.util.Map;
+
+ class DummyClass<T> {
+ @Describe
+ void method1(T something) { }
+
+ @Describe
+ T method2() { return null; }
+
+ @Describe
+ List<? extends String> method3() { return null; }
+
+ @Describe
+ Map<T, String> method4() { return null; }
+
+ @Describe
+ ArrayList<Map<T, String>> method5() { return null; }
+
+ @Describe
+ static <I, O extends I> O method6(I input) { return null; }
+
+ @Describe
+ static <I, O extends String> O method7(I input) { return null; }
+
+ @Describe
+ static <P extends Collection & Comparable> P method8() { return null; }
+
+ @Describe
+ static <P extends String & List<Character>> P method9() { return null; }
+ }
+ """.toJFO("androidx.room.test.DummyClass")
+ ) { descriptors ->
+ assertThat(descriptors).isEqualTo(
+ setOf(
+ "method1(Ljava/lang/Object;)V",
+ "method2()Ljava/lang/Object;",
+ "method3()Ljava/util/List;",
+ "method4()Ljava/util/Map;",
+ "method5()Ljava/util/ArrayList;",
+ "method6(Ljava/lang/Object;)Ljava/lang/Object;",
+ "method7(Ljava/lang/Object;)Ljava/lang/String;",
+ "method8()Ljava/util/Collection;",
+ "method9()Ljava/lang/String;"
+ )
+ )
}.compilesWithoutError()
}
@@ -94,6 +186,7 @@
import java.util.ArrayList;
import java.util.List;
+ import java.util.Map;
class DummyClass {
@Describe
@@ -104,6 +197,9 @@
@Describe
List<String> method3(ArrayList<Integer> list) { return null; }
+
+ @Describe
+ Map<String, Object> method4() { return null; }
}
""".toJFO("androidx.room.test.DummyClass")
) { descriptors ->
@@ -111,7 +207,8 @@
setOf(
"method1(Ljava/lang/Object;)V",
"method2()Ljava/lang/Object;",
- "method3(Ljava/util/ArrayList;)Ljava/util/List;"
+ "method3(Ljava/util/ArrayList;)Ljava/util/List;",
+ "method4()Ljava/util/Map;"
)
)
}.compilesWithoutError()
@@ -243,7 +340,13 @@
.processedWith(TestProcessor.builder()
.nextRunHandler {
it.roundEnv.getElementsAnnotatedWith(it.annotations.first()).map { element ->
- MoreElements.asExecutable(element).descriptor(it.processingEnv.typeUtils)
+ when (element.kind) {
+ ElementKind.FIELD ->
+ MoreElements.asVariable(element).descriptor()
+ ElementKind.CONSTRUCTOR, ElementKind.METHOD ->
+ MoreElements.asExecutable(element).descriptor()
+ else -> error("Unsupported element to describe.")
+ }
}.toSet().let(handler)
true
}
diff --git a/room/compiler/src/test/kotlin/androidx/room/kotlin/KotlinMetadataElementTest.kt b/room/compiler/src/test/kotlin/androidx/room/kotlin/KotlinMetadataElementTest.kt
index 0d49c95..5d89402 100644
--- a/room/compiler/src/test/kotlin/androidx/room/kotlin/KotlinMetadataElementTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/kotlin/KotlinMetadataElementTest.kt
@@ -55,7 +55,7 @@
)
assertThat(
ElementFilter.constructorsIn(testClassElement.enclosedElements).map {
- val desc = MoreElements.asExecutable(it).descriptor(invocation.typeUtils)
+ val desc = MoreElements.asExecutable(it).descriptor()
desc to (desc == metadataElement.findPrimaryConstructorSignature())
}
).containsExactly(