Improve Ksp isSameType & error types
This CL fixes two issues:
* isSameType in KSP was not working as Room expects for platform types.
We still want it to consider nullability for kotlin types but for types
coming from Java (or .class w/ nullability), we use flexible equality
the same way kotlin does.
We may eventually change how isSameType works as it is not always clear
whether it expects exact equality with nullability or without
nullability.
* We were losing error types by eagerly calling `asMemberOf` which loses
that information. https://github.com/google/ksp/issues/107
To workaround it, we don't call asMemberOf if the type resolution
returns an error type.
I've also updated KspTypeTests to use the XProcessing classes to ensure
they go through the same expected path (which revelaed the asMemberOf
bug). They are still not running w/ KAPT because some things like
wildcard handling changes. I'll do that in a followup.
Bug: 160322705
Bug: 175246617
Test: XTypeTest, KspTypeTest
Change-Id: Ibd241456e4f402e5bc2b9002511ff59b7fab08e2
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSAsMemberOf.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSAsMemberOf.kt
index 6c230d8..7e84d7c 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSAsMemberOf.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSAsMemberOf.kt
@@ -26,10 +26,17 @@
* Returns the type of a property as if it is member of the given [ksType].
*/
internal fun KSPropertyDeclaration.typeAsMemberOf(resolver: Resolver, ksType: KSType): KSType {
+ val resolved = type.resolve()
if (isStatic()) {
// calling as member with a static would throw as it might be a member of the companion
// object
- return type.resolve()
+ return resolved
+ }
+ // see: https://github.com/google/ksp/issues/107
+ // as member of might lose the `isError` information hence we should check before calling
+ // asMemberOf.
+ if (resolved.isError) {
+ return resolved
}
return resolver.asMemberOf(
property = this,
@@ -42,10 +49,17 @@
functionDeclaration: KSFunctionDeclaration,
ksType: KSType
): KSType {
+ val resolved = type.resolve()
if (functionDeclaration.isStatic()) {
// calling as member with a static would throw as it might be a member of the companion
// object
- return type.resolve()
+ return resolved
+ }
+ if (resolved.isError) {
+ // see: https://github.com/google/ksp/issues/107
+ // as member of might lose the `isError` information hence we should check before calling
+ // asMemberOf.
+ return resolved
}
val asMember = resolver.asMemberOf(
function = functionDeclaration,
@@ -54,22 +68,25 @@
// TODO b/173224718
// this is counter intuitive, we should remove asMemberOf from method parameters.
val myIndex = functionDeclaration.parameters.indexOf(this)
- return asMember.parameterTypes[myIndex] ?: type.resolve()
+ return asMember.parameterTypes[myIndex] ?: resolved
}
internal fun KSFunctionDeclaration.returnTypeAsMemberOf(
resolver: Resolver,
ksType: KSType
): KSType {
- val returnType = if (isStatic()) {
- // calling as member with a static would throw as it might be a member of the companion
- // object
- returnType?.resolve()
- } else {
- resolver.asMemberOf(
+ val resolved = returnType?.resolve()
+ return when {
+ resolved == null -> null
+ resolved.isError -> resolved
+ isStatic() -> {
+ // calling as member with a static would throw as it might be a member of the companion
+ // object
+ resolved
+ }
+ else -> resolver.asMemberOf(
function = this,
containing = ksType
).returnType
- }
- return returnType ?: error("cannot find return type for $this")
+ } ?: error("cannot find return type for $this")
}
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
index 1292542..c60d55a 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
@@ -125,6 +125,11 @@
override fun isSameType(other: XType): Boolean {
check(other is KspType)
+ if (nullability == XNullability.UNKNOWN || other.nullability == XNullability.UNKNOWN) {
+ // if one the nullabilities is unknown, it is coming from java source code or .class.
+ // for those cases, use java platform type equality (via typename)
+ return typeName == other.typeName
+ }
// NOTE: this is inconsistent with java where nullability is ignored.
// it is intentional but might be reversed if it happens to break use cases.
return ksType == other.ksType
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
index 4aa8ac9..814425b 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
@@ -16,6 +16,7 @@
package androidx.room.compiler.processing
+import androidx.room.compiler.processing.ksp.ERROR_TYPE_NAME
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.className
import androidx.room.compiler.processing.util.getDeclaredMethod
@@ -24,7 +25,6 @@
import androidx.room.compiler.processing.util.javaElementUtils
import androidx.room.compiler.processing.util.kspResolver
import androidx.room.compiler.processing.util.runKspTest
-import androidx.room.compiler.processing.util.runProcessorTestWithoutKsp
import androidx.room.compiler.processing.util.runProcessorTest
import androidx.room.compiler.processing.util.typeName
import com.google.common.truth.Truth
@@ -110,22 +110,24 @@
""".trimIndent()
)
- // enable KSP once https://github.com/google/ksp/issues/107 is fixed.
- runProcessorTestWithoutKsp(
+ runProcessorTest(
sources = listOf(missingTypeRef)
) {
+ val errorTypeName = if (it.isKsp) {
+ // in ksp, we lose the name when resolving the type.
+ // b/175246617
+ ERROR_TYPE_NAME
+ } else {
+ ClassName.get("", "NotExistingType")
+ }
val element = it.processingEnv.requireTypeElement("foo.bar.Baz")
element.getField("badField").let { field ->
assertThat(field.type.isError()).isTrue()
- assertThat(field.type.typeName).isEqualTo(
- ClassName.get("", "NotExistingType")
- )
+ assertThat(field.type.typeName).isEqualTo(errorTypeName)
}
element.getDeclaredMethod("badMethod").let { method ->
assertThat(method.returnType.isError()).isTrue()
- assertThat(method.returnType.typeName).isEqualTo(
- ClassName.get("", "NotExistingType")
- )
+ assertThat(method.returnType.typeName).isEqualTo(errorTypeName)
}
it.assertCompilationResult {
compilationDidFail()
@@ -157,6 +159,56 @@
}
@Test
+ fun sameType_kotlinJava() {
+ val javaSrc = Source.java(
+ "JavaClass",
+ """
+ class JavaClass {
+ int intField;
+ Integer integerField;
+ }
+ """.trimIndent()
+ )
+ val kotlinSrc = Source.kotlin(
+ "Foo.kt",
+ """
+ class KotlinClass {
+ val intProp: Int = 0
+ val integerProp : Int? = null
+ }
+ """.trimIndent()
+ )
+ runProcessorTest(
+ sources = listOf(javaSrc, kotlinSrc)
+ ) { invocation ->
+ val javaElm = invocation.processingEnv.requireTypeElement("JavaClass")
+ val kotlinElm = invocation.processingEnv.requireTypeElement("KotlinClass")
+ fun XFieldElement.isSameType(other: XFieldElement): Boolean {
+ return type.isSameType(other.type)
+ }
+ val fields = javaElm.getAllFieldsIncludingPrivateSupers() +
+ kotlinElm.getAllFieldsIncludingPrivateSupers()
+ val results = fields.flatMap { f1 ->
+ fields.map { f2 ->
+ f1 to f2
+ }.filter { (first, second) ->
+ first.isSameType(second)
+ }
+ }.map { (first, second) ->
+ first.name to second.name
+ }
+
+ val expected = setOf(
+ "intField" to "intProp",
+ "intProp" to "intField",
+ "integerField" to "integerProp",
+ "integerProp" to "integerField"
+ ) + fields.map { it.name to it.name }.toSet()
+ assertThat(results).containsExactlyElementsIn(expected)
+ }
+ }
+
+ @Test
fun isCollection() {
runProcessorTest {
it.processingEnv.requireType("java.util.List").let { list ->
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt
index 7643b04..8609c80 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt
@@ -18,19 +18,21 @@
import androidx.room.compiler.processing.XNullability.NONNULL
import androidx.room.compiler.processing.XNullability.NULLABLE
+import androidx.room.compiler.processing.asDeclaredType
import androidx.room.compiler.processing.isDeclared
import androidx.room.compiler.processing.util.Source
-import androidx.room.compiler.processing.util.XTestInvocation
import androidx.room.compiler.processing.util.className
+import androidx.room.compiler.processing.util.getField
+import androidx.room.compiler.processing.util.getMethod
import androidx.room.compiler.processing.util.kspResolver
import androidx.room.compiler.processing.util.runKspTest
import androidx.room.compiler.processing.util.typeName
import com.google.common.truth.Truth.assertThat
import com.google.devtools.ksp.getClassDeclarationByName
import com.google.devtools.ksp.getDeclaredFunctions
-import com.google.devtools.ksp.symbol.KSPropertyDeclaration
import com.squareup.javapoet.ClassName
import com.squareup.javapoet.TypeName
+import com.squareup.javapoet.TypeVariableName
import com.squareup.javapoet.WildcardTypeName
import org.junit.Test
import org.junit.runner.RunWith
@@ -83,22 +85,24 @@
val src = Source.kotlin(
"foo.kt",
"""
- package foo.bar;
- val errorType : IDontExist = TODO()
- val listOfErrorType : List<IDontExist> = TODO()
+ class Subject {
+ val errorType : IDontExist = TODO()
+ val listOfErrorType : List<IDontExist> = TODO()
+ }
""".trimIndent()
)
runKspTest(
listOf(src)
) { invocation ->
- invocation.requireDeclaredPropertyType("errorType").let { type ->
+ val subject = invocation.processingEnv.requireTypeElement("Subject")
+ subject.getField("errorType").type.asDeclaredType().let { type ->
assertThat(type.isError()).isTrue()
assertThat(type.typeArguments).isEmpty()
assertThat(type.typeName).isEqualTo(ERROR_TYPE_NAME)
assertThat(type.asTypeElement().className).isEqualTo(ERROR_TYPE_NAME)
}
- invocation.requireDeclaredPropertyType("listOfErrorType").let { type ->
+ subject.getField("listOfErrorType").type.asDeclaredType().let { type ->
assertThat(type.isError()).isFalse()
assertThat(type.typeArguments).hasSize(1)
type.typeArguments.single().let { typeArg ->
@@ -117,15 +121,17 @@
val src = Source.kotlin(
"foo.kt",
"""
- package foo.bar;
- val listOfNullableStrings : List<String?> = TODO()
- val listOfInts : List<Int> = TODO()
+ class Subject {
+ val listOfNullableStrings : List<String?> = TODO()
+ val listOfInts : List<Int> = TODO()
+ }
""".trimIndent()
)
runKspTest(
listOf(src)
) { invocation ->
- invocation.requireDeclaredPropertyType("listOfNullableStrings").let { type ->
+ val subject = invocation.processingEnv.requireTypeElement("Subject")
+ subject.getField("listOfNullableStrings").type.asDeclaredType().let { type ->
assertThat(type.nullability).isEqualTo(NONNULL)
assertThat(type.typeArguments).hasSize(1)
assertThat(type.asTypeElement().className).isEqualTo(
@@ -141,7 +147,7 @@
}
}
- invocation.requireDeclaredPropertyType("listOfInts").let { type ->
+ subject.getField("listOfInts").type.asDeclaredType().let { type ->
assertThat(type.nullability).isEqualTo(NONNULL)
assertThat(type.typeArguments).hasSize(1)
type.typeArguments.single().let { typeArg ->
@@ -164,34 +170,36 @@
val src = Source.kotlin(
"foo.kt",
"""
- package foo.bar;
- val listOfNullableStrings : List<String?> = TODO()
- val listOfNullableStrings_2 : List<String?> = TODO()
- val listOfNonNullStrings : List<String> = TODO()
- val listOfNonNullStrings_2 : List<String> = TODO()
- val nullableString : String? = TODO()
- val nonNullString : String = TODO()
+ class Subject {
+ val listOfNullableStrings : List<String?> = TODO()
+ val listOfNullableStrings_2 : List<String?> = TODO()
+ val listOfNonNullStrings : List<String> = TODO()
+ val listOfNonNullStrings_2 : List<String> = TODO()
+ val nullableString : String? = TODO()
+ val nonNullString : String = TODO()
+ }
""".trimIndent()
)
runKspTest(
listOf(src)
) { invocation ->
- val nullableStringList = invocation
- .requireDeclaredPropertyType("listOfNullableStrings")
- val nonNullStringList = invocation
- .requireDeclaredPropertyType("listOfNonNullStrings")
+ val subject = invocation.processingEnv.requireTypeElement("Subject")
+ val nullableStringList = subject.getField("listOfNullableStrings")
+ .type.asDeclaredType()
+ val nonNullStringList = subject.getField("listOfNonNullStrings")
+ .type.asDeclaredType()
assertThat(nullableStringList).isNotEqualTo(nonNullStringList)
assertThat(nonNullStringList).isNotEqualTo(nullableStringList)
- val nullableStringList_2 = invocation
- .requireDeclaredPropertyType("listOfNullableStrings_2")
- val nonNullStringList_2 = invocation
- .requireDeclaredPropertyType("listOfNonNullStrings_2")
+ val nullableStringList_2 = subject.getField("listOfNullableStrings_2")
+ .type.asDeclaredType()
+ val nonNullStringList_2 = subject.getField("listOfNonNullStrings_2")
+ .type.asDeclaredType()
assertThat(nullableStringList).isEqualTo(nullableStringList_2)
assertThat(nonNullStringList).isEqualTo(nonNullStringList_2)
- val nullableString = invocation.requirePropertyType("nullableString")
- val nonNullString = invocation.requirePropertyType("nonNullString")
+ val nullableString = subject.getField("nullableString").type
+ val nonNullString = subject.getField("nonNullString").type
assertThat(nullableString).isEqualTo(
nullableStringList.typeArguments.single()
)
@@ -212,32 +220,34 @@
val src = Source.kotlin(
"foo.kt",
"""
- package foo.bar;
- val simple : Int = 0
- val list : List<String> = TODO()
- val map : Map<String, String> = TODO()
- val listOfMaps : List<Map<String, String>> = TODO()
+ class Subject {
+ val simple : Int = 0
+ val list : List<String> = TODO()
+ val map : Map<String, String> = TODO()
+ val listOfMaps : List<Map<String, String>> = TODO()
+ }
""".trimIndent()
)
runKspTest(
listOf(src)
) { invocation ->
- invocation.requirePropertyType("simple").let {
+ val subject = invocation.processingEnv.requireTypeElement("Subject")
+ subject.getField("simple").type.let {
assertThat(it.rawType.typeName).isEqualTo(TypeName.INT)
}
- invocation.requireDeclaredPropertyType("list").let { list ->
+ subject.getField("list").type.asDeclaredType().let { list ->
assertThat(list.rawType).isNotEqualTo(list)
assertThat(list.typeArguments).isNotEmpty()
assertThat(list.rawType.typeName)
.isEqualTo(ClassName.get("java.util", "List"))
}
- invocation.requireDeclaredPropertyType("map").let { map ->
+ subject.getField("map").type.asDeclaredType().let { map ->
assertThat(map.rawType).isNotEqualTo(map)
assertThat(map.typeArguments).hasSize(2)
assertThat(map.rawType.typeName)
.isEqualTo(ClassName.get("java.util", "Map"))
}
- invocation.requireDeclaredPropertyType("listOfMaps").let { listOfMaps ->
+ subject.getField("listOfMaps").type.asDeclaredType().let { listOfMaps ->
assertThat(listOfMaps.rawType).isNotEqualTo(listOfMaps)
assertThat(listOfMaps.typeArguments).hasSize(1)
}
@@ -277,20 +287,23 @@
val src = Source.kotlin(
"foo.kt",
"""
- val intProp : Int = 0
- val nullableIntProp : Int? = null
- val longProp : Long = 0
- val nullableLongProp : Long? = null
- val byteProp : Byte = 0
- val nullableByteProp :Byte? = null
- val errorProp : IDontExist = TODO()
- val nullableErrorProp : IDontExist? = TODO()
+ class Subject {
+ val intProp : Int = 0
+ val nullableIntProp : Int? = null
+ val longProp : Long = 0
+ val nullableLongProp : Long? = null
+ val byteProp : Byte = 0
+ val nullableByteProp :Byte? = null
+ val errorProp : IDontExist = TODO()
+ val nullableErrorProp : IDontExist? = TODO()
+ }
""".trimIndent()
)
runKspTest(
listOf(src)
) { invocation ->
- fun mapProp(name: String) = invocation.requirePropertyType(name).let {
+ val subject = invocation.processingEnv.requireTypeElement("Subject")
+ fun mapProp(name: String) = subject.getField(name).type.let {
listOf(
"isInt" to it.isInt(),
"isLong" to it.isLong(),
@@ -322,22 +335,25 @@
val src = Source.kotlin(
"foo.kt",
"""
- val intProp : Int = 3 // kotlin default value is unrelated, will be ignored
- val nullableIntProp : Int? = null
- val longProp : Long = 3
- val nullableLongProp : Long? = null
- val floatProp = 3f
- val byteProp : Byte = 0
- val nullableByteProp :Byte? = null
- val errorProp : IDontExist = TODO()
- val nullableErrorProp : IDontExist? = TODO()
- val stringProp : String = "abc"
+ class Subject {
+ val intProp : Int = 3 // kotlin default value is unrelated, will be ignored
+ val nullableIntProp : Int? = null
+ val longProp : Long = 3
+ val nullableLongProp : Long? = null
+ val floatProp = 3f
+ val byteProp : Byte = 0
+ val nullableByteProp :Byte? = null
+ val errorProp : IDontExist = TODO()
+ val nullableErrorProp : IDontExist? = TODO()
+ val stringProp : String = "abc"
+ }
""".trimIndent()
)
runKspTest(
listOf(src)
) { invocation ->
- fun getDefaultValue(name: String) = invocation.requirePropertyType(name).defaultValue()
+ val subject = invocation.processingEnv.requireTypeElement("Subject")
+ fun getDefaultValue(name: String) = subject.getField(name).type.defaultValue()
// javac types do not check nullability but checking it is more correct
// since KSP is an opt-in by the developer, it is better for it to be more strict about
// types.
@@ -362,42 +378,45 @@
val src = Source.kotlin(
"foo.kt",
"""
- val intProp : Int = 3
- val longProp : Long = 3
- val stringProp : String = "abc"
- val listProp : List<String> = TODO()
+ class Subject {
+ val intProp : Int = 3
+ val longProp : Long = 3
+ val stringProp : String = "abc"
+ val listProp : List<String> = TODO()
+ }
""".trimIndent()
)
runKspTest(
listOf(src)
) { invocation ->
+ val subject = invocation.processingEnv.requireTypeElement("Subject")
assertThat(
- invocation.requirePropertyType("stringProp").isTypeOf(
+ subject.getField("stringProp").type.isTypeOf(
String::class
)
).isTrue()
assertThat(
- invocation.requirePropertyType("intProp").isTypeOf(
+ subject.getField("intProp").type.isTypeOf(
Int::class
)
).isTrue()
assertThat(
- invocation.requirePropertyType("longProp").isTypeOf(
+ subject.getField("longProp").type.isTypeOf(
Long::class
)
).isTrue()
assertThat(
- invocation.requirePropertyType("listProp").isTypeOf(
+ subject.getField("listProp").type.isTypeOf(
List::class
)
).isTrue()
assertThat(
- invocation.requirePropertyType("listProp").isTypeOf(
+ subject.getField("listProp").type.isTypeOf(
Set::class
)
).isFalse()
assertThat(
- invocation.requirePropertyType("listProp").isTypeOf(
+ subject.getField("listProp").type.isTypeOf(
Iterable::class
)
).isFalse()
@@ -409,22 +428,25 @@
val src = Source.kotlin(
"foo.kt",
"""
- val intProp : Int = 3
- val intProp2 : Int = 4
- val longProp : Long = 0L
- val nullableLong : Long? = null
- val listOfStrings1 : List<String> = TODO()
- val listOfStrings2 : List<String> = TODO()
- val listOfInts : List<Int> = TODO()
- val listOfNullableStrings : List<String?> = TODO()
+ class Subject {
+ val intProp : Int = 3
+ val intProp2 : Int = 4
+ val longProp : Long = 0L
+ val nullableLong : Long? = null
+ val listOfStrings1 : List<String> = TODO()
+ val listOfStrings2 : List<String> = TODO()
+ val listOfInts : List<Int> = TODO()
+ val listOfNullableStrings : List<String?> = TODO()
+ }
""".trimIndent()
)
runKspTest(
listOf(src)
) { invocation ->
+ val subject = invocation.processingEnv.requireTypeElement("Subject")
fun check(prop1: String, prop2: String): Boolean {
- return invocation.requirePropertyType(prop1).isSameType(
- invocation.requirePropertyType(prop2)
+ return subject.getField(prop1).type.isSameType(
+ subject.getField(prop2).type
)
}
assertThat(check("intProp", "intProp2")).isTrue()
@@ -453,26 +475,24 @@
runKspTest(
listOf(src)
) { invocation ->
- val env = (invocation.processingEnv as KspProcessingEnv)
val classNames = listOf("Bar", "Bar_NullableFoo")
- val typeArgs = classNames.associateWith {
- env.resolver.findClass(it)!!
- .asStarProjectedType()
- .arguments
+ val typeArgs = classNames.associateWith { className ->
+ invocation.processingEnv
+ .requireType(className)
+ .asDeclaredType()
+ .typeArguments
.single()
- .type
- .let { typeRef ->
- env.wrap(
- ksType = typeRef!!.resolve(),
- allowPrimitives = false
- )
- }
}
- assertThat(typeArgs["Bar"]!!.typeName)
- .isEqualTo(ClassName.get("", "Foo"))
+ val typeName = typeArgs["Bar"]!!.typeName
+ assertThat(typeName)
+ .isEqualTo(
+ TypeVariableName.get("T", ClassName.get("", "Foo"))
+ )
assertThat(typeArgs["Bar"]!!.nullability).isEqualTo(NONNULL)
assertThat(typeArgs["Bar_NullableFoo"]!!.typeName)
- .isEqualTo(ClassName.get("", "Foo"))
+ .isEqualTo(
+ TypeVariableName.get("T", ClassName.get("", "Foo"))
+ )
assertThat(typeArgs["Bar_NullableFoo"]!!.nullability).isEqualTo(NULLABLE)
}
}
@@ -493,17 +513,10 @@
runKspTest(
listOf(src)
) { invocation ->
- val env = (invocation.processingEnv as KspProcessingEnv)
- val method = env.resolver
- .findClass("foo.bar.Baz")
- ?.getDeclaredFunctions()
- ?.first {
- it.simpleName.asString() == "wildcardMethod"
- } ?: throw AssertionError("cannot find test method")
- val paramType = env.wrap(
- ksType = method.parameters.first().type.resolve(),
- allowPrimitives = false
- )
+
+ val method = invocation.processingEnv.requireTypeElement("foo.bar.Baz")
+ .getMethod("wildcardMethod")
+ val paramType = method.parameters.first().type
check(paramType.isDeclared())
val arg1 = paramType.typeArguments.single()
assertThat(arg1.typeName)
@@ -515,29 +528,4 @@
assertThat(arg1.extendsBound()).isNull()
}
}
-
- private fun XTestInvocation.requirePropertyType(name: String): KspType {
- val prop = requireProperty(name)
- return (processingEnv as KspProcessingEnv).wrap(prop.type)
- }
-
- private fun XTestInvocation.requireDeclaredPropertyType(name: String): KspDeclaredType {
- val prop = requireProperty(name)
- val result =
- (processingEnv as KspProcessingEnv).wrap(
- ksType = prop.type.resolve(),
- allowPrimitives = false
- )
- check(result is KspDeclaredType)
- return result
- }
-
- private fun XTestInvocation.requireProperty(name: String): KSPropertyDeclaration {
- kspResolver.getAllFiles().forEach { file ->
- return file.declarations.first {
- it.simpleName.asString() == name
- } as KSPropertyDeclaration
- }
- throw IllegalStateException("cannot find any property with name $name")
- }
}
\ No newline at end of file