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