Treat platform types as nullable by default
This causes KotlinPoet names to be nullable when the type is a platform type, i.e. from Java sources or compiled Java code. Some exceptions are added for types that are never null, these are: annotation value types, exception types in 'throws' declarations, super types and in Kotlin only the array type of a vararg.
Two additional changes that contribute to this CL are:
* Remove workaround for https://github.com/google/ksp/issues/1004, it is no longer needed and the KSType for annotation values are correctly returned by the latest version of KSP along with the correct nullability.
* Remove 3 lazy properties in KspProcessingEnv, these are the KSTypeVarianceResolver, KspArrayType.Factory and CommonTypes. All 3 helpers retained KSP's resolver across rounds, which shouldn't be done as it can lead to stale caches.
* Avoid usages of toKS() to check for KSP 2, instead create a helper internal function.
See also https://kotlinlang.org/docs/java-interop.html#notation-for-platform-types
Bug: 331427836
Test: ./gradlew :room:room-compiler-processing:test
Change-Id: I643ba1d9c005b1b5c5084d08a23288298bec7489
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSFunctionExt.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSFunctionExt.kt
index 9e5fa7d..5699b25 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSFunctionExt.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSFunctionExt.kt
@@ -34,22 +34,10 @@
env: KspProcessingEnv,
containing: KspType?
): KspType {
- return if (containing?.typeElement?.isAnnotationClass() == true) {
- // Calling #getOriginatingReference() or #returnTypeAsMemberOf() currently fails for
- // annotation classes due to https://github.com/google/ksp/issues/1004. Thus, we avoid
- // calling those methods and just return the return type directly. This should be safe for
- // annotation classes since they can't extend other types or use generics.
- val returnTypeReference = checkNotNull(returnType)
- env.wrap(
- originatingReference = returnTypeReference,
- ksType = returnTypeReference.resolve()
- )
- } else {
- env.wrap(
- originatingReference = checkNotNull(getOriginatingReference()),
- ksType = returnTypeAsMemberOf(ksType = containing?.ksType)
- )
- }
+ return env.wrap(
+ originatingReference = checkNotNull(getOriginatingReference()),
+ ksType = returnTypeAsMemberOf(ksType = containing?.ksType)
+ )
}
private fun KSFunctionDeclaration.getOriginatingReference(): KSTypeReference? {
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeKotlinPoetExt.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeKotlinPoetExt.kt
index 7a80d08..286b0b7 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeKotlinPoetExt.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeKotlinPoetExt.kt
@@ -94,15 +94,9 @@
val typeName = createModifiableTypeVariableName(name = name.asString(), bounds = mutableBounds)
typeArgumentTypeLookup[name] = typeName
val resolvedBounds = bounds.map { typeReference ->
- typeReference.asKTypeName(resolver, typeArgumentTypeLookup).let { kTypeName ->
- typeReference.resolve().let {
- if (it.nullability == Nullability.PLATFORM) {
- kTypeName.copy(nullable = true)
- } else {
- kTypeName
- }
- }
- }
+ val ksType = typeReference.resolve()
+ typeReference.asKTypeName(resolver, typeArgumentTypeLookup)
+ .copy(nullable = ksType.isMarkedNullable || ksType.nullability == Nullability.PLATFORM)
}.toList()
if (resolvedBounds.isNotEmpty()) {
mutableBounds.addAll(resolvedBounds)
@@ -164,7 +158,7 @@
typeName.parameterizedBy(args)
} else {
this.declaration.asKTypeName(resolver, typeArgumentTypeLookup)
- }.copy(nullable = isMarkedNullable)
+ }.copy(nullable = isMarkedNullable || nullability == Nullability.PLATFORM)
}
/**
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt
index ee283c1a..ca9fac4 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt
@@ -51,7 +51,8 @@
override val thrownTypes: List<XType> by lazy {
env.resolver.getJvmCheckedException(declaration).map {
env.wrap(
- ksType = it,
+ // Thrown exception types are never nullable
+ ksType = it.makeNotNullable(),
allowPrimitives = false
)
}.toList()
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt
index bcadc1a..df2511a 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt
@@ -27,6 +27,7 @@
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.google.devtools.ksp.symbol.KSPropertySetter
import com.google.devtools.ksp.symbol.KSValueParameter
+import com.google.devtools.ksp.symbol.Origin
internal class KspExecutableParameterElement(
env: KspProcessingEnv,
@@ -92,10 +93,20 @@
asMemberOf = container,
)
)
- // In KSP2 the varargs have the component type instead of the array type. We make it always
- // return the array type in XProcessing.
- return if (isVarArgs() && !type.isArray()) {
- env.getArrayType(env.getWildcardType(producerExtends = type))
+ return if (isVarArgs()) {
+ if (!type.isArray()) {
+ // In KSP2 the varargs have the component type instead of the array type.
+ // We make it always return the array type in XProcessing.
+ env.getArrayType(env.getWildcardType(producerExtends = type))
+ } else {
+ type
+ }.run {
+ // In Kotlin the vararg array is never null
+ when (parameter.origin) {
+ Origin.KOTLIN, Origin.KOTLIN_LIB -> makeNonNullable()
+ else -> makeNullable()
+ }
+ }
} else {
type
}
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 5627679..707b085 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
@@ -82,14 +82,17 @@
}
}
+ internal val isKsp2 by lazy {
+ delegate.kspVersion >= KotlinVersion(2, 0)
+ }
+
private val ksFileMemberContainers = mutableMapOf<KSFile, KspFileMemberContainer>()
/**
* Variance resolver to find JVM types of KSType. See [KSTypeVarianceResolver] docs for details.
*/
- private val ksTypeVarianceResolver by lazy {
- KSTypeVarianceResolver(resolver)
- }
+ private val ksTypeVarianceResolver
+ get() = KSTypeVarianceResolver(resolver)
private var _resolver: Resolver? = null
@@ -125,15 +128,11 @@
override val messager: XMessager = KspMessager(logger)
- private val arrayTypeFactory by lazy {
- KspArrayType.Factory(this)
- }
+ private val arrayTypeFactory
+ get() = KspArrayType.Factory(this)
override val filer: XFiler = KspFiler(codeGenerator, messager)
- val commonTypes
- get() = CommonTypes()
-
val voidType
get() = KspVoidType(
env = this,
@@ -384,10 +383,6 @@
return returnType(type1).isSameType(returnType(type2))
}
- inner class CommonTypes() {
- val anyType: XType = requireType("kotlin.Any")
- }
-
internal enum class JvmDefaultMode(val option: String) {
DISABLE("disable"),
ALL_COMPATIBILITY("all-compatibility"),
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
index 18ce9fa..d9a5710 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
@@ -113,7 +113,8 @@
}
override val superTypes: List<XType> by lazy {
- if (xTypeName == XTypeName.ANY_OBJECT) {
+ val anyType = env.requireType(Any::class)
+ if (this == anyType) {
// The object class doesn't have any supertypes.
return@lazy emptyList<XType>()
}
@@ -125,16 +126,16 @@
env.wrap(
ksType = resolveTypeArguments(it.resolve(), resolvedTypeArguments),
allowPrimitives = false
- )
+ ).makeNonNullable()
} ?: emptyList()
val (superClasses, superInterfaces) = superTypes.partition {
it.typeElement?.isClass() == true
}
// Per documentation, always return the class before the interfaces.
if (superClasses.isEmpty()) {
- // Return Object when there's no explicit super class specified on the class/interface.
- // This matches javac's Types#directSupertypes().
- listOf(env.requireType(TypeName.OBJECT)) + superInterfaces
+ // Return Any / Object when there's no explicit super class specified on the\
+ // class/interface. This matches javac's Types#directSupertypes().
+ listOf(anyType) + superInterfaces
} else {
check(superClasses.size == 1) {
"Class ${this.typeName} should have only one super class. Found" +
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
index 93b7fb7..99c141a 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
@@ -102,27 +102,28 @@
}
override val superClass: XType? by lazy {
+ val anyTypeElement = env.requireTypeElement(Any::class)
if (isInterface()) {
// interfaces don't have super classes (they do have super types)
null
- } else if (this == env.commonTypes.anyType.typeElement) {
+ } else if (this == anyTypeElement) {
null
} else {
declaration.superTypes
.singleOrNull {
val declaration = it.resolve().declaration.replaceTypeAliases()
declaration is KSClassDeclaration && declaration.classKind == ClassKind.CLASS
- }?.let { env.wrap(it) }
- ?: env.commonTypes.anyType
+ }?.let { env.wrap(it).makeNonNullable() }
+ ?: anyTypeElement.type
}
}
override val superInterfaces by lazy {
- declaration.superTypes.asSequence()
+ declaration.superTypes
.filter {
val declaration = it.resolve().declaration.replaceTypeAliases()
declaration is KSClassDeclaration && declaration.classKind == ClassKind.INTERFACE
- }.mapTo(mutableListOf()) { env.wrap(it) }
+ }.mapTo(mutableListOf()) { env.wrap(it).makeNonNullable() }
}
@Deprecated(
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
index 3f57122..f6ffe01 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
@@ -125,7 +125,8 @@
override val thrownTypes: List<XType> by lazy {
env.resolver.getJvmCheckedException(accessor).map {
env.wrap(
- ksType = it,
+ // Thrown exception types are never nullable
+ ksType = it.makeNotNullable(),
allowPrimitives = false
)
}.toList()
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt
index 46e753d..be10792 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt
@@ -18,7 +18,6 @@
import androidx.kruth.assertThat
import androidx.room.compiler.codegen.JArrayTypeName
-import androidx.room.compiler.processing.compat.XConverters.toKS
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.XTestInvocation
import androidx.room.compiler.processing.util.asJClassName
@@ -1284,45 +1283,40 @@
)
val kClassKTypeName = kotlin.reflect.KClass::class.asKClassName().parameterizedBy(STAR)
fun checkSingleValue(annotationValue: XAnnotationValue, expectedValue: String) {
- // TODO(bcorso): Consider making the value types match in this case.
- if (!invocation.isKsp ||
- (invocation.processingEnv.toKS().kspVersion < KotlinVersion(2, 0) &&
- sourceKind == SourceKind.JAVA &&
- !isPreCompiled)) {
- assertThat(annotationValue.valueType.asTypeName().java)
- .isEqualTo(classJTypeName)
- } else {
+ if (invocation.isKsp) {
assertThat(annotationValue.valueType.asTypeName().java)
.isEqualTo(kClassJTypeName)
assertThat(annotationValue.valueType.asTypeName().kotlin)
.isEqualTo(kClassKTypeName)
+ } else {
+ assertThat(annotationValue.valueType.asTypeName().java)
+ .isEqualTo(classJTypeName)
}
assertThat(annotationValue.hasTypeValue()).isTrue()
assertThat(annotationValue.asType().typeElement?.name).isEqualTo(expectedValue)
}
fun checkListValues(annotationValue: XAnnotationValue, vararg expectedValues: String) {
- // TODO(bcorso): Consider making the value types match in this case.
- if (!invocation.isKsp ||
- (invocation.processingEnv.toKS().kspVersion < KotlinVersion(2, 0) &&
- sourceKind == SourceKind.JAVA &&
- !isPreCompiled)) {
- assertThat(annotationValue.valueType.asTypeName().java)
- .isEqualTo(JArrayTypeName.of(classJTypeName))
- } else {
+ if (invocation.isKsp) {
assertThat(annotationValue.valueType.asTypeName().java)
.isEqualTo(JArrayTypeName.of(kClassJTypeName))
if (sourceKind == SourceKind.KOTLIN &&
- annotationValue.name.contains("VarArgs")) {
+ annotationValue.name.contains("VarArgs")
+ ) {
// Kotlin vararg are producers
assertThat(annotationValue.valueType.asTypeName().kotlin)
- .isEqualTo(ARRAY.parameterizedBy(
- KWildcardTypeName.producerOf(kClassKTypeName))
+ .isEqualTo(
+ ARRAY.parameterizedBy(
+ KWildcardTypeName.producerOf(kClassKTypeName)
+ )
)
} else {
assertThat(annotationValue.valueType.asTypeName().kotlin)
.isEqualTo(ARRAY.parameterizedBy(kClassKTypeName))
}
+ } else {
+ assertThat(annotationValue.valueType.asTypeName().java)
+ .isEqualTo(JArrayTypeName.of(classJTypeName))
}
assertThat(annotationValue.hasTypeListValue()).isTrue()
// Check the list of values
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XArrayTypeTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XArrayTypeTest.kt
index d37d558..0f5ca1c 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XArrayTypeTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XArrayTypeTest.kt
@@ -19,7 +19,8 @@
import androidx.kruth.assertThat
import androidx.kruth.assertWithMessage
import androidx.room.compiler.codegen.JArrayTypeName
-import androidx.room.compiler.processing.compat.XConverters.toKS
+import androidx.room.compiler.codegen.XTypeName
+import androidx.room.compiler.codegen.asClassName
import androidx.room.compiler.processing.ksp.KspProcessingEnv
import androidx.room.compiler.processing.ksp.createTypeReference
import androidx.room.compiler.processing.util.Source
@@ -55,25 +56,21 @@
.getField("param")
.type
assertThat(type.isArray()).isTrue()
- assertThat(type.asTypeName().java).isEqualTo(
- JArrayTypeName.of(String::class.java)
+ val arrComponentTypeName = if (
+ invocation.isKsp &&
+ (invocation.processingEnv as KspProcessingEnv).isKsp2
+ ) {
+ XTypeName.getProducerExtendsName(String::class.asClassName())
+ } else {
+ String::class.asClassName()
+ }.copy(nullable = true)
+ assertThat(type.asTypeName()).isEqualTo(
+ XTypeName.getArrayName(arrComponentTypeName).copy(nullable = true)
)
- if (invocation.isKsp) {
- assertThat(type.asTypeName().kotlin).isEqualTo(
- if (invocation.processingEnv.toKS().kspVersion >= KotlinVersion(2, 0)) {
- com.squareup.kotlinpoet.ARRAY.parameterizedBy(
- KWildcardTypeName.producerOf(String::class.asKTypeName()))
- } else {
- com.squareup.kotlinpoet.ARRAY.parameterizedBy(String::class.asKTypeName())
- }
- )
- }
check(type.isArray())
type.componentType.let { component ->
- assertThat(component.asTypeName().java).isEqualTo(String::class.asJTypeName())
- if (invocation.isKsp) {
- assertThat(component.asTypeName().kotlin).isEqualTo(String::class.asKTypeName())
- }
+ assertThat(component.asTypeName())
+ .isEqualTo(String::class.asClassName().copy(nullable = true))
assertThat(component.nullability).isEqualTo(XNullability.UNKNOWN)
}
}
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XElementTest.kt
index 9a83501..38933b7 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XElementTest.kt
@@ -266,7 +266,7 @@
)
validateMethodTypeAsMemberOf(
element = it.processingEnv.requireTypeElement("foo.bar.Child"),
- tTypeName = String::class.asClassName(),
+ tTypeName = String::class.asClassName().copy(nullable = true),
rTypeName = XTypeName.getTypeVariableName("R", listOf(
XTypeName.ANY_OBJECT.copy(nullable = true)))
)
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
index 77161da..55020b7 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
@@ -20,7 +20,7 @@
import androidx.kruth.assertWithMessage
import androidx.room.compiler.codegen.XTypeName
import androidx.room.compiler.codegen.asClassName
-import androidx.room.compiler.processing.compat.XConverters.toKS
+import androidx.room.compiler.processing.ksp.KspProcessingEnv
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
@@ -89,10 +89,11 @@
val paramType = param.type
check(paramType.isArray())
assertThat(paramType.componentType.asTypeName())
- .isEqualTo(String::class.asClassName())
+ .isEqualTo(String::class.asClassName().copy(nullable = true))
assertThat(param.enclosingElement).isEqualTo(method)
}
- assertThat(method.returnType.asTypeName()).isEqualTo(String::class.asClassName())
+ assertThat(method.returnType.asTypeName())
+ .isEqualTo(String::class.asClassName().copy(nullable = true))
}
element.getConstructors().single().let { ctor ->
assertThat(ctor.parameters).hasSize(1)
@@ -120,12 +121,16 @@
element.getMethodByJvmName("method").let { method ->
assertThat(method.isVarArgs()).isTrue()
assertThat(method.parameters.single().type.asTypeName()).isEqualTo(
- XTypeName.getArrayName(String::class.asClassName()))
+ XTypeName.getArrayName(
+ String::class.asClassName().copy(nullable = true)
+ ).copy(nullable = true)
+ )
}
element.getMethodByJvmName("methodPrimitive").let { method ->
assertThat(method.isVarArgs()).isTrue()
assertThat(method.parameters.single().type.asTypeName()).isEqualTo(
- XTypeName.getArrayName(XTypeName.PRIMITIVE_INT))
+ XTypeName.getArrayName(XTypeName.PRIMITIVE_INT).copy(nullable = true)
+ )
}
}
}
@@ -808,13 +813,13 @@
val elm = invocation.processingEnv.requireTypeElement("JavaImpl")
assertThat(
elm.getMethodByJvmName("getX").returnType.asTypeName()
- ).isEqualTo(Int::class.asClassName())
+ ).isEqualTo(Int::class.asClassName().copy(nullable = true))
assertThat(
elm.getMethodByJvmName("getY").returnType.asTypeName()
- ).isEqualTo(Int::class.asClassName())
+ ).isEqualTo(Int::class.asClassName().copy(nullable = true))
assertThat(
elm.getMethodByJvmName("setY").parameters.first().type.asTypeName()
- ).isEqualTo(Int::class.asClassName())
+ ).isEqualTo(Int::class.asClassName().copy(nullable = true))
}
}
@@ -1477,9 +1482,7 @@
assertThat(parameterName).isEqualTo("param1")
} else {
if (it.isKsp) {
- if (hasDebugFlag &&
- it.processingEnv.toKS().kspVersion >=
- KotlinVersion(2, 0)) {
+ if (hasDebugFlag && (it.processingEnv as KspProcessingEnv).isKsp2) {
if (isAbstract || isJavaNative) {
assertThat(parameterName).isEqualTo("p0")
} else {
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XNullabilityTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XNullabilityTest.kt
index 165deab..9e873e7 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XNullabilityTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XNullabilityTest.kt
@@ -29,7 +29,6 @@
import com.squareup.kotlinpoet.INT
import com.squareup.kotlinpoet.UNIT
import com.squareup.kotlinpoet.javapoet.JTypeName
-import org.junit.Assert.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -320,15 +319,7 @@
assertThat(it.nullability).isEqualTo(NULLABLE)
}
if (invocation.isKsp) {
- assertThat(typeArg.asTypeName().kotlin).isEqualTo(
- when (it) {
- "KotlinClass" -> INT.copy(nullable = true)
- // A type arg from Java has unknown nullability,
- // so name defaults to not-null
- "JavaClass" -> INT
- else -> fail("Unknown src $it")
- }
- )
+ assertThat(typeArg.asTypeName().kotlin).isEqualTo(INT.copy(nullable = true))
typeArg.makeNonNullable().let {
assertThat(it.asTypeName().kotlin).isEqualTo(INT)
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
index f1dfb5f..84d6cd4 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
@@ -21,8 +21,8 @@
import androidx.room.compiler.codegen.XClassName
import androidx.room.compiler.codegen.XTypeName
import androidx.room.compiler.codegen.asClassName
-import androidx.room.compiler.processing.compat.XConverters.toKS
import androidx.room.compiler.processing.javac.JavacType
+import androidx.room.compiler.processing.ksp.KspProcessingEnv
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.XTestInvocation
import androidx.room.compiler.processing.util.asKClassName
@@ -1889,9 +1889,7 @@
// TODO(kuanyingchou): https://github.com/google/ksp/issues/1761
val parent = typeElement.superClass!!.typeElement!!
if (qName == "test.KotlinEnum" && !isPreCompiled && invocation.isKsp) {
- if (invocation.isKsp &&
- invocation.processingEnv.toKS().kspVersion >=
- KotlinVersion(2, 0)) {
+ if (invocation.isKsp && (invocation.processingEnv as KspProcessingEnv).isKsp2) {
assertThat(parent.asClassName()).isEqualTo(XTypeName.ENUM)
} else {
assertThat(parent.asClassName()).isEqualTo(Any::class.asClassName())
@@ -1903,17 +1901,19 @@
val methodNames = typeElement.getDeclaredMethods().map { it.jvmName }
if (qName == "test.KotlinEnum") {
if (invocation.isKsp) {
- if (!isPreCompiled && invocation.processingEnv.toKS().kspVersion <
- KotlinVersion(2, 0)) {
- assertThat(methodNames).containsExactly(
- "enumMethod",
- )
- } else {
+ if (
+ isPreCompiled ||
+ (invocation.processingEnv as KspProcessingEnv).isKsp2
+ ) {
assertThat(methodNames).containsExactly(
"enumMethod",
"values",
"valueOf",
)
+ } else {
+ assertThat(methodNames).containsExactly(
+ "enumMethod",
+ )
}
} else {
assertThat(methodNames).containsExactly(
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
index 30422ec..7662e9f 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
@@ -19,6 +19,7 @@
import androidx.kruth.assertThat
import androidx.kruth.assertWithMessage
import androidx.room.compiler.codegen.XClassName
+import androidx.room.compiler.codegen.XTypeName
import androidx.room.compiler.codegen.XTypeName.Companion.ANY_OBJECT
import androidx.room.compiler.codegen.XTypeName.Companion.UNAVAILABLE_KTYPE_NAME
import androidx.room.compiler.processing.ksp.ERROR_JTYPE_NAME
@@ -144,7 +145,7 @@
)
if (it.isKsp) {
assertThat(wildcardParam.type.asTypeName().kotlin).isEqualTo(
- MUTABLE_SET.parameterizedBy(STAR)
+ MUTABLE_SET.parameterizedBy(STAR).copy(nullable = true)
)
assertThat(extendsBoundOrSelf.rawType)
.isEqualTo(
@@ -165,7 +166,7 @@
)
if (it.isKsp) {
assertThat(rawParamType.type.asTypeName().kotlin).isEqualTo(
- KClassName("kotlin.collections", "MutableSet")
+ KClassName("kotlin.collections", "MutableSet").copy(nullable = true)
)
}
}
@@ -180,8 +181,8 @@
if (it.isKsp) {
assertThat(rawParamTypeArgument.type.asTypeName().kotlin).isEqualTo(
KClassName("kotlin.collections", "MutableList").parameterizedBy(
- KClassName("kotlin.collections", "MutableSet")
- )
+ KClassName("kotlin.collections", "MutableSet").copy(nullable = true)
+ ).copy(nullable = true)
)
}
val rawTypeArgument = rawParamTypeArgument.type.typeArguments.single()
@@ -190,7 +191,7 @@
)
if (it.isKsp) {
assertThat(rawTypeArgument.asTypeName().kotlin).isEqualTo(
- KClassName("kotlin.collections", "MutableSet")
+ KClassName("kotlin.collections", "MutableSet").copy(nullable = true)
)
}
}
@@ -628,22 +629,19 @@
val expectedTypeStringDumpKotlin = """
SelfReferencing<T>
| T
- | > SelfReferencing<T>?
- | > | T
- | > | > SelfReferencing<T>?
- | > | > | T
+ | > SelfReferencing<T?>?
+ | > | T?
+ | > | > SelfReferencing<T?>?
+ | > | > | T?
""".trimIndent()
assertThat(typeElement.type.asTypeName().kotlin.dumpToString(5))
.isEqualTo(expectedTypeStringDumpKotlin)
}
- val expectedParamStringDump = """
- SelfReferencing
- """.trimIndent()
assertThat(parameter.type.asTypeName().java.dumpToString(5))
- .isEqualTo(expectedParamStringDump)
+ .isEqualTo("SelfReferencing")
if (invocation.isKsp) {
assertThat(parameter.type.asTypeName().kotlin.dumpToString(5))
- .isEqualTo(expectedParamStringDump)
+ .isEqualTo("SelfReferencing?")
}
}
}
@@ -1381,38 +1379,48 @@
@Test
fun getWildcardType() {
- fun XTestInvocation.checkType() {
+ fun XTestInvocation.checkType(isJavaSrc: Boolean) {
val usageElement = processingEnv.requireTypeElement("test.Usage")
val fooElement = processingEnv.requireTypeElement("test.Foo")
- val barType = processingEnv.requireType("test.Bar")
+ val barType = processingEnv.requireType("test.Bar").run {
+ if (isJavaSrc) makeNullable() else makeNonNullable()
+ }
// Test a manually constructed Foo<Bar>
- val fooBarType = processingEnv.getDeclaredType(fooElement, barType)
+ val fooBarType = processingEnv.getDeclaredType(fooElement, barType).run {
+ if (isJavaSrc) makeNullable() else makeNonNullable()
+ }
val fooBarUsageType = usageElement.getDeclaredField("fooBar").type
- assertThat(fooBarType.asTypeName()).isEqualTo(fooBarUsageType.asTypeName())
+ assertThat(fooBarUsageType.asTypeName()).isEqualTo(fooBarType.asTypeName())
// Test a manually constructed Foo<? extends Bar>
val fooExtendsBarType = processingEnv.getDeclaredType(
fooElement,
processingEnv.getWildcardType(producerExtends = barType)
- )
+ ).run {
+ if (isJavaSrc) makeNullable() else makeNonNullable()
+ }
val fooExtendsBarUsageType = usageElement.getDeclaredField("fooExtendsBar").type
- assertThat(fooExtendsBarType.asTypeName())
- .isEqualTo(fooExtendsBarUsageType.asTypeName())
+ assertThat(fooExtendsBarUsageType.asTypeName())
+ .isEqualTo(fooExtendsBarType.asTypeName())
// Test a manually constructed Foo<? super Bar>
val fooSuperBarType = processingEnv.getDeclaredType(
fooElement,
processingEnv.getWildcardType(consumerSuper = barType)
- )
+ ).run {
+ if (isJavaSrc) makeNullable() else makeNonNullable()
+ }
val fooSuperBarUsageType = usageElement.getDeclaredField("fooSuperBar").type
- assertThat(fooSuperBarType.asTypeName()).isEqualTo(fooSuperBarUsageType.asTypeName())
+ assertThat(fooSuperBarUsageType.asTypeName()).isEqualTo(fooSuperBarType.asTypeName())
// Test a manually constructed Foo<?>
val fooUnboundedType = processingEnv.getDeclaredType(
fooElement,
processingEnv.getWildcardType()
- )
+ ).run {
+ if (isJavaSrc) makeNullable() else makeNonNullable()
+ }
val fooUnboundedUsageType = usageElement.getDeclaredField("fooUnbounded").type
assertThat(fooUnboundedType.asTypeName()).isEqualTo(fooUnboundedUsageType.asTypeName())
}
@@ -1430,10 +1438,10 @@
interface Foo<T> {}
interface Bar {}
""".trimIndent()
- ))) { it.checkType() }
+ ))) { it.checkType(isJavaSrc = true) }
runProcessorTest(listOf(Source.kotlin(
- "test.Usage.kt",
+ "Usage.kt",
"""
package test
class Usage {
@@ -1445,7 +1453,7 @@
interface Foo<T>
interface Bar
""".trimIndent()
- ))) { it.checkType() }
+ ))) { it.checkType(isJavaSrc = false) }
}
@Test
@@ -1599,45 +1607,87 @@
""".trimIndent()
)
runProcessorTest(sources = listOf(src)) { invocation ->
- fun assertHasTypeName(type: XType, expectedTypeName: String) {
- assertThat(type.asTypeName().java.toString()).isEqualTo(expectedTypeName)
- if (invocation.isKsp) {
- assertThat(type.asTypeName().kotlin.toString()).isEqualTo(expectedTypeName)
- }
+ val fooTypeName = XClassName.get("test", "Foo")
+ val barTypeName = XClassName.get("test", "Bar")
+
+ fun assertHasTypeName(type: XType, expectedTypeName: XTypeName) {
+ assertThat(type.asTypeName()).isEqualTo(expectedTypeName)
}
val subject = invocation.processingEnv.requireTypeElement("test.Subject")
- assertHasTypeName(subject.getDeclaredField("foo").type, "test.Foo")
- assertHasTypeName(subject.getDeclaredField("fooFoo").type, "test.Foo<test.Foo>")
assertHasTypeName(
- subject.getDeclaredField("fooFooFoo").type, "test.Foo<test.Foo<test.Foo>>")
+ type = subject.getDeclaredField("foo").type,
+ expectedTypeName = fooTypeName.copy(nullable = true)
+ )
assertHasTypeName(
- subject.getDeclaredField("barFooFoo").type, "test.Bar<test.Foo, test.Foo>")
+ type = subject.getDeclaredField("fooFoo").type,
+ expectedTypeName = fooTypeName.parametrizedBy(
+ fooTypeName.copy(nullable = true)
+ ).copy(nullable = true)
+ )
+ assertHasTypeName(
+ type = subject.getDeclaredField("fooFooFoo").type,
+ expectedTypeName = fooTypeName.parametrizedBy(
+ fooTypeName.parametrizedBy(
+ fooTypeName.copy(nullable = true)
+ ).copy(nullable = true)
+ ).copy(nullable = true)
+ )
+ assertHasTypeName(
+ type = subject.getDeclaredField("barFooFoo").type,
+ expectedTypeName = barTypeName.parametrizedBy(
+ fooTypeName.copy(nullable = true), fooTypeName.copy(nullable = true)
+ ).copy(nullable = true)
+ )
// Test manually wrapping raw type using XProcessingEnv#getDeclaredType()
subject.getDeclaredField("foo").type.let { foo ->
val fooTypeElement = invocation.processingEnv.requireTypeElement("test.Foo")
val fooFoo: XType = invocation.processingEnv.getDeclaredType(fooTypeElement, foo)
- assertHasTypeName(fooFoo, "test.Foo<test.Foo>")
+ assertHasTypeName(
+ type = fooFoo,
+ expectedTypeName = fooTypeName.parametrizedBy(
+ fooTypeName.copy(nullable = true)
+ )
+ )
val fooFooFoo: XType =
invocation.processingEnv.getDeclaredType(fooTypeElement, fooFoo)
- assertHasTypeName(fooFooFoo, "test.Foo<test.Foo<test.Foo>>")
+ assertHasTypeName(
+ type = fooFooFoo,
+ expectedTypeName = fooTypeName.parametrizedBy(
+ fooTypeName.parametrizedBy(fooTypeName.copy(nullable = true))
+ )
+ )
val barTypeElement = invocation.processingEnv.requireTypeElement("test.Bar")
val barFooFoo: XType =
invocation.processingEnv.getDeclaredType(barTypeElement, foo, foo)
- assertHasTypeName(barFooFoo, "test.Bar<test.Foo, test.Foo>")
+ assertHasTypeName(
+ type = barFooFoo,
+ expectedTypeName = barTypeName.parametrizedBy(
+ fooTypeName.copy(nullable = true), fooTypeName.copy(nullable = true)
+ )
+ )
}
// Test manually unwrapping a type with a raw type argument:
subject.getDeclaredField("fooFoo").type.let { fooFoo ->
- assertHasTypeName(fooFoo.typeArguments.single(), "test.Foo")
+ assertHasTypeName(
+ type = fooFoo.typeArguments.single(),
+ expectedTypeName = fooTypeName.copy(nullable = true)
+ )
}
subject.getDeclaredField("barFooFoo").type.let { barFooFoo ->
assertThat(barFooFoo.typeArguments).hasSize(2)
- assertHasTypeName(barFooFoo.typeArguments[0], "test.Foo")
- assertHasTypeName(barFooFoo.typeArguments[1], "test.Foo")
+ assertHasTypeName(
+ type = barFooFoo.typeArguments[0],
+ expectedTypeName = fooTypeName.copy(nullable = true)
+ )
+ assertHasTypeName(
+ type = barFooFoo.typeArguments[1],
+ expectedTypeName = fooTypeName.copy(nullable = true)
+ )
}
}
}
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt
index 0bb58a2..84acf17 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt
@@ -605,13 +605,11 @@
JClassName.get("java.lang", "Number")
)
if (invocation.isKsp) {
+ val numberKClassName = KClassName("kotlin", "Number").copy(nullable = true)
assertThat(arg1.asTypeName().kotlin)
- .isEqualTo(
- KWildcardTypeName.producerOf(Number::class)
- )
- assertThat(arg1.extendsBound()?.asTypeName()?.kotlin).isEqualTo(
- KClassName("kotlin", "Number")
- )
+ .isEqualTo(KWildcardTypeName.producerOf(numberKClassName))
+ assertThat(arg1.extendsBound()?.asTypeName()?.kotlin)
+ .isEqualTo(numberKClassName)
}
assertThat(
arg1.extendsBound()?.extendsBound()