Merge "Add XMethodType.typeVariables APIs" into androidx-main
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/JavaPoetExt.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/JavaPoetExt.kt
index 08e61c1..61bca7a 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/JavaPoetExt.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/JavaPoetExt.kt
@@ -22,6 +22,7 @@
import com.squareup.javapoet.TypeName
import com.squareup.javapoet.TypeSpec
import com.squareup.kotlinpoet.javapoet.JClassName
+import com.squareup.kotlinpoet.javapoet.JTypeVariableName
import java.lang.Character.isISOControl
import javax.lang.model.SourceVersion
import javax.lang.model.element.Modifier
@@ -183,7 +184,7 @@
): MethodSpec.Builder {
return MethodSpec.methodBuilder(executableElement.jvmName).apply {
addTypeVariables(
- resolvedType.typeVariableNames
+ resolvedType.typeVariables.map { it.asTypeName().java as JTypeVariableName }
)
resolvedType.parameterTypes.forEachIndexed { index, paramType ->
addParameter(
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XMethodType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XMethodType.kt
index 9fb09bc..6647d68 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XMethodType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XMethodType.kt
@@ -30,9 +30,18 @@
*/
val returnType: XType
+ val typeVariables: List<XTypeVariableType>
+
/**
* Returns the names of [TypeVariableName]s for this executable.
*/
+ @Deprecated(
+ message = "Use typeVariables property and convert to JavaPoet names.",
+ replaceWith = ReplaceWith(
+ expression = "typeVariables.map { it.asTypeName().toJavaPoet() }",
+ imports = ["androidx.room.compiler.codegen.toJavaPoet"]
+ )
+ )
val typeVariableNames: List<TypeVariableName>
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XType.kt
index 9ad98bf..5933211 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XType.kt
@@ -49,7 +49,7 @@
fun asTypeName(): XTypeName
/**
- * Returns the rawType of this type. (e.g. `List<String>` to `List`.
+ * Returns the rawType of this type. (e.g. `List<String>` to `List`).
*/
val rawType: XRawType
@@ -72,8 +72,8 @@
/**
* The [XTypeElement] that represents this type.
*
- * Note that it might be null if the type is not backed by a type element (e.g. if it is a
- * primitive, wildcard etc)
+ * Note that it will be null if the type is not backed by a type element (e.g. it is a
+ * primitive, type variable, wildcard, etc)
*
* @see isTypeElement
*/
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/DefaultJavacType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/DefaultJavacType.kt
index f829a4b..d4074a9 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/DefaultJavacType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/DefaultJavacType.kt
@@ -19,7 +19,8 @@
import androidx.room.compiler.processing.XNullability
import androidx.room.compiler.processing.XType
import androidx.room.compiler.processing.javac.kotlin.KmTypeContainer
-import androidx.room.compiler.processing.javac.kotlin.nullability
+import com.google.auto.common.MoreTypes
+import javax.lang.model.type.TypeKind
import javax.lang.model.type.TypeMirror
/**
@@ -76,6 +77,30 @@
*/
get() = emptyList()
+ override fun boxed(): JavacType {
+ return when {
+ typeMirror.kind.isPrimitive -> {
+ env.wrap(
+ typeMirror =
+ env.typeUtils.boxedClass(MoreTypes.asPrimitiveType(typeMirror)).asType(),
+ kotlinType = kotlinType,
+ elementNullability = XNullability.NULLABLE
+ )
+ }
+ typeMirror.kind == TypeKind.VOID -> {
+ env.wrap(
+ typeMirror =
+ env.elementUtils.getTypeElement("java.lang.Void").asType(),
+ kotlinType = kotlinType,
+ elementNullability = XNullability.NULLABLE
+ )
+ }
+ else -> {
+ this
+ }
+ }
+ }
+
override fun copyWithNullability(nullability: XNullability): JavacType {
return DefaultJavacType(
env = env,
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacArrayType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacArrayType.kt
index e48dd79..fd384c2 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacArrayType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacArrayType.kt
@@ -22,7 +22,6 @@
import androidx.room.compiler.processing.XNullability
import androidx.room.compiler.processing.XType
import androidx.room.compiler.processing.javac.kotlin.KmTypeContainer
-import androidx.room.compiler.processing.javac.kotlin.nullability
import javax.lang.model.type.ArrayType
internal class JavacArrayType private constructor(
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacDeclaredType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacDeclaredType.kt
index a00819f..8a3f7b9 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacDeclaredType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacDeclaredType.kt
@@ -18,7 +18,6 @@
import androidx.room.compiler.processing.XNullability
import androidx.room.compiler.processing.javac.kotlin.KmTypeContainer
-import androidx.room.compiler.processing.javac.kotlin.nullability
import javax.lang.model.type.DeclaredType
/**
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodType.kt
index 54287bb..9d4cee8 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodType.kt
@@ -42,12 +42,23 @@
)
}
- override val typeVariableNames by lazy {
- executableType.typeVariables.map {
- TypeVariableName.get(it)
+ override val typeVariables: List<JavacTypeVariableType> by lazy {
+ executableType.typeVariables.mapIndexed { index, typeVariable ->
+ env.wrap(typeVariable, element.kotlinMetadata?.typeParameters?.get(index))
}
}
+ @Deprecated(
+ "Use typeVariables property and convert to JavaPoet names.",
+ replaceWith = ReplaceWith(
+ "typeVariables.map { it.asTypeName().toJavaPoet() }",
+ "androidx.room.compiler.codegen.toJavaPoet"
+ )
+ )
+ override val typeVariableNames by lazy {
+ typeVariables.map { it.asTypeName().java as TypeVariableName }
+ }
+
private class NormalMethodType(
env: JavacProcessingEnv,
element: JavacMethodElement,
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacProcessingEnv.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacProcessingEnv.kt
index cec6636..89bfdb6 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacProcessingEnv.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacProcessingEnv.kt
@@ -24,6 +24,7 @@
import androidx.room.compiler.processing.XType
import androidx.room.compiler.processing.XTypeElement
import androidx.room.compiler.processing.javac.kotlin.KmTypeContainer
+import androidx.room.compiler.processing.javac.kotlin.KmTypeParameterContainer
import com.google.auto.common.GeneratedAnnotations
import com.google.auto.common.MoreTypes
import java.util.Locale
@@ -36,6 +37,7 @@
import javax.lang.model.element.VariableElement
import javax.lang.model.type.TypeKind
import javax.lang.model.type.TypeMirror
+import javax.lang.model.type.TypeVariable
import javax.lang.model.util.Elements
import javax.lang.model.util.Types
@@ -163,6 +165,27 @@
fun wrapTypeElement(element: TypeElement) = typeElementStore[element]
+ fun wrap(
+ typeMirror: TypeVariable,
+ kotlinType: KmTypeParameterContainer?,
+ ): JavacTypeVariableType {
+ return when {
+ kotlinType != null -> {
+ JavacTypeVariableType(
+ env = this,
+ typeMirror = MoreTypes.asTypeVariable(typeMirror),
+ kotlinType = kotlinType
+ )
+ }
+ else -> {
+ JavacTypeVariableType(
+ env = this,
+ typeMirror = MoreTypes.asTypeVariable(typeMirror)
+ )
+ }
+ }
+ }
+
/**
* Wraps the given java processing type into an XType.
*
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacType.kt
index 89420be..2d66b79 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacType.kt
@@ -24,6 +24,7 @@
import androidx.room.compiler.processing.XNullability
import androidx.room.compiler.processing.XRawType
import androidx.room.compiler.processing.XType
+import androidx.room.compiler.processing.javac.kotlin.KmBaseTypeContainer
import androidx.room.compiler.processing.javac.kotlin.KmClassContainer
import androidx.room.compiler.processing.javac.kotlin.KmTypeContainer
import androidx.room.compiler.processing.ksp.ERROR_JTYPE_NAME
@@ -42,7 +43,7 @@
) : XType, XEquality, InternalXAnnotated {
// Kotlin type information about the type if this type is driven from Kotlin code.
- abstract val kotlinType: KmTypeContainer?
+ abstract val kotlinType: KmBaseTypeContainer?
override val rawType: XRawType by lazy {
JavacRawType(env, this)
@@ -107,12 +108,12 @@
}
override fun getAllAnnotations(): List<XAnnotation> {
- return kotlinType?.annotations?.map {
+ return (kotlinType as? KmTypeContainer)?.annotations?.map {
JavacKmAnnotation(env, it)
} ?: typeMirror.annotationMirrors.map { mirror -> JavacAnnotation(env, mirror) }
- .flatMap { annotation ->
- annotation.unwrapRepeatedAnnotationsFromContainer() ?: listOf(annotation)
- }
+ .flatMap { annotation ->
+ annotation.unwrapRepeatedAnnotationsFromContainer() ?: listOf(annotation)
+ }
}
override fun hasAnnotationWithPackage(pkg: String): Boolean {
@@ -142,26 +143,7 @@
}
override fun boxed(): JavacType {
- return when {
- typeMirror.kind.isPrimitive -> {
- env.wrap(
- typeMirror = env.typeUtils.boxedClass(MoreTypes.asPrimitiveType(typeMirror))
- .asType(),
- kotlinType = kotlinType,
- elementNullability = XNullability.NULLABLE
- )
- }
- typeMirror.kind == TypeKind.VOID -> {
- env.wrap(
- typeMirror = env.elementUtils.getTypeElement("java.lang.Void").asType(),
- kotlinType = kotlinType,
- elementNullability = XNullability.NULLABLE
- )
- }
- else -> {
- this
- }
- }
+ return this
}
override fun isNone() = typeMirror.kind == TypeKind.NONE
@@ -174,7 +156,7 @@
return typeMirror.extendsBound()?.let {
env.wrap<JavacType>(
typeMirror = it,
- kotlinType = kotlinType?.extendsBound,
+ kotlinType = (kotlinType as? KmTypeContainer)?.extendsBound,
elementNullability = maybeNullability
)
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeVariableType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeVariableType.kt
index 98a3703..a0dcb17 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeVariableType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeVariableType.kt
@@ -19,8 +19,7 @@
import androidx.room.compiler.processing.XNullability
import androidx.room.compiler.processing.XType
import androidx.room.compiler.processing.XTypeVariableType
-import androidx.room.compiler.processing.javac.kotlin.KmTypeContainer
-import androidx.room.compiler.processing.javac.kotlin.nullability
+import androidx.room.compiler.processing.javac.kotlin.KmBaseTypeContainer
import com.google.auto.common.MoreTypes.asIntersection
import javax.lang.model.type.TypeKind
import javax.lang.model.type.TypeVariable
@@ -29,7 +28,7 @@
env: JavacProcessingEnv,
override val typeMirror: TypeVariable,
nullability: XNullability?,
- override val kotlinType: KmTypeContainer?
+ override val kotlinType: KmBaseTypeContainer?
) : JavacType(env, typeMirror, nullability), XTypeVariableType {
constructor(
env: JavacProcessingEnv,
@@ -44,7 +43,7 @@
constructor(
env: JavacProcessingEnv,
typeMirror: TypeVariable,
- kotlinType: KmTypeContainer
+ kotlinType: KmBaseTypeContainer
) : this(
env = env,
typeMirror = typeMirror,
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
index 8c9d94b..518aac9 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
@@ -53,6 +53,12 @@
val flags: Flags
}
+internal interface KmBaseTypeContainer : KmFlags {
+ val upperBounds: List<KmTypeContainer>
+ val nullability: XNullability
+ fun isNullable() = Flag.Type.IS_NULLABLE(flags)
+}
+
internal class KmClassContainer(
private val env: JavacProcessingEnv,
private val kmClass: KmClass
@@ -296,9 +302,9 @@
val typeArguments: List<KmTypeContainer>,
/** The extends bounds are only non-null for wildcard (i.e. in/out variant) types. */
val extendsBound: KmTypeContainer? = null,
- /** The upper bounds are only non-null for type variable types with upper bounds. */
- val upperBounds: List<KmTypeContainer>? = null
-) : KmFlags {
+ /** The upper bounds are only non-empty for type variable types with upper bounds. */
+ override val upperBounds: List<KmTypeContainer> = emptyList()
+) : KmBaseTypeContainer {
override val flags: Flags
get() = kmType.flags
@@ -313,15 +319,17 @@
fun isExtensionType() =
kmType.annotations.any { it.className == "kotlin/ExtensionFunctionType" }
- fun isNullable() = Flag.Type.IS_NULLABLE(flags)
fun erasure(): KmTypeContainer = KmTypeContainer(
kmType = kmType,
typeArguments = emptyList(),
extendsBound = extendsBound?.erasure(),
// The erasure of a type variable is equal to the erasure of the first upper bound.
- upperBounds = upperBounds?.firstOrNull()?.erasure()?.let { listOf(it) },
+ upperBounds = upperBounds.firstOrNull()?.erasure()?.let { listOf(it) } ?: emptyList(),
)
+
+ override val nullability: XNullability
+ get() = computeTypeNullability(this.isNullable(), this.upperBounds, this.extendsBound)
}
internal class KmAnnotationContainer(private val kmAnnotation: KmAnnotation) {
@@ -367,26 +375,17 @@
}
}
-internal val KmTypeContainer.nullability: XNullability
- get() = if (isNullable()) {
- XNullability.NULLABLE
- } else {
- // if there is an upper bound information, use its nullability (e.g. it might be T : Foo?)
- if (upperBounds?.all { it.nullability == XNullability.NULLABLE } == true) {
- XNullability.NULLABLE
- } else {
- extendsBound?.nullability ?: XNullability.NONNULL
- }
- }
-
internal class KmTypeParameterContainer(
private val kmTypeParameter: KmTypeParameter,
- val upperBounds: List<KmTypeContainer>
-) : KmFlags {
+ override val upperBounds: List<KmTypeContainer>
+) : KmBaseTypeContainer {
override val flags: Flags
get() = kmTypeParameter.flags
val name: String
get() = kmTypeParameter.name
+
+ override val nullability: XNullability
+ get() = computeTypeNullability(this.isNullable(), this.upperBounds, null)
}
internal class KmValueParameterContainer(
@@ -402,6 +401,21 @@
fun hasDefault() = Flag.ValueParameter.DECLARES_DEFAULT_VALUE(flags)
}
+private fun computeTypeNullability(
+ isNullable: Boolean,
+ upperBounds: List<KmTypeContainer>,
+ extendsBound: KmTypeContainer?
+): XNullability {
+ if (isNullable) {
+ return XNullability.NULLABLE
+ }
+ // if there is an upper bound information, use its nullability (e.g. it might be T : Foo?)
+ if (upperBounds.isNotEmpty() && upperBounds.all { it.nullability == XNullability.NULLABLE }) {
+ return XNullability.NULLABLE
+ }
+ return extendsBound?.nullability ?: XNullability.NONNULL
+}
+
private fun KmFunction.asContainer(): KmFunctionContainer =
KmFunctionContainerImpl(
kmFunction = this,
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodType.kt
index 600bb01..04bd525 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodType.kt
@@ -19,6 +19,7 @@
import androidx.room.compiler.processing.XMethodType
import androidx.room.compiler.processing.XSuspendMethodType
import androidx.room.compiler.processing.XType
+import androidx.room.compiler.processing.XTypeVariableType
import com.squareup.javapoet.TypeVariableName
internal sealed class KspMethodType(
@@ -26,18 +27,24 @@
override val origin: KspMethodElement,
containing: KspType?
) : KspExecutableType(env, origin, containing), XMethodType {
- override val typeVariableNames: List<TypeVariableName> by lazy {
+
+ override val typeVariables: List<XTypeVariableType> by lazy {
origin.declaration.typeParameters.map {
- val typeParameterBounds = it.bounds.map {
- it.asJTypeName(env.resolver)
- }.toList().toTypedArray()
- TypeVariableName.get(
- it.name.asString(),
- *typeParameterBounds
- )
+ KspMethodTypeVariableType(env, it)
}
}
+ @Deprecated(
+ "Use typeVariables property and convert to JavaPoet names.",
+ replaceWith = ReplaceWith(
+ "typeVariables.map { it.asTypeName().toJavaPoet() }",
+ "androidx.room.compiler.codegen.toJavaPoet"
+ )
+ )
+ override val typeVariableNames: List<TypeVariableName> by lazy {
+ typeVariables.map { it.asTypeName().java as TypeVariableName }
+ }
+
private class KspNormalMethodType(
env: KspProcessingEnv,
origin: KspMethodElement,
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodTypeVariableType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodTypeVariableType.kt
new file mode 100644
index 0000000..5a9d520
--- /dev/null
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodTypeVariableType.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.compiler.processing.ksp
+
+import androidx.room.compiler.codegen.XTypeName
+import androidx.room.compiler.processing.XEquality
+import androidx.room.compiler.processing.XNullability
+import androidx.room.compiler.processing.XRawType
+import androidx.room.compiler.processing.XType
+import androidx.room.compiler.processing.XTypeElement
+import androidx.room.compiler.processing.XTypeVariableType
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSTypeParameter
+import com.squareup.javapoet.TypeName
+import kotlin.reflect.KClass
+
+/**
+ * A KSP [XType] representing the type var type declared in a function.
+ *
+ * This class is different than [KspTypeVariableType] due to KSP having no type var model and only
+ * type var declaration (i.e. [KSTypeParameter]).
+ */
+internal class KspMethodTypeVariableType(
+ env: KspProcessingEnv,
+ val ksTypeVariable: KSTypeParameter,
+) : KspAnnotated(env), XTypeVariableType, XEquality {
+
+ override val typeName: TypeName by lazy {
+ xTypeName.java
+ }
+
+ override fun asTypeName() = xTypeName
+
+ private val xTypeName: XTypeName by lazy {
+ XTypeName(
+ ksTypeVariable.asJTypeName(env.resolver),
+ ksTypeVariable.asKTypeName(env.resolver),
+ nullability
+ )
+ }
+
+ override val upperBounds: List<XType> = ksTypeVariable.bounds.map(env::wrap).toList()
+
+ override fun annotations(): Sequence<KSAnnotation> {
+ return ksTypeVariable.annotations
+ }
+
+ override val rawType: XRawType by lazy {
+ object : XRawType {
+ override val typeName: TypeName
+ get() = this@KspMethodTypeVariableType.typeName
+
+ override fun asTypeName(): XTypeName =
+ this@KspMethodTypeVariableType.asTypeName()
+
+ override fun isAssignableFrom(other: XRawType): Boolean {
+ return this.typeName == other.typeName
+ }
+ }
+ }
+
+ override val nullability: XNullability
+ get() = XNullability.UNKNOWN
+
+ override val superTypes: List<XType> by lazy {
+ val anyType = env.requireType(XTypeName.ANY_OBJECT).makeNullable()
+ if (upperBounds.size == 1 && upperBounds.single() == anyType) {
+ upperBounds
+ } else {
+ listOf(anyType) + upperBounds
+ }
+ }
+
+ override val typeElement: XTypeElement?
+ get() = null
+
+ override val typeArguments: List<XType>
+ get() = emptyList()
+
+ override fun isAssignableFrom(other: XType): Boolean {
+ val typeVar = when (other) {
+ is KspTypeVariableType -> other.ksTypeVariable
+ is KspMethodTypeVariableType -> other.ksTypeVariable
+ else -> null
+ }
+ return ksTypeVariable == typeVar
+ }
+
+ override fun isError(): Boolean {
+ return false
+ }
+
+ override fun defaultValue(): String {
+ return "null"
+ }
+
+ override fun boxed(): KspMethodTypeVariableType {
+ return this
+ }
+
+ override fun isNone(): Boolean {
+ return false
+ }
+
+ override fun isTypeOf(other: KClass<*>): Boolean {
+ return false
+ }
+
+ override fun isSameType(other: XType): Boolean {
+ val typeVar = when (other) {
+ is KspTypeVariableType -> other.ksTypeVariable
+ is KspMethodTypeVariableType -> other.ksTypeVariable
+ else -> null
+ }
+ return ksTypeVariable == typeVar
+ }
+
+ override fun extendsBound(): XType? {
+ return null
+ }
+
+ override fun makeNullable(): XType {
+ return this
+ }
+
+ override fun makeNonNullable(): XType {
+ return this
+ }
+
+ override val equalityItems: Array<out Any?> by lazy {
+ arrayOf(ksTypeVariable)
+ }
+
+ override fun equals(other: Any?): Boolean {
+ return XEquality.equals(this, other)
+ }
+
+ override fun hashCode(): Int {
+ return XEquality.hashCode(equalityItems)
+ }
+
+ override fun toString(): String {
+ return ksTypeVariable.toString()
+ }
+}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt
index e17e57f3..0eff801 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt
@@ -269,7 +269,7 @@
}
val qName = ksType.declaration.qualifiedName?.asString()
if (declaration is KSTypeParameter) {
- return KspTypeVariableType(this, ksType, originalAnnotations)
+ return KspTypeVariableType(this, declaration, ksType, originalAnnotations)
}
if (allowPrimitives && qName != null && ksType.nullability == Nullability.NOT_NULL) {
// check for primitives
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeVariableType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeVariableType.kt
index 04ea9f7..33f7600 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeVariableType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeVariableType.kt
@@ -24,30 +24,30 @@
import com.squareup.kotlinpoet.javapoet.JTypeName
import com.squareup.kotlinpoet.javapoet.KTypeName
+/**
+ * An [XType] representing the type var type in a function parameter, return type or class
+ * declaration.
+ *
+ * This is different than [KspMethodTypeVariableType] because the [KSType] has as reference the
+ * [KSTypeParameter] declaration.
+ */
internal class KspTypeVariableType(
env: KspProcessingEnv,
+ val ksTypeVariable: KSTypeParameter,
ksType: KSType,
- originalKSAnnotations: Sequence<KSAnnotation> = ksType.annotations,
+ originalKSAnnotations: Sequence<KSAnnotation> = ksTypeVariable.annotations,
scope: KSTypeVarianceResolverScope? = null,
) : KspType(env, ksType, originalKSAnnotations, scope, null), XTypeVariableType {
- private val typeVariable: KSTypeParameter by lazy {
- // Note: This is a workaround for a bug in KSP where we may get ERROR_TYPE in the bounds
- // (https://github.com/google/ksp/issues/1250). To work around it we get the matching
- // KSTypeParameter from the parent declaration instead.
- ksType.declaration.parentDeclaration!!.typeParameters
- .filter { it.name == (ksType.declaration as KSTypeParameter).name }
- .single()
- }
override fun resolveJTypeName(): JTypeName {
- return typeVariable.asJTypeName(env.resolver)
+ return ksTypeVariable.asJTypeName(env.resolver)
}
override fun resolveKTypeName(): KTypeName {
- return typeVariable.asKTypeName(env.resolver)
+ return ksTypeVariable.asKTypeName(env.resolver)
}
- override val upperBounds: List<XType> = typeVariable.bounds.map(env::wrap).toList()
+ override val upperBounds: List<XType> = ksTypeVariable.bounds.map(env::wrap).toList()
override fun boxed(): KspTypeVariableType {
return this
@@ -59,5 +59,15 @@
originalKSAnnotations: Sequence<KSAnnotation>,
scope: KSTypeVarianceResolverScope?,
typeAlias: KSType?
- ) = KspTypeVariableType(env, ksType, originalKSAnnotations, scope)
+ ) = KspTypeVariableType(
+ env,
+ ksType.declaration as KSTypeParameter,
+ ksType,
+ originalKSAnnotations,
+ scope
+ )
+
+ override val equalityItems: Array<out Any?> by lazy {
+ arrayOf(ksTypeVariable)
+ }
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodType.kt
index 7341b8a..c14bec0 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodType.kt
@@ -19,6 +19,7 @@
import androidx.room.compiler.processing.XExecutableType
import androidx.room.compiler.processing.XMethodType
import androidx.room.compiler.processing.XType
+import androidx.room.compiler.processing.XTypeVariableType
import androidx.room.compiler.processing.ksp.KSTypeVarianceResolverScope
import androidx.room.compiler.processing.ksp.KspProcessingEnv
import androidx.room.compiler.processing.ksp.KspType
@@ -47,6 +48,16 @@
}
}
+ override val typeVariables: List<XTypeVariableType>
+ get() = emptyList()
+
+ @Deprecated(
+ "Use typeVariables property and convert to JavaPoet names.",
+ replaceWith = ReplaceWith(
+ "typeVariables.map { it.asTypeName().toJavaPoet() }",
+ "androidx.room.compiler.codegen.toJavaPoet"
+ )
+ )
override val typeVariableNames: List<TypeVariableName>
get() = emptyList()
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableTypeTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableTypeTest.kt
index 95adf50..4d9dcea 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableTypeTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableTypeTest.kt
@@ -17,10 +17,13 @@
package androidx.room.compiler.processing
import androidx.kruth.assertThat
+import androidx.room.compiler.codegen.XTypeName
+import androidx.room.compiler.codegen.asMutableClassName
import androidx.room.compiler.processing.util.CONTINUATION_JCLASS_NAME
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.UNIT_JCLASS_NAME
import androidx.room.compiler.processing.util.getMethodByJvmName
+import androidx.room.compiler.processing.util.runKspTest
import androidx.room.compiler.processing.util.runProcessorTest
import androidx.room.compiler.processing.util.typeName
import com.google.common.truth.Truth
@@ -458,7 +461,7 @@
}
assertThat(method.parameterTypes).isEmpty()
- assertThat(method.typeVariableNames).isEmpty()
+ assertThat(method.typeVariables).isEmpty()
}
checkMethods("getMutableT", subject) { method ->
assertThat(method.returnType.typeName).isEqualTo(String::class.typeName())
@@ -468,7 +471,7 @@
assertThat(method.returnType.nullability).isEqualTo(XNullability.NULLABLE)
}
assertThat(method.parameterTypes).isEmpty()
- assertThat(method.typeVariableNames).isEmpty()
+ assertThat(method.typeVariables).isEmpty()
}
checkMethods("setMutableT", subject) { method ->
assertThat(method.returnType.typeName).isEqualTo(TypeName.VOID)
@@ -476,7 +479,7 @@
.isEqualTo(XNullability.NULLABLE)
assertThat(method.parameterTypes.first().typeName)
.isEqualTo(String::class.typeName())
- assertThat(method.typeVariableNames).isEmpty()
+ assertThat(method.typeVariables).isEmpty()
}
checkMethods("getList", subject) { method ->
assertThat(method.returnType.typeName).isEqualTo(
@@ -509,7 +512,7 @@
assertThat(method.returnType.nullability).isEqualTo(XNullability.NULLABLE)
}
assertThat(method.parameterTypes).isEmpty()
- assertThat(method.typeVariableNames).isEmpty()
+ assertThat(method.typeVariables).isEmpty()
}
checkMethods("getMutableT", nullableSubject) { method ->
@@ -520,7 +523,7 @@
assertThat(method.returnType.nullability).isEqualTo(XNullability.NULLABLE)
}
assertThat(method.parameterTypes).isEmpty()
- assertThat(method.typeVariableNames).isEmpty()
+ assertThat(method.typeVariables).isEmpty()
}
checkMethods("setMutableT", nullableSubject) { method ->
@@ -529,7 +532,7 @@
.isEqualTo(XNullability.NULLABLE)
assertThat(method.parameterTypes.first().typeName)
.isEqualTo(String::class.typeName())
- assertThat(method.typeVariableNames).isEmpty()
+ assertThat(method.typeVariables).isEmpty()
}
checkMethods("getList", nullableSubject) { method ->
@@ -570,4 +573,78 @@
}
}
}
+
+ @Test
+ fun typeVariableTest() {
+ val kotlinSrc = Source.kotlin(
+ "KotlinSubject.kt",
+ """
+ class KotlinSubject {
+ fun <T> oneTypeVar(): Unit = TODO()
+ fun <T : MutableList<*>> oneBoundedTypeVar(): Unit = TODO()
+ fun <A, B> twoTypeVar(param: B): A = TODO()
+ }
+ """.trimIndent()
+ )
+ val javaSrc = Source.java(
+ "JavaSubject",
+ """
+ import java.util.List;
+ class JavaSubject {
+ <T> void oneTypeVar() {}
+ <T extends List<?>> void oneBoundedTypeVar() { }
+ <A, B> A twoTypeVar(B param) { return null; }
+ }
+ """.trimIndent()
+ )
+ runKspTest(sources = listOf(kotlinSrc, javaSrc)) { invocation ->
+ listOf("KotlinSubject", "JavaSubject",).forEach { subjectFqn ->
+ val subject = invocation.processingEnv.requireTypeElement(subjectFqn)
+ subject.getMethodByJvmName("oneTypeVar").let {
+ val typeVar = it.executableType.typeVariables.single()
+ assertThat(typeVar.asTypeName())
+ .isEqualTo(XTypeName.getTypeVariableName("T"))
+ assertThat(typeVar.superTypes.map { it.asTypeName() })
+ .containsExactly(XTypeName.ANY_OBJECT.copy(nullable = true))
+ assertThat(typeVar.typeArguments).isEmpty()
+ assertThat(typeVar.typeElement).isNull()
+ }
+ subject.getMethodByJvmName("oneBoundedTypeVar").let {
+ val typeVar = it.executableType.typeVariables.single()
+ assertThat(typeVar.asTypeName())
+ .isEqualTo(
+ XTypeName.getTypeVariableName(
+ name = "T",
+ bounds = listOf(
+ List::class.asMutableClassName()
+ .parametrizedBy(XTypeName.ANY_WILDCARD)
+ )
+ )
+ )
+ assertThat(typeVar.superTypes.map { it.asTypeName() })
+ .containsExactly(
+ XTypeName.ANY_OBJECT.copy(nullable = true),
+ List::class.asMutableClassName()
+ .parametrizedBy(XTypeName.ANY_WILDCARD)
+ )
+ assertThat(typeVar.typeArguments).isEmpty()
+ assertThat(typeVar.typeElement).isNull()
+ }
+ subject.getMethodByJvmName("twoTypeVar").let {
+ // TODO(b/294102849): Figure out origin JAVA bounds difference between type
+ // var declaration and usage.
+ if (invocation.isKsp && subjectFqn == "JavaSubject") {
+ return@let
+ }
+ val firstTypeVar = it.executableType.typeVariables[0]
+ assertThat(firstTypeVar.isSameType(it.returnType)).isTrue()
+ assertThat(firstTypeVar).isNotEqualTo(it.parameters.single().type)
+
+ val secondTypeVar = it.executableType.typeVariables[1].asTypeName()
+ assertThat(secondTypeVar).isNotEqualTo(it.returnType.asTypeName())
+ assertThat(secondTypeVar).isEqualTo(it.parameters.single().type.asTypeName())
+ }
+ }
+ }
+ }
}
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElementTest.kt
index 26b9bab..0e97e4a 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElementTest.kt
@@ -696,10 +696,10 @@
val (_, withUpperBounds) = getMetadataElement(env, "WithUpperBounds")
assertThat(withUpperBounds.type.typeArguments).hasSize(2)
assertThat(withUpperBounds.type.typeArguments[0].upperBounds).hasSize(1)
- assertThat(withUpperBounds.type.typeArguments[0].upperBounds!![0].isNullable())
+ assertThat(withUpperBounds.type.typeArguments[0].upperBounds[0].isNullable())
.isFalse()
assertThat(withUpperBounds.type.typeArguments[1].upperBounds).hasSize(1)
- assertThat(withUpperBounds.type.typeArguments[1].upperBounds!![0].isNullable())
+ assertThat(withUpperBounds.type.typeArguments[1].upperBounds[0].isNullable())
.isTrue()
val (_, withSuperType) = getMetadataElement(env, "WithSuperType")