Merge "Update KSP to 1.4.10-dev-experimental-20201110" into androidx-master-dev
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
index bc2e12d..e78fdc2 100644
--- a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
@@ -74,7 +74,7 @@
     "com.squareup:kotlinpoet-classinspector-elements:1.4.0"
 const val KOTLIN_COMPILE_TESTING = "com.github.tschuchortdev:kotlin-compile-testing:1.3.1"
 const val KOTLIN_COMPILE_TESTING_KSP = "com.github.tschuchortdev:kotlin-compile-testing-ksp:1.3.1"
-const val KSP_VERSION = "1.4.10-dev-experimental-20201009"
+const val KSP_VERSION = "1.4.10-dev-experimental-20201110"
 const val KOTLIN_KSP_API = "com.google.devtools.ksp:symbol-processing-api:$KSP_VERSION"
 const val KOTLIN_KSP = "com.google.devtools.ksp:symbol-processing:$KSP_VERSION"
 const val KOTLIN_GRADLE_PLUGIN = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.0-rc"
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 be59f1a..ba27191 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
@@ -16,32 +16,20 @@
 
 package androidx.room.compiler.processing.ksp
 
-import com.google.devtools.ksp.closestClassDeclaration
-import com.google.devtools.ksp.getAllSuperTypes
 import com.google.devtools.ksp.processing.Resolver
-import com.google.devtools.ksp.symbol.KSClassDeclaration
-import com.google.devtools.ksp.symbol.KSDeclaration
 import com.google.devtools.ksp.symbol.KSFunctionDeclaration
-import com.google.devtools.ksp.symbol.KSName
 import com.google.devtools.ksp.symbol.KSPropertyDeclaration
 import com.google.devtools.ksp.symbol.KSType
-import com.google.devtools.ksp.symbol.KSTypeArgument
-import com.google.devtools.ksp.symbol.KSTypeParameter
 import com.google.devtools.ksp.symbol.KSValueParameter
-import com.google.devtools.ksp.symbol.Nullability
 
 /**
  * Returns the type of a property as if it is member of the given [ksType].
- *
- * This is a temporary / inefficient implementation until KSP provides the API. It also does not
- * handle inner classes properly.
- * TODO: remove once https://github.com/android/kotlin/issues/26 is implemented
  */
 internal fun KSPropertyDeclaration.typeAsMemberOf(resolver: Resolver, ksType: KSType): KSType {
-    val myType: KSType = checkNotNull(type.resolve()) {
-        "Cannot find type of Kotlin property: $this"
-    }
-    return myType.asMemberOf(resolver, this, ksType)
+    return resolver.asMemberOf(
+        property = this,
+        containing = ksType
+    )
 }
 
 internal fun KSValueParameter.typeAsMemberOf(
@@ -49,102 +37,22 @@
     functionDeclaration: KSFunctionDeclaration,
     ksType: KSType
 ): KSType {
-    val myType: KSType = checkNotNull(type?.resolve()) {
-        "Cannot find type of method parameter: $this"
-    }
-    return myType.asMemberOf(resolver, functionDeclaration, ksType)
+    val asMember = resolver.asMemberOf(
+        function = functionDeclaration,
+        containing = ksType
+    )
+    // 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()
 }
 
 internal fun KSFunctionDeclaration.returnTypeAsMemberOf(
     resolver: Resolver,
     ksType: KSType
 ): KSType {
-    val myType: KSType = checkNotNull(returnType?.resolve()) {
-        "Cannot resolve return type of $this"
-    }
-    return myType.asMemberOf(resolver, this, ksType)
-}
-
-/**
- * Returns `this` type as member of the [other] type.
- *
- * @param resolver The KSP resolver instance
- * @param declaration The KSDeclaration where the owner of this type is defined. Note that this can
- * be different from [KSType.declaration]. For instance, if you have a class `Foo<T>` with property
- * `x : List<T>`, `x`'s type declaration is `kotlin.List` whereas the declaration that
- * should be passed here is `x` (from which the implementation will find `Foo`). On the other hand,
- * `T` of `List<T>`'s declaration is already in `Foo`.
- * @param other The new owner for this type. For instance, if you want to resolve `x` in
- * `Bar<String>`, this would be the star projected type of `Bar`.
- */
-internal fun KSType.asMemberOf(
-    resolver: Resolver,
-    declaration: KSDeclaration,
-    other: KSType
-): KSType {
-    val parent = declaration.closestClassDeclaration() ?: return this
-    val parentQName = parent.qualifiedName ?: return this
-    val matchingParentType: KSType = (other.declaration as? KSClassDeclaration)
-        ?.getAllSuperTypes()
-        ?.firstOrNull {
-            it.starProjection().declaration.qualifiedName == parentQName
-        } ?: return this
-    // create a map of replacements.
-    val replacements = parent.typeParameters.mapIndexed { index, ksTypeParameter ->
-        ksTypeParameter.name to matchingParentType.arguments.getOrNull(index)
-    }.toMap()
-    return replaceFromMap(resolver, replacements)
-}
-
-private fun KSTypeArgument.replaceFromMap(
-    resolver: Resolver,
-    arguments: Map<KSName, KSTypeArgument?>
-): KSTypeArgument {
-    val resolvedType = type?.resolve()
-    val myTypeDeclaration = resolvedType?.declaration
-    if (myTypeDeclaration is KSTypeParameter) {
-        val match = arguments[myTypeDeclaration.name] ?: return this
-        // workaround for https://github.com/google/ksp/issues/82
-        val explicitNullable = resolvedType.makeNullable() == resolvedType
-        return if (explicitNullable) {
-            match.makeNullable(resolver)
-        } else {
-            match
-        }
-    }
-    return this
-}
-
-private fun KSType.replaceFromMap(
-    resolver: Resolver,
-    arguments: Map<KSName, KSTypeArgument?>
-): KSType {
-    val myDeclaration = this.declaration
-    if (myDeclaration is KSTypeParameter) {
-        val match = arguments[myDeclaration.name]?.type?.resolve() ?: return this
-        // workaround for https://github.com/google/ksp/issues/82
-        val explicitNullable = this.makeNullable() == this
-        return if (explicitNullable) {
-            match.makeNullable()
-        } else {
-            match
-        }
-    }
-    if (this.arguments.isEmpty()) {
-        return this
-    }
-    return replace(
-        this.arguments.map {
-            it.replaceFromMap(resolver, arguments)
-        }
-    )
-}
-
-private fun KSTypeArgument.makeNullable(resolver: Resolver): KSTypeArgument {
-    val myType = type
-    val resolved = myType?.resolve() ?: return this
-    if (resolved.nullability == Nullability.NULLABLE) {
-        return this
-    }
-    return resolver.getTypeArgument(myType.swapResolvedType(resolved.makeNullable()), variance)
+    return resolver.asMemberOf(
+        function = this,
+        containing = ksType
+    ).returnType ?: returnType?.resolve() ?: error("cannot find return type for $this")
 }
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotationBox.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotationBox.kt
index 4e308fb..edfd964 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotationBox.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotationBox.kt
@@ -30,12 +30,22 @@
 ) : XAnnotationBox<T> {
     override fun getAsType(methodName: String): XType? {
         val value = getFieldValue<KSType>(methodName)
-        return value?.let(env::wrapDeclared)
+        return value?.let {
+            env.wrap(
+                ksType = it,
+                allowPrimitives = true
+            )
+        }
     }
 
     override fun getAsTypeList(methodName: String): List<XType> {
         val values = getFieldValue<List<KSType>>(methodName) ?: return emptyList()
-        return values.map(env::wrapDeclared)
+        return values.map {
+            env.wrap(
+                ksType = it,
+                allowPrimitives = true
+            )
+        }
     }
 
     override fun <R : Annotation> getAsAnnotationBox(methodName: String): XAnnotationBox<R> {
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspArrayType.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspArrayType.kt
index 579d447..7831603 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspArrayType.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspArrayType.kt
@@ -51,8 +51,9 @@
             val arg = ksType.arguments.single()
             // https://kotlinlang.org/docs/reference/basic-types.html#primitive-type-arrays
             // these are always boxed
-            env.wrapDeclared(
-                checkNotNull(arg.type?.resolve())
+            env.wrap(
+                ksType = checkNotNull(arg.type?.resolve()),
+                allowPrimitives = false
             )
         }
     }
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt
index c0d0099..629d421 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt
@@ -23,7 +23,6 @@
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.ksp.KspAnnotated.UseSiteFilter.Companion.METHOD_PARAMETER
 import com.google.devtools.ksp.symbol.KSValueParameter
-import com.google.devtools.ksp.symbol.Origin
 
 internal class KspExecutableParameterElement(
     val env: KspProcessingEnv,
@@ -40,22 +39,16 @@
         get() = parameter.name?.asString() ?: "_no_param_name"
 
     override val type: XType by lazy {
-        val paramType = parameter.typeAsMemberOf(
+        parameter.typeAsMemberOf(
             resolver = env.resolver,
             functionDeclaration = method.declaration,
             ksType = method.containing.declaration.asStarProjectedType()
         ).let {
             env.wrap(
-                originatingReference = parameter.type!!, // as member of doesn't allow nulls
+                originatingReference = parameter.type,
                 ksType = it
             )
         }
-        // if vararg and kotlin source, wrap in an array because thats how it is represented in java
-        if (parameter.isVararg && parameter.origin == Origin.KOTLIN) {
-            env.getArrayType(paramType)
-        } else {
-            paramType
-        }
     }
 
     override fun asMemberOf(other: XDeclaredType): XType {
@@ -69,7 +62,7 @@
             ksType = other.ksType
         ).let {
             env.wrap(
-                originatingReference = parameter.type!!, // as member of doesn't allow nulls
+                originatingReference = parameter.type,
                 ksType = it
             )
         }
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodElement.kt
index ab01a0b..6088fcc 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodElement.kt
@@ -65,7 +65,6 @@
     }
 
     override fun hasKotlinDefaultImpl(): Boolean {
-        // see https://github.com/google/ksp/issues/32
         val parentDeclaration = declaration.parentDeclaration
         // if parent declaration is an interface and we are not marked as an abstract method,
         // we should have a default implementation
@@ -114,7 +113,10 @@
         override fun isSuspendFunction() = true
 
         override val returnType: XType by lazy {
-            env.wrapDeclared(env.resolver.builtIns.anyType.makeNullable())
+            env.wrap(
+                ksType = env.resolver.builtIns.anyType.makeNullable(),
+                allowPrimitives = false
+            )
         }
 
         override val parameters: List<XExecutableParameterElement>
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodType.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodType.kt
index cab8045..0ce3d78 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodType.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodType.kt
@@ -70,12 +70,13 @@
             get() = origin.returnType
 
         override fun getSuspendFunctionReturnType(): XType {
-            // suspend functions work w/ continuation so it is always declared
-            return env.wrapDeclared(
+            // suspend functions work w/ continuation so it is always boxed
+            return env.wrap(
                 ksType = origin.declaration.returnTypeAsMemberOf(
                     resolver = env.resolver,
                     ksType = containing.ksType
-                )
+                ),
+                allowPrimitives = false
             )
         }
     }
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspPrimitiveType.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspPrimitiveType.kt
index 6a4f357..29fed31 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspPrimitiveType.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspPrimitiveType.kt
@@ -36,6 +36,9 @@
         get() = ksType.typeName(env.resolver).tryUnbox()
 
     override fun boxed(): XType {
-        return env.wrapDeclared(ksType)
+        return env.wrap(
+            ksType = ksType,
+            allowPrimitives = false
+        )
     }
 }
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt
index e90169b..41cd7e2 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt
@@ -16,7 +16,6 @@
 
 package androidx.room.compiler.processing.ksp
 
-import androidx.room.compiler.processing.XDeclaredType
 import androidx.room.compiler.processing.XFiler
 import androidx.room.compiler.processing.XMessager
 import androidx.room.compiler.processing.XProcessingEnv
@@ -92,7 +91,7 @@
             ?: findTypeElement("javax.annotation.Generated")
     }
 
-    override fun getDeclaredType(type: XTypeElement, vararg types: XType): XDeclaredType {
+    override fun getDeclaredType(type: XTypeElement, vararg types: XType): KspDeclaredType {
         check(type is KspTypeElement) {
             "Unexpected type element type: $type"
         }
@@ -105,9 +104,14 @@
                 variance = Variance.INVARIANT
             )
         }
-        return wrapDeclared(
-            type.declaration.asType(typeArguments)
+        val result = wrap(
+            ksType = type.declaration.asType(typeArguments),
+            allowPrimitives = false
         )
+        check(result is KspDeclaredType) {
+            "Expected $type to be a declared type but a non-declared type ($result) is received"
+        }
+        return result
     }
 
     override fun getArrayType(type: XType): KspArrayType {
@@ -116,18 +120,6 @@
     }
 
     /**
-     * Wraps the given `ksType` as a [KspDeclaredType].
-     * For the edge cases where `ksType` potentially represents a java primitive, it is always
-     * boxed.
-     */
-    fun wrapDeclared(ksType: KSType): KspDeclaredType {
-        return wrap(
-            ksType = ksType,
-            allowPrimitives = false
-        ) as KspDeclaredType
-    }
-
-    /**
      * Wraps the given `ksType`.
      *
      * The [originatingReference] is used to calculate whether the given [ksType] can be a
@@ -169,7 +161,7 @@
      * Instead, it is passed in an argument to this function and public wrap functions make that
      * decision.
      */
-    private fun wrap(ksType: KSType, allowPrimitives: Boolean): KspType {
+    fun wrap(ksType: KSType, allowPrimitives: Boolean): KspType {
         val qName = ksType.declaration.qualifiedName?.asString()
         if (allowPrimitives && qName != null && ksType.nullability == Nullability.NOT_NULL) {
             // check for primitives
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
index 8f31e56..f4575aa 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
@@ -73,7 +73,15 @@
     }
 
     override val type: KspDeclaredType by lazy {
-        env.wrapDeclared(declaration.asStarProjectedType())
+        val result = env.wrap(
+            ksType = declaration.asStarProjectedType(),
+            allowPrimitives = false
+        )
+        check(result is KspDeclaredType) {
+            "Internal error, expected type of $this to resolve to a declared type but it resolved" +
+                " to $result (${result::class})"
+        }
+        result
     }
 
     override val superType: XType? by lazy {
@@ -81,7 +89,10 @@
             val type = it.resolve().declaration as? KSClassDeclaration ?: return@firstOrNull false
             type.classKind == ClassKind.CLASS
         }?.let {
-            env.wrapDeclared(it.resolve())
+            env.wrap(
+                ksType = it.resolve(),
+                allowPrimitives = false
+            )
         }
     }
 
@@ -190,12 +201,7 @@
     }
 
     override fun findPrimaryConstructor(): XConstructorElement? {
-        val primary = if (declaration.declaredConstructors().isEmpty() && !isInterface()) {
-            declaration.primaryConstructor
-        } else {
-            declaration.getNonSyntheticPrimaryConstructor()
-        }
-        return primary?.let {
+        return declaration.primaryConstructor?.let {
             KspConstructorElement(
                 env = env,
                 containing = this,
@@ -288,5 +294,5 @@
     private fun KSClassDeclaration.declaredConstructors() = this.getDeclaredFunctions()
         .filter {
             it.simpleName == this.simpleName
-        }.distinct() // workaround for: https://github.com/google/ksp/issues/99
+        }
 }
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt
index 42deaa39..68121e3 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt
@@ -65,7 +65,10 @@
                 )
             )
         )
-        env.wrapDeclared(contType)
+        env.wrap(
+            ksType = contType,
+            allowPrimitives = false
+        )
     }
 
     override fun asMemberOf(other: XDeclaredType): XType {
@@ -83,7 +86,10 @@
             Variance.CONTRAVARIANT
         )
         val contType = continuation.asType(listOf(returnTypeAsTypeArgument))
-        return env.wrapDeclared(contType)
+        return env.wrap(
+            ksType = contType,
+            allowPrimitives = false
+        )
     }
 
     override fun kindName(): String {
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingEnvTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingEnvTest.kt
index 003e2b1..12f726f 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingEnvTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingEnvTest.kt
@@ -17,8 +17,6 @@
 package androidx.room.compiler.processing
 
 import androidx.room.compiler.processing.util.Source
-import androidx.room.compiler.processing.util.TestInvocation
-import androidx.room.compiler.processing.util.runProcessorTest
 import androidx.room.compiler.processing.util.runProcessorTestForFailedCompilation
 import androidx.room.compiler.processing.util.runProcessorTestIncludingKsp
 import com.google.common.truth.Truth.assertThat
@@ -203,17 +201,7 @@
             """.trimIndent()
         )
         listOf(javaSrc, kotlinSrc).forEach { src ->
-            fun runTest(block: (TestInvocation) -> Unit) {
-                // KSP does not support generated code access in java sources yet
-                // TODO remove this check once the bug is fixed.
-                //  https://github.com/google/ksp/issues/119
-                if (src === javaSrc) {
-                    runProcessorTest(sources = listOf(src), block)
-                } else {
-                    runProcessorTestIncludingKsp(sources = listOf(src), block)
-                }
-            }
-            runTest { invocation ->
+            runProcessorTestIncludingKsp(sources = listOf(src)) { invocation ->
                 val className = ClassName.get("foo.bar", "ToBeGenerated")
                 if (invocation.processingEnv.findTypeElement(className) == null) {
                     // generate only if it doesn't exist to handle multi-round
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspFieldElementTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspFieldElementTest.kt
index dbfc27d..1e3e3c3 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspFieldElementTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspFieldElementTest.kt
@@ -100,14 +100,30 @@
             val base = invocation.processingEnv.requireTypeElement("Base")
             val t = base.getField("t")
             val listOfR = base.getField("listOfR")
-            assertThat(t.type.typeName).isEqualTo(TypeVariableName.get("T"))
+            if (invocation.isKsp) {
+                // KSP replaces unspecified type parameters with Any? while javac keeps them as is.
+                // This might be an issue when detecting errors but besides that it should be OK.
+                // It other words, it shouldn't be an issue in proper code. It will only have an
+                // impact when Room wants to report `unbound generics` errors as we won't
+                // recognize them and instead assume they were set as Object.
+                // see: UNBOUND_GENERICS errors in ProcessorErrors)
+                assertThat(t.type.typeName).isEqualTo(TypeName.OBJECT)
+            } else {
+                assertThat(t.type.typeName).isEqualTo(TypeVariableName.get("T"))
+            }
+            val typeVariableName = if (invocation.isKsp) {
+                "E" // ksp reads from class declaration
+            } else {
+                "R" // javac reads from variable declaration
+            }
             assertThat(listOfR.type.typeName)
                 .isEqualTo(
                     ParameterizedTypeName.get(
                         List::class.className(),
-                        TypeVariableName.get("R")
+                        TypeVariableName.get(typeVariableName)
                     )
                 )
+
             assertThat(t.enclosingTypeElement).isEqualTo(base)
             assertThat(listOfR.enclosingTypeElement).isEqualTo(base)
             assertThat(t.asMemberOf(sub.type).typeName).isEqualTo(TypeName.INT.box())
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt
index 43950af..10c8f93 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt
@@ -241,8 +241,14 @@
             }
 
             baseClass.getField("genericProp").let { field ->
-                assertThat(field.type.typeName).isEqualTo(TypeVariableName.get("T"))
+                if (invocation.isKsp) {
+                    // ksp replaces these with Any?
+                    assertThat(field.type.typeName).isEqualTo(TypeName.OBJECT)
+                } else {
+                    assertThat(field.type.typeName).isEqualTo(TypeVariableName.get("T"))
+                }
             }
+
             subClass.getField("genericProp").let { field ->
                 // this is tricky because even though it is non-null it, it should still be boxed
                 assertThat(field.type.typeName).isEqualTo(TypeName.INT.box())
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 cb953a4..5c0a3c6 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,6 +18,7 @@
 
 import androidx.room.compiler.processing.XNullability.NONNULL
 import androidx.room.compiler.processing.XNullability.NULLABLE
+import androidx.room.compiler.processing.isDeclared
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.TestInvocation
 import androidx.room.compiler.processing.util.className
@@ -459,8 +460,11 @@
                     .arguments
                     .single()
                     .type
-                    .let {
-                        invocation.processingEnv.wrapDeclared(it!!.resolve())
+                    .let { typeRef ->
+                        invocation.processingEnv.wrap(
+                            ksType = typeRef!!.resolve(),
+                            allowPrimitives = false
+                        )
                     }
             }
             assertThat(typeArgs["Bar"]!!.typeName)
@@ -496,9 +500,11 @@
                 ?.first {
                     it.simpleName.asString() == "wildcardMethod"
                 } ?: throw AssertionError("cannot find test method")
-            val paramType = invocation.processingEnv.wrapDeclared(
-                method.parameters.first().type!!.resolve()
+            val paramType = invocation.processingEnv.wrap(
+                ksType = method.parameters.first().type.resolve(),
+                allowPrimitives = false
             )
+            check(paramType.isDeclared())
             val arg1 = paramType.typeArguments.single()
             assertThat(arg1.typeName)
                 .isEqualTo(
@@ -517,7 +523,13 @@
 
     private fun TestInvocation.requireDeclaredPropertyType(name: String): KspDeclaredType {
         val prop = requireProperty(name)
-        return (processingEnv as KspProcessingEnv).wrapDeclared(prop.type.resolve())
+        val result =
+            (processingEnv as KspProcessingEnv).wrap(
+                ksType = prop.type.resolve(),
+                allowPrimitives = false
+            )
+        check(result is KspDeclaredType)
+        return result
     }
 
     private fun TestInvocation.requireProperty(name: String): KSPropertyDeclaration {
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/ProcessorTestExt.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/ProcessorTestExt.kt
index ae79f1d..c50a9d7 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/ProcessorTestExt.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/ProcessorTestExt.kt
@@ -23,7 +23,18 @@
 import com.google.testing.compile.CompileTester
 import com.google.testing.compile.JavaSourcesSubjectFactory
 import com.tschuchort.compiletesting.KotlinCompilation
+import com.tschuchort.compiletesting.SourceFile
+import com.tschuchort.compiletesting.kspSourcesDir
 import com.tschuchort.compiletesting.symbolProcessors
+import java.io.File
+
+// TODO get rid of these once kotlin compile testing supports two step compilation for KSP.
+//  https://github.com/tschuchortdev/kotlin-compile-testing/issues/72
+private val KotlinCompilation.kspJavaSourceDir: File
+    get() = kspSourcesDir.resolve("java")
+
+private val KotlinCompilation.kspKotlinSourceDir: File
+    get() = kspSourcesDir.resolve("kotlin")
 
 private fun compileSources(
     sources: List<Source>,
@@ -66,7 +77,7 @@
 private fun compileWithKsp(
     sources: List<Source>,
     handler: (TestInvocation) -> Unit
-): Pair<SyntheticKspProcessor, KotlinCompilation> {
+): Pair<SyntheticKspProcessor, KotlinCompilation.Result> {
     @Suppress("NAME_SHADOWING")
     val sources = if (sources.none { it is Source.KotlinSource }) {
         // looks like this requires a kotlin source file
@@ -76,23 +87,44 @@
         sources
     }
     val syntheticKspProcessor = SyntheticKspProcessor(handler)
-    val compilation = KotlinCompilation()
-    sources.forEach {
-        compilation.workingDir.resolve("sources")
-            .resolve(it.relativePath())
-            .parentFile
-            .mkdirs()
+    fun prepareCompilation(): KotlinCompilation {
+        val compilation = KotlinCompilation()
+        sources.forEach {
+            compilation.workingDir.resolve("sources")
+                .resolve(it.relativePath())
+                .parentFile
+                .mkdirs()
+        }
+        compilation.sources = sources.map {
+            it.toKotlinSourceFile()
+        }
+        compilation.jvmDefault = "enable"
+        compilation.jvmTarget = "1.8"
+        compilation.inheritClassPath = true
+        compilation.verbose = false
+        return compilation
     }
-    compilation.sources = sources.map {
-        it.toKotlinSourceFile()
-    }
-    compilation.symbolProcessors = listOf(syntheticKspProcessor)
-    compilation.jvmDefault = "enable"
-    compilation.jvmTarget = "1.8"
-    compilation.inheritClassPath = true
-    compilation.verbose = false
+    val kspCompilation = prepareCompilation()
+    kspCompilation.symbolProcessors = listOf(syntheticKspProcessor)
+    kspCompilation.compile()
+    // ignore KSP result for now because KSP stops compilation, which might create false negatives
+    // when java code accesses kotlin code.
+    // TODO:  fix once https://github.com/tschuchortdev/kotlin-compile-testing/issues/72 is fixed
 
-    return syntheticKspProcessor to compilation
+    // after ksp, compile without ksp with KSP's output as input
+    val finalCompilation = prepareCompilation()
+    // build source files from generated code
+    finalCompilation.sources += kspCompilation.kspJavaSourceDir.collectSourceFiles() +
+        kspCompilation.kspKotlinSourceDir.collectSourceFiles()
+    return syntheticKspProcessor to finalCompilation.compile()
+}
+
+private fun File.collectSourceFiles(): List<SourceFile> {
+    return walkTopDown().filter {
+        it.isFile
+    }.map { file ->
+        SourceFile.fromPath(file)
+    }.toList()
 }
 
 fun runProcessorTest(
@@ -191,8 +223,7 @@
     succeed: Boolean,
     handler: (TestInvocation) -> Unit
 ) {
-    val (kspProcessor, kotlinCompilation) = compileWithKsp(sources, handler)
-    val compilationResult = kotlinCompilation.compile()
+    val (kspProcessor, compilationResult) = compileWithKsp(sources, handler)
     if (succeed) {
         assertThat(compilationResult.exitCode).isEqualTo(KotlinCompilation.ExitCode.OK)
     } else {