Implement methods in KSP
This CL adds more implementation to methods in KSP, specifically,
we can now get executable type and method parameters in KSP.
As Room still generates Java, I implemented Synthetic parameters
for suspend functions and changed their return values to match
Java as well.
Similarly, there are no getters/setters for properties hence I
implemented Synthetics for their elements and types. KAPT does not
generate them for private properties so I also excluded them from
the list.
This CL does not handle JvmOverloads yet.
Bug: 160322705
Bug: 169882122
Test: XExecutableElementTest, XExecutableTypeTest
Change-Id: I0ebb99325e648c81568a5c46a6d8e9566c73b26e
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 2ea9db7..f716d04 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
@@ -21,11 +21,13 @@
import org.jetbrains.kotlin.ksp.processing.Resolver
import org.jetbrains.kotlin.ksp.symbol.KSClassDeclaration
import org.jetbrains.kotlin.ksp.symbol.KSDeclaration
+import org.jetbrains.kotlin.ksp.symbol.KSFunctionDeclaration
import org.jetbrains.kotlin.ksp.symbol.KSName
import org.jetbrains.kotlin.ksp.symbol.KSPropertyDeclaration
import org.jetbrains.kotlin.ksp.symbol.KSType
import org.jetbrains.kotlin.ksp.symbol.KSTypeArgument
import org.jetbrains.kotlin.ksp.symbol.KSTypeParameter
+import org.jetbrains.kotlin.ksp.symbol.KSVariableParameter
import org.jetbrains.kotlin.ksp.symbol.Nullability
/**
@@ -42,6 +44,27 @@
return myType.asMemberOf(resolver, this, ksType)
}
+internal fun KSVariableParameter.typeAsMemberOf(
+ resolver: Resolver,
+ functionDeclaration: KSFunctionDeclaration,
+ ksType: KSType
+): KSType {
+ val myType: KSType = checkNotNull(type?.requireType()) {
+ "Cannot find type of method parameter: $this"
+ }
+ return myType.asMemberOf(resolver, functionDeclaration, ksType)
+}
+
+internal fun KSFunctionDeclaration.returnTypeAsMemberOf(
+ resolver: Resolver,
+ ksType: KSType
+): KSType {
+ val myType: KSType = checkNotNull(returnType?.requireType()) {
+ "Cannot resolve return type of $this"
+ }
+ return myType.asMemberOf(resolver, this, ksType)
+}
+
/**
* Returns `this` type as member of the [other] type.
*
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt
index 7c95149..6f38f4b 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt
@@ -22,7 +22,7 @@
import androidx.room.compiler.processing.XTypeElement
import org.jetbrains.kotlin.ksp.symbol.KSFunctionDeclaration
-internal open class KspExecutableElement(
+internal abstract class KspExecutableElement(
env: KspProcessingEnv,
val containing: KspTypeElement,
override val declaration: KSFunctionDeclaration
@@ -39,13 +39,15 @@
declaration.requireEnclosingTypeElement(env)
}
- override val parameters: List<XExecutableParameterElement>
- get() = TODO(
- """
- implement parameters. need to be careful w/ suspend functions as they need to fake
- an additional parameter to look like java
- """.trimIndent()
- )
+ override val parameters: List<XExecutableParameterElement> by lazy {
+ declaration.parameters.map {
+ KspExecutableParameterElement(
+ env = env,
+ method = this,
+ parameter = it
+ )
+ }
+ }
override fun isVarArgs(): Boolean {
return declaration.parameters.any {
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
new file mode 100644
index 0000000..8fa582d
--- /dev/null
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.compiler.processing.ksp
+
+import androidx.room.compiler.processing.XAnnotationBox
+import androidx.room.compiler.processing.XDeclaredType
+import androidx.room.compiler.processing.XEquality
+import androidx.room.compiler.processing.XExecutableParameterElement
+import androidx.room.compiler.processing.XType
+import org.jetbrains.kotlin.ksp.symbol.KSVariableParameter
+import kotlin.reflect.KClass
+
+internal class KspExecutableParameterElement(
+ val env: KspProcessingEnv,
+ val method: KspExecutableElement,
+ val parameter: KSVariableParameter
+) : XExecutableParameterElement, XEquality {
+
+ override val equalityItems: Array<out Any?>
+ get() = arrayOf(method, parameter)
+
+ override val name: String
+ get() = parameter.name?.asString() ?: "_no_param_name"
+
+ override val type: XType by lazy {
+ parameter.typeAsMemberOf(
+ resolver = env.resolver,
+ functionDeclaration = method.declaration,
+ ksType = method.containing.declaration.asStarProjectedType()
+ ).let(env::wrap)
+ }
+
+ override fun asMemberOf(other: XDeclaredType): XType {
+ if (method.containing.type.isSameType(other)) {
+ return type
+ }
+ check(other is KspType)
+ return parameter.typeAsMemberOf(
+ resolver = env.resolver,
+ functionDeclaration = method.declaration,
+ ksType = other.ksType
+ ).let(env::wrap)
+ }
+
+ override fun kindName(): String {
+ return "function parameter"
+ }
+
+ override fun <T : Annotation> toAnnotationBox(annotation: KClass<T>): XAnnotationBox<T>? {
+ TODO("Not yet implemented")
+ }
+
+ override fun hasAnnotationWithPackage(pkg: String): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ override fun hasAnnotation(annotation: KClass<out Annotation>): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ override fun equals(other: Any?): Boolean {
+ return XEquality.equals(this, other)
+ }
+
+ override fun hashCode(): Int {
+ return XEquality.hashCode(equalityItems)
+ }
+}
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 74d352b..148b753 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
@@ -17,14 +17,20 @@
package androidx.room.compiler.processing.ksp
import androidx.room.compiler.processing.XDeclaredType
+import androidx.room.compiler.processing.XExecutableParameterElement
import androidx.room.compiler.processing.XMethodElement
import androidx.room.compiler.processing.XMethodType
import androidx.room.compiler.processing.XType
import androidx.room.compiler.processing.XTypeElement
+import androidx.room.compiler.processing.ksp.synthetic.KspSyntheticContinuationParameterElement
+import androidx.room.compiler.processing.ksp.synthetic.KspSyntheticPropertyMethodElement
+import org.jetbrains.kotlin.ksp.symbol.ClassKind
+import org.jetbrains.kotlin.ksp.symbol.KSClassDeclaration
import org.jetbrains.kotlin.ksp.symbol.KSFunctionDeclaration
import org.jetbrains.kotlin.ksp.symbol.Modifier
+import org.jetbrains.kotlin.ksp.symbol.Origin
-internal class KspMethodElement(
+internal sealed class KspMethodElement(
env: KspProcessingEnv,
containing: KspTypeElement,
declaration: KSFunctionDeclaration
@@ -38,44 +44,128 @@
declaration.simpleName.asString()
}
- override val returnType: XType
- get() = TODO(
- """
- Implement return type.
- Need to handle suspend functions where their signature is different as long as we
- generate java code.
- """.trimIndent()
+ override val executableType: XMethodType by lazy {
+ KspMethodType.create(
+ env = env,
+ origin = this,
+ containing = this.containing.type
)
-
- override val executableType: XMethodType
- get() = TODO("Not yet implemented")
+ }
override fun isJavaDefault(): Boolean {
return declaration.modifiers.contains(Modifier.JAVA_DEFAULT) || declaration.isJvmDefault()
}
override fun asMemberOf(other: XDeclaredType): XMethodType {
- TODO("Not yet implemented")
+ check(other is KspType)
+ return KspMethodType.create(
+ env = env,
+ origin = this,
+ containing = other
+ )
}
override fun hasKotlinDefaultImpl(): Boolean {
- TODO("Not yet implemented")
- }
-
- override fun isSuspendFunction(): Boolean {
- return declaration.modifiers.contains(Modifier.SUSPEND)
+ // 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
+ return parentDeclaration is KSClassDeclaration &&
+ parentDeclaration.classKind == ClassKind.INTERFACE &&
+ !declaration.isAbstract
}
override fun overrides(other: XMethodElement, owner: XTypeElement): Boolean {
- return other is KspMethodElement && declaration.overrides(other.declaration)
+ if (other is KspMethodElement) {
+ return try {
+ declaration.overrides(other.declaration)
+ } catch (castException: ClassCastException) {
+ // TODO remove the try catch once that bug is fixed.
+ // see https://github.com/google/ksp/issues/94
+ false
+ }
+ }
+ // TODO https://github.com/google/ksp/issues/93
+ // remove this custom implementation when KSP supports this out of the box
+ // if our declaration is coming from java, it can override property getters/setters as well
+ val checkForJavaToKotlinOverride = other.isOverrideableIgnoringContainer() &&
+ (declaration.origin == Origin.JAVA || declaration.origin == Origin.CLASS)
+ return if (checkForJavaToKotlinOverride && name == other.name) {
+ when (other) {
+ is KspSyntheticPropertyMethodElement.Getter -> {
+ return parameters.isEmpty() &&
+ asMemberOf(owner.type).returnType.isSameType(
+ other.asMemberOf(owner.type).returnType
+ )
+ }
+ is KspSyntheticPropertyMethodElement.Setter -> {
+ return parameters.size == 1 &&
+ parameters.first().asMemberOf(owner.type).isSameType(
+ other.parameters.first().asMemberOf(owner.type)
+ )
+ }
+ else -> false
+ }
+ } else {
+ false
+ }
}
- override fun copyTo(newContainer: XTypeElement): XMethodElement {
+ override fun copyTo(newContainer: XTypeElement): KspMethodElement {
check(newContainer is KspTypeElement)
- return KspMethodElement(
+ return create(
env = env,
containing = newContainer,
declaration = declaration
)
}
+
+ private class KspNormalMethodElement(
+ env: KspProcessingEnv,
+ containing: KspTypeElement,
+ declaration: KSFunctionDeclaration
+ ) : KspMethodElement(
+ env, containing, declaration
+ ) {
+ override val returnType: XType by lazy {
+ env.wrap(checkNotNull(declaration.returnType) {
+ "return type on a method declaration cannot be null"
+ })
+ }
+ override fun isSuspendFunction() = false
+ }
+
+ private class KspSuspendMethodElement(
+ env: KspProcessingEnv,
+ containing: KspTypeElement,
+ declaration: KSFunctionDeclaration
+ ) : KspMethodElement(
+ env, containing, declaration
+ ) {
+ override fun isSuspendFunction() = true
+
+ override val returnType: XType by lazy {
+ env.wrap(env.resolver.builtIns.anyType.makeNullable())
+ }
+
+ override val parameters: List<XExecutableParameterElement>
+ get() = super.parameters + KspSyntheticContinuationParameterElement(
+ env = env,
+ containing = this
+ )
+ }
+
+ companion object {
+ fun create(
+ env: KspProcessingEnv,
+ containing: KspTypeElement,
+ declaration: KSFunctionDeclaration
+ ): KspMethodElement {
+ return if (declaration.modifiers.contains(Modifier.SUSPEND)) {
+ KspSuspendMethodElement(env, containing, declaration)
+ } else {
+ KspNormalMethodElement(env, containing, declaration)
+ }
+ }
+ }
}
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
new file mode 100644
index 0000000..192a52b
--- /dev/null
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodType.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.compiler.processing.ksp
+
+import androidx.room.compiler.processing.XMethodType
+import androidx.room.compiler.processing.XType
+import com.squareup.javapoet.TypeVariableName
+
+internal sealed class KspMethodType(
+ val env: KspProcessingEnv,
+ val origin: KspMethodElement,
+ val containing: KspType
+) : XMethodType {
+ override val parameterTypes: List<XType> by lazy {
+ origin.parameters.map {
+ it.asMemberOf(containing)
+ }
+ }
+
+ override val typeVariableNames: List<TypeVariableName> by lazy {
+ origin.declaration.typeParameters.map {
+ TypeVariableName.get(
+ it.name.asString(),
+ *(it.bounds.map {
+ it.typeName()
+ }.toTypedArray())
+ )
+ }
+ }
+
+ private class KspNormalMethodType(
+ env: KspProcessingEnv,
+ origin: KspMethodElement,
+ containing: KspType
+ ) : KspMethodType(env, origin, containing) {
+ override val returnType: XType by lazy {
+ env.wrap(
+ origin.declaration.returnTypeAsMemberOf(
+ resolver = env.resolver,
+ ksType = containing.ksType
+ )
+ )
+ }
+
+ override fun getSuspendFunctionReturnType(): XType {
+ throw IllegalStateException(
+ "cannot call getSuspendFunctionReturnType on a non-suspend method. $this"
+ )
+ }
+ }
+
+ private class KspSuspendMethodType(
+ env: KspProcessingEnv,
+ origin: KspMethodElement,
+ containing: KspType
+ ) : KspMethodType(env, origin, containing) {
+ override val returnType: XType
+ // suspend functions always return Any?, no need to call asMemberOf
+ get() = origin.returnType
+
+ override fun getSuspendFunctionReturnType(): XType {
+ return env.wrap(
+ origin.declaration.returnTypeAsMemberOf(
+ resolver = env.resolver,
+ ksType = containing.ksType
+ )
+ )
+ }
+ }
+
+ companion object {
+ fun create(
+ env: KspProcessingEnv,
+ origin: KspMethodElement,
+ containing: KspType
+ ) = if (origin.isSuspendFunction()) {
+ KspSuspendMethodType(env, origin, containing)
+ } else {
+ KspNormalMethodType(env, origin, containing)
+ }
+ }
+}
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 959d0eb..1244d41 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
@@ -185,7 +185,7 @@
// filter out constructors
it.simpleName.asString() != name
}.map {
- KspMethodElement(
+ KspMethodElement.create(
env = env,
containing = this,
declaration = it
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/ResolverExt.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/ResolverExt.kt
index 9e53d6d..d490a38 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/ResolverExt.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/ResolverExt.kt
@@ -25,3 +25,5 @@
internal fun Resolver.requireClass(qName: String) = checkNotNull(findClass(qName)) {
"cannot find class $qName"
}
+
+internal fun Resolver.requireContinuationClass() = requireClass("kotlin.coroutines.Continuation")
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
new file mode 100644
index 0000000..334bb1f
--- /dev/null
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.compiler.processing.ksp.synthetic
+
+import androidx.room.compiler.processing.XAnnotationBox
+import androidx.room.compiler.processing.XDeclaredType
+import androidx.room.compiler.processing.XEquality
+import androidx.room.compiler.processing.XExecutableParameterElement
+import androidx.room.compiler.processing.XType
+import androidx.room.compiler.processing.ksp.KspExecutableElement
+import androidx.room.compiler.processing.ksp.KspProcessingEnv
+import androidx.room.compiler.processing.ksp.KspType
+import androidx.room.compiler.processing.ksp.requireContinuationClass
+import androidx.room.compiler.processing.ksp.returnTypeAsMemberOf
+import androidx.room.compiler.processing.ksp.swapResolvedType
+import org.jetbrains.kotlin.ksp.symbol.Variance
+import kotlin.reflect.KClass
+
+/**
+ * XProcessing adds an additional argument to each suspend function for the continiuation because
+ * this is what KAPT generates and Room needs it as long as it generates java code.
+ */
+internal class KspSyntheticContinuationParameterElement(
+ private val env: KspProcessingEnv,
+ private val containing: KspExecutableElement
+) : XExecutableParameterElement, XEquality {
+
+ override val name: String
+ get() = "_syntheticContinuation"
+
+ override val equalityItems: Array<out Any?> by lazy {
+ arrayOf("continuation", containing)
+ }
+
+ override val type: XType by lazy {
+ val continuation = env.resolver.requireContinuationClass()
+ val contType = continuation.asType(
+ listOf(
+ env.resolver.getTypeArgument(
+ checkNotNull(containing.declaration.returnType) {
+ "cannot find return type for $this"
+ },
+ Variance.CONTRAVARIANT
+ )
+ )
+ )
+ env.wrap(contType)
+ }
+
+ override fun asMemberOf(other: XDeclaredType): XType {
+ check(other is KspType)
+ val continuation = env.resolver.requireContinuationClass()
+ val asMember = containing.declaration.returnTypeAsMemberOf(
+ resolver = env.resolver,
+ ksType = other.ksType
+ )
+ val returnTypeRef = checkNotNull(containing.declaration.returnType) {
+ "cannot find return type reference for $this"
+ }
+ val returnTypeAsTypeArgument = env.resolver.getTypeArgument(
+ returnTypeRef.swapResolvedType(asMember),
+ Variance.CONTRAVARIANT
+ )
+ val contType = continuation.asType(listOf(returnTypeAsTypeArgument))
+ return env.wrap(contType)
+ }
+
+ override fun kindName(): String {
+ return "synthetic continuation parameter"
+ }
+
+ override fun <T : Annotation> toAnnotationBox(annotation: KClass<T>): XAnnotationBox<T>? {
+ TODO("Not yet implemented")
+ }
+
+ override fun hasAnnotationWithPackage(pkg: String): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ override fun hasAnnotation(annotation: KClass<out Annotation>): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ override fun equals(other: Any?): Boolean {
+ return XEquality.equals(this, other)
+ }
+
+ override fun hashCode(): Int {
+ return XEquality.hashCode(equalityItems)
+ }
+}
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
index 26327f1..e401b10 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
@@ -38,6 +38,7 @@
*
* @see KspSyntheticPropertyMethodElement.Getter
* @see KspSyntheticPropertyMethodElement.Setter
+ * @see KspSyntheticPropertyMethodType
*/
internal sealed class KspSyntheticPropertyMethodElement(
env: KspProcessingEnv,
@@ -62,11 +63,18 @@
final override fun isVarArgs() = false
- final override val executableType: XMethodType
- get() = TODO()
+ final override val executableType: XMethodType by lazy {
+ KspSyntheticPropertyMethodType.create(
+ element = this,
+ container = field.containing.type
+ )
+ }
final override fun asMemberOf(other: XDeclaredType): XMethodType {
- TODO()
+ return KspSyntheticPropertyMethodType.create(
+ element = this,
+ container = other
+ )
}
internal class Getter(
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodType.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodType.kt
new file mode 100644
index 0000000..485de45
--- /dev/null
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodType.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.compiler.processing.ksp.synthetic
+
+import androidx.room.compiler.processing.XDeclaredType
+import androidx.room.compiler.processing.XMethodType
+import androidx.room.compiler.processing.XType
+import com.squareup.javapoet.TypeVariableName
+
+/**
+ * @see KspSyntheticPropertyMethodElement
+ */
+internal sealed class KspSyntheticPropertyMethodType(
+ val origin: KspSyntheticPropertyMethodElement,
+ val containing: XDeclaredType
+) : XMethodType {
+
+ override val parameterTypes: List<XType> by lazy {
+ origin.parameters.map {
+ it.asMemberOf(containing)
+ }
+ }
+
+ override val typeVariableNames: List<TypeVariableName>
+ get() = emptyList()
+
+ override fun getSuspendFunctionReturnType(): XType {
+ throw IllegalStateException("Property types are not suspend functions.")
+ }
+
+ companion object {
+ fun create(
+ element: KspSyntheticPropertyMethodElement,
+ container: XDeclaredType
+ ): XMethodType {
+ return when (element) {
+ is KspSyntheticPropertyMethodElement.Getter ->
+ Getter(
+ origin = element,
+ containingType = container
+ )
+ is KspSyntheticPropertyMethodElement.Setter ->
+ Setter(
+ origin = element,
+ containingType = container
+ )
+ }
+ }
+ }
+
+ private class Getter(
+ origin: KspSyntheticPropertyMethodElement.Getter,
+ containingType: XDeclaredType
+ ) : KspSyntheticPropertyMethodType(
+ origin = origin,
+ containing = containingType
+ ) {
+ override val returnType: XType by lazy {
+ origin.field.asMemberOf(containingType)
+ }
+ }
+
+ private class Setter(
+ origin: KspSyntheticPropertyMethodElement.Setter,
+ containingType: XDeclaredType
+ ) : KspSyntheticPropertyMethodType(
+ origin = origin,
+ containing = containingType
+ ) {
+ override val returnType: XType
+ // setters always return Unit, no need to get it as type of
+ get() = origin.returnType
+ }
+}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
index 33a65a5..7e4dd73 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
@@ -16,13 +16,16 @@
package androidx.room.compiler.processing
+import androidx.room.compiler.processing.util.KotlinTypeNames
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.getDeclaredMethod
import androidx.room.compiler.processing.util.getMethod
import androidx.room.compiler.processing.util.getParameter
-import androidx.room.compiler.processing.util.runProcessorTest
+import androidx.room.compiler.processing.util.runProcessorTestIncludingKsp
+import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
-import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.ParameterizedTypeName
+import com.squareup.javapoet.WildcardTypeName
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -31,8 +34,8 @@
class XExecutableElementTest {
@Test
fun basic() {
- runProcessorTest(
- listOf(
+ runProcessorTestIncludingKsp(
+ sources = listOf(
Source.java(
"foo.bar.Baz", """
package foo.bar;
@@ -53,22 +56,23 @@
assertThat(method.isOverrideableIgnoringContainer()).isFalse()
assertThat(method.parameters).isEmpty()
val returnType = method.returnType
- assertThat(returnType.isVoid()).isTrue()
+ // check both as in KSP, it will show up as Unit
+ assertThat(returnType.isVoid() || returnType.isKotlinUnit()).isTrue()
assertThat(returnType.defaultValue()).isEqualTo("null")
}
element.getDeclaredMethod("bar").let { method ->
assertThat(method.isOverrideableIgnoringContainer()).isTrue()
assertThat(method.parameters).hasSize(1)
- val stringTypeName = ClassName.get("java.lang", "String")
method.getParameter("param1").let { param ->
assertThat(param.type.isArray()).isTrue()
assertThat(param.type.asArray().componentType.typeName)
- .isEqualTo(stringTypeName)
+ .isEqualTo(it.types.string)
}
- assertThat(method.returnType.typeName).isEqualTo(stringTypeName)
+ assertThat(method.returnType.typeName).isEqualTo(it.types.string)
}
}
}
+
@Test
fun isVarArgs() {
val subject = Source.java(
@@ -79,7 +83,7 @@
}
""".trimIndent()
)
- runProcessorTest(
+ runProcessorTestIncludingKsp(
sources = listOf(subject)
) {
val element = it.processingEnv.requireTypeElement("foo.bar.Baz")
@@ -107,7 +111,7 @@
}
""".trimIndent()
)
- runProcessorTest(
+ runProcessorTestIncludingKsp(
sources = listOf(subject)
) {
val element = it.processingEnv.requireTypeElement("foo.bar.Baz")
@@ -138,4 +142,261 @@
}
}
}
+
+ @Test
+ fun suspendMethod() {
+ val src = Source.kotlin(
+ "Foo.kt", """
+ class Subject {
+ suspend fun noArg():Unit = TODO()
+ suspend fun intReturn(): Int = TODO()
+ suspend fun twoParams(param1:String, param2:Int): Pair<String, Int> = TODO()
+ }
+ """.trimIndent()
+ )
+ runProcessorTestIncludingKsp(
+ sources = listOf(src)
+ ) { invocation ->
+ val subject = invocation.processingEnv.requireTypeElement("Subject")
+ subject.getMethod("noArg").let { method ->
+ assertThat(method.parameters).hasSize(1)
+ assertThat(method.isSuspendFunction()).isTrue()
+ assertThat(method.returnType.typeName).isEqualTo(invocation.types.objectOrAny)
+ assertThat(method.returnType.nullability).isEqualTo(XNullability.NULLABLE)
+ method.executableType.parameterTypes.last().let { cont ->
+ assertThat(cont.typeName).isEqualTo(
+ ParameterizedTypeName.get(
+ KotlinTypeNames.CONTINUATION_CLASS_NAME,
+ WildcardTypeName.supertypeOf(KotlinTypeNames.UNIT_CLASS_NAME)
+ )
+ )
+ assertThat(cont.nullability).isEqualTo(XNullability.NONNULL)
+ }
+ }
+ subject.getMethod("intReturn").let { method ->
+ assertThat(method.parameters).hasSize(1)
+ assertThat(method.parameters.last().type.typeName).isEqualTo(
+ ParameterizedTypeName.get(
+ KotlinTypeNames.CONTINUATION_CLASS_NAME,
+ WildcardTypeName.supertypeOf(invocation.types.boxedInt)
+ )
+ )
+ assertThat(method.isSuspendFunction()).isTrue()
+ assertThat(method.returnType.typeName).isEqualTo(invocation.types.objectOrAny)
+ method.executableType.parameterTypes.last().let { cont ->
+ assertThat(cont.typeName).isEqualTo(
+ ParameterizedTypeName.get(
+ KotlinTypeNames.CONTINUATION_CLASS_NAME,
+ WildcardTypeName.supertypeOf(invocation.types.boxedInt)
+ )
+ )
+ }
+ }
+ subject.getMethod("twoParams").let { method ->
+ assertThat(method.parameters).hasSize(3)
+ assertThat(method.parameters[0].type.typeName).isEqualTo(
+ invocation.types.string
+ )
+ assertThat(method.parameters[1].type.typeName).isEqualTo(
+ invocation.types.int
+ )
+ assertThat(method.isSuspendFunction()).isTrue()
+ assertThat(method.returnType.typeName).isEqualTo(invocation.types.objectOrAny)
+ method.executableType.parameterTypes.last().let { cont ->
+ assertThat(cont.typeName).isEqualTo(
+ ParameterizedTypeName.get(
+ KotlinTypeNames.CONTINUATION_CLASS_NAME,
+ WildcardTypeName.supertypeOf(
+ ParameterizedTypeName.get(
+ KotlinTypeNames.PAIR_CLASS_NAME,
+ invocation.types.string,
+ invocation.types.boxedInt
+ )
+ )
+ )
+ )
+ }
+ }
+ }
+ }
+
+ @Test
+ fun kotlinProperties() {
+ val src = Source.kotlin(
+ "Foo.kt", """
+ data class MyDataClass(val x:String, var y:String, private val z:String) {
+ val prop1: String = ""
+ var prop2: String = ""
+ var prop3: String = TODO()
+ private set
+ get() = TODO()
+ private val prop4:String = ""
+ }
+ """.trimIndent()
+ )
+ runProcessorTestIncludingKsp(sources = listOf(src)) { invocation ->
+ val klass = invocation.processingEnv.requireTypeElement("MyDataClass")
+ val methodNames = klass.getAllMethods().map {
+ it.name
+ }
+ assertThat(methodNames).containsNoneIn(
+ listOf(
+ "setX", "setProp3", "setZ", "setProp4", "getProp4"
+ )
+ )
+ listOf("getX", "getProp1", "getProp2", "getProp3").forEach {
+ klass.getMethod(it).let { method ->
+ assertThat(method.returnType.typeName).isEqualTo(invocation.types.string)
+ assertThat(method.parameters).isEmpty()
+ }
+ }
+ listOf("setY", "setProp2").forEach {
+ klass.getMethod(it).let { method ->
+ assertThat(method.returnType.typeName).isEqualTo(invocation.types.voidOrUnit)
+ assertThat(method.parameters.first().type.typeName).isEqualTo(
+ invocation.types.string
+ )
+ }
+ }
+ }
+ }
+
+ @Test
+ fun parametersAsMemberOf() {
+ val source = Source.kotlin(
+ "Foo.kt", """
+ open class Base<T> {
+ fun foo(t:T, nullableT:T?): List<T?> = TODO()
+ }
+ class Subject : Base<String>()
+ class NullableSubject: Base<String?>()
+ """.trimIndent()
+ )
+ runProcessorTestIncludingKsp(sources = listOf(source)) { invocation ->
+ val base = invocation.processingEnv.requireTypeElement("Base")
+ val subject = invocation.processingEnv.requireType("Subject")
+ .asDeclaredType()
+ val nullableSubject = invocation.processingEnv.requireType("NullableSubject")
+ .asDeclaredType()
+ val method = base.getMethod("foo")
+ method.getParameter("t").let { param ->
+ param.asMemberOf(subject).let {
+ assertThat(it.typeName).isEqualTo(invocation.types.string)
+ assertThat(it.nullability).isEqualTo(XNullability.NONNULL)
+ }
+ param.asMemberOf(nullableSubject).let {
+ assertThat(it.typeName).isEqualTo(invocation.types.string)
+ if (invocation.isKsp) {
+ // kapt implementation is unable to read this properly
+ assertThat(it.nullability).isEqualTo(XNullability.NULLABLE)
+ }
+ }
+ }
+ method.getParameter("nullableT").let { param ->
+ param.asMemberOf(subject).let {
+ assertThat(it.typeName).isEqualTo(invocation.types.string)
+ assertThat(it.nullability).isEqualTo(XNullability.NULLABLE)
+ }
+ param.asMemberOf(nullableSubject).let {
+ assertThat(it.typeName).isEqualTo(invocation.types.string)
+ assertThat(it.nullability).isEqualTo(XNullability.NULLABLE)
+ }
+ }
+ }
+ }
+
+ @Test
+ fun kotlinPropertyOverrides() {
+ val src = Source.kotlin(
+ "Foo.kt", """
+ interface MyInterface {
+ val x:Int
+ var y:Int
+ }
+ class MyImpl : MyInterface {
+ override var x: Int = 1
+ override var y: Int = 1
+ }
+ """.trimIndent()
+ )
+ val javaSrc = Source.java(
+ "JavaImpl", """
+ class JavaImpl implements MyInterface {
+ public int getX() {
+ return 1;
+ }
+ public int getY() {
+ return 1;
+ }
+ public void setY(int value) {
+ }
+ }
+ """.trimIndent()
+ )
+ runProcessorTestIncludingKsp(sources = listOf(src, javaSrc)) { invocation ->
+ val base = invocation.processingEnv.requireTypeElement("MyInterface")
+ val impl = invocation.processingEnv.requireTypeElement("MyImpl")
+ val javaImpl = invocation.processingEnv.requireTypeElement("JavaImpl")
+
+ fun overrides(
+ owner: XTypeElement,
+ ownerMethodName: String,
+ base: XTypeElement,
+ baseMethodName: String = ownerMethodName
+ ): Boolean {
+ val overridee = owner.getMethod(ownerMethodName)
+ val overridden = base.getMethod(baseMethodName)
+ return overridee.overrides(
+ overridden, owner
+ )
+ }
+ listOf(impl, javaImpl).forEach { subject ->
+ listOf("getY", "getX", "setY").forEach { methodName ->
+ Truth.assertWithMessage("${subject.className}:$methodName").that(
+ overrides(
+ owner = subject,
+ ownerMethodName = methodName,
+ base = base
+ )
+ ).isTrue()
+ }
+
+ Truth.assertWithMessage(subject.className.canonicalName()).that(
+ overrides(
+ owner = subject,
+ ownerMethodName = "getY",
+ base = base,
+ baseMethodName = "getX"
+ )
+ ).isFalse()
+
+ Truth.assertWithMessage(subject.className.canonicalName()).that(
+ overrides(
+ owner = subject,
+ ownerMethodName = "getY",
+ base = subject,
+ baseMethodName = "getX"
+ )
+ ).isFalse()
+
+ Truth.assertWithMessage(subject.className.canonicalName()).that(
+ overrides(
+ owner = base,
+ ownerMethodName = "getX",
+ base = subject,
+ baseMethodName = "getX"
+ )
+ ).isFalse()
+
+ Truth.assertWithMessage(subject.className.canonicalName()).that(
+ overrides(
+ owner = subject,
+ ownerMethodName = "setY",
+ base = base,
+ baseMethodName = "getY"
+ )
+ ).isFalse()
+ }
+ }
+ }
}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableTypeTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableTypeTest.kt
new file mode 100644
index 0000000..1b5c7ab
--- /dev/null
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableTypeTest.kt
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.compiler.processing
+
+import androidx.room.compiler.processing.util.KotlinTypeNames
+import androidx.room.compiler.processing.util.Source
+import androidx.room.compiler.processing.util.getMethod
+import androidx.room.compiler.processing.util.runProcessorTestIncludingKsp
+import com.google.common.truth.Truth.assertThat
+import com.squareup.javapoet.ParameterizedTypeName
+import com.squareup.javapoet.WildcardTypeName
+import org.junit.Test
+
+class XExecutableTypeTest {
+ @Test
+ fun inheritanceResolution() {
+ val src = Source.kotlin(
+ "Foo.kt", """
+ interface MyInterface<T> {
+ fun getT(): T
+ fun setT(t:T): Unit
+ suspend fun suspendGetT(): T
+ suspend fun suspendSetT(t:T): Unit
+ }
+ abstract class Subject : MyInterface<String>
+ """.trimIndent()
+ )
+ runProcessorTestIncludingKsp(
+ sources = listOf(src)
+ ) { invocation ->
+ val myInterface = invocation.processingEnv.requireTypeElement("MyInterface")
+
+ // helper method to get executable types both from sub class and also as direct child of
+ // the given type
+ fun checkMethods(
+ methodName: String,
+ vararg subjects: XTypeElement,
+ callback: (XMethodType) -> Unit
+ ) {
+ assertThat(subjects).isNotEmpty()
+ subjects.forEach {
+ callback(myInterface.getMethod(methodName).asMemberOf(it.type))
+ callback(it.getMethod(methodName).executableType)
+ }
+ }
+
+ val subject = invocation.processingEnv.requireTypeElement("Subject")
+ checkMethods("getT", subject) { type ->
+ assertThat(type.parameterTypes).isEmpty()
+ assertThat(type.returnType.typeName).isEqualTo(invocation.types.string)
+ }
+ checkMethods("setT", subject) { type ->
+ assertThat(type.parameterTypes).containsExactly(
+ invocation.processingEnv.requireType(invocation.types.string)
+ )
+ assertThat(type.returnType.typeName).isEqualTo(invocation.types.voidOrUnit)
+ }
+ checkMethods("suspendGetT", subject) { type ->
+ assertThat(type.parameterTypes.first().typeName).isEqualTo(
+ ParameterizedTypeName.get(
+ KotlinTypeNames.CONTINUATION_CLASS_NAME,
+ WildcardTypeName.supertypeOf(invocation.types.string)
+ )
+ )
+ assertThat(type.returnType.typeName).isEqualTo(invocation.types.objectOrAny)
+ }
+ checkMethods("suspendSetT", subject) { type ->
+ assertThat(type.parameterTypes.first().typeName).isEqualTo(
+ invocation.types.string
+ )
+ assertThat(type.parameterTypes[1].typeName).isEqualTo(
+ ParameterizedTypeName.get(
+ KotlinTypeNames.CONTINUATION_CLASS_NAME,
+ WildcardTypeName.supertypeOf(KotlinTypeNames.UNIT_CLASS_NAME)
+ )
+ )
+ assertThat(type.returnType.typeName).isEqualTo(invocation.types.objectOrAny)
+ }
+ }
+ }
+
+ @Test
+ fun kotlinPropertyInheritance() {
+ val src = Source.kotlin(
+ "Foo.kt", """
+ interface MyInterface<T> {
+ val immutableT: T
+ var mutableT: T?
+ val list: List<T>
+ val nullableList: List<T?>
+ }
+ abstract class Subject : MyInterface<String>
+ abstract class NullableSubject: MyInterface<String?>
+ """.trimIndent()
+ )
+ runProcessorTestIncludingKsp(sources = listOf(src)) { invocation ->
+ val myInterface = invocation.processingEnv.requireTypeElement("MyInterface")
+
+ // helper method to get executable types both from sub class and also as direct child of
+ // the given type
+ fun checkMethods(
+ methodName: String,
+ vararg subjects: XTypeElement,
+ callback: (XMethodType) -> Unit
+ ) {
+ assertThat(subjects).isNotEmpty()
+ subjects.forEach {
+ callback(myInterface.getMethod(methodName).asMemberOf(it.type))
+ callback(it.getMethod(methodName).executableType)
+ }
+ }
+
+ val subject = invocation.processingEnv.requireTypeElement("Subject")
+ checkMethods("getImmutableT", subject) { method ->
+ assertThat(method.returnType.typeName).isEqualTo(invocation.types.string)
+ if (invocation.isKsp) {
+ // we don't get proper nullable here for kapt
+ // partially related to b/169629272
+ assertThat(method.returnType.nullability).isEqualTo(XNullability.NONNULL)
+ }
+
+ assertThat(method.parameterTypes).isEmpty()
+ assertThat(method.typeVariableNames).isEmpty()
+ }
+ checkMethods("getMutableT", subject) { method ->
+ assertThat(method.returnType.typeName).isEqualTo(invocation.types.string)
+ if (invocation.isKsp) {
+ // we don't get proper nullable here for kapt
+ // partially related to b/169629272
+ assertThat(method.returnType.nullability).isEqualTo(XNullability.NULLABLE)
+ }
+ assertThat(method.parameterTypes).isEmpty()
+ assertThat(method.typeVariableNames).isEmpty()
+ }
+ checkMethods("setMutableT", subject) { method ->
+ assertThat(method.returnType.typeName).isEqualTo(invocation.types.voidOrUnit)
+ assertThat(method.parameterTypes.first().nullability)
+ .isEqualTo(XNullability.NULLABLE)
+ assertThat(method.parameterTypes.first().typeName)
+ .isEqualTo(invocation.types.string)
+ assertThat(method.typeVariableNames).isEmpty()
+ }
+ checkMethods("getList", subject) { method ->
+ assertThat(method.returnType.typeName).isEqualTo(
+ ParameterizedTypeName.get(
+ invocation.types.list,
+ invocation.types.string
+ )
+ )
+ assertThat(method.returnType.nullability).isEqualTo(
+ XNullability.NONNULL
+ )
+ if (invocation.isKsp) {
+ // kapt cannot read type parameter nullability yet
+ assertThat(
+ method.returnType.asDeclaredType().typeArguments.first().nullability
+ ).isEqualTo(
+ XNullability.NONNULL
+ )
+ }
+ }
+
+ val nullableSubject = invocation.processingEnv.requireTypeElement("NullableSubject")
+ // check that nullability is inferred from type parameters as well
+ checkMethods("getImmutableT", nullableSubject) { method ->
+ assertThat(method.returnType.typeName).isEqualTo(invocation.types.string)
+ if (invocation.isKsp) {
+ // we don't get proper nullable here for kapt
+ // partially related to b/169629272
+ assertThat(method.returnType.nullability).isEqualTo(XNullability.NULLABLE)
+ }
+ assertThat(method.parameterTypes).isEmpty()
+ assertThat(method.typeVariableNames).isEmpty()
+ }
+
+ checkMethods("getMutableT", nullableSubject) { method ->
+ assertThat(method.returnType.typeName).isEqualTo(invocation.types.string)
+ if (invocation.isKsp) {
+ // we don't get proper nullable here for kapt
+ // partially related to b/169629272
+ assertThat(method.returnType.nullability).isEqualTo(XNullability.NULLABLE)
+ }
+ assertThat(method.parameterTypes).isEmpty()
+ assertThat(method.typeVariableNames).isEmpty()
+ }
+
+ checkMethods("setMutableT", nullableSubject) { method ->
+ assertThat(method.returnType.typeName).isEqualTo(invocation.types.voidOrUnit)
+ assertThat(method.parameterTypes.first().nullability)
+ .isEqualTo(XNullability.NULLABLE)
+ assertThat(method.parameterTypes.first().typeName)
+ .isEqualTo(invocation.types.string)
+ assertThat(method.typeVariableNames).isEmpty()
+ }
+
+ checkMethods("getList", nullableSubject) { method ->
+ assertThat(method.returnType.typeName).isEqualTo(
+ ParameterizedTypeName.get(
+ invocation.types.list,
+ invocation.types.string
+ )
+ )
+ assertThat(method.returnType.nullability).isEqualTo(
+ XNullability.NONNULL
+ )
+ if (invocation.isKsp) {
+ assertThat(
+ method.returnType.asDeclaredType().typeArguments.first().nullability
+ ).isEqualTo(
+ XNullability.NULLABLE
+ )
+ }
+ }
+ checkMethods("getNullableList", subject, nullableSubject) { method ->
+ assertThat(method.returnType.typeName).isEqualTo(
+ ParameterizedTypeName.get(
+ invocation.types.list,
+ invocation.types.string
+ )
+ )
+ assertThat(method.returnType.nullability).isEqualTo(
+ XNullability.NONNULL
+ )
+ if (invocation.isKsp) {
+ assertThat(
+ method.returnType.asDeclaredType().typeArguments.first().nullability
+ ).isEqualTo(
+ XNullability.NULLABLE
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/KotlinTypeNames.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/KotlinTypeNames.kt
index 32d77be..644a0a3 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/KotlinTypeNames.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/KotlinTypeNames.kt
@@ -27,4 +27,5 @@
val MUTABLELIST_CLASS_NAME = ClassName.get("kotlin.collections", "MutableList")
val MAP_CLASS_NAME = ClassName.get("kotlin.collections", "Map")
val PAIR_CLASS_NAME = ClassName.get(Pair::class.java)
+ val CONTINUATION_CLASS_NAME = ClassName.get("kotlin.coroutines", "Continuation")
}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/TestInvocation.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/TestInvocation.kt
index 9398adf..9411922 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/TestInvocation.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/TestInvocation.kt
@@ -25,6 +25,8 @@
class TestInvocation(
val processingEnv: XProcessingEnv
) {
+ val isKsp = processingEnv is KspProcessingEnv
+
val kspResolver: Resolver
get() = (processingEnv as KspProcessingEnv).resolver
@@ -35,7 +37,8 @@
voidOrUnit = KotlinTypeNames.UNIT_CLASS_NAME,
objectOrAny = KotlinTypeNames.ANY_CLASS_NAME,
boxedInt = KotlinTypeNames.INT_CLASS_NAME,
- int = KotlinTypeNames.INT_CLASS_NAME
+ int = KotlinTypeNames.INT_CLASS_NAME,
+ list = KotlinTypeNames.LIST_CLASS_NAME
)
} else {
Types(
@@ -43,7 +46,8 @@
voidOrUnit = TypeName.VOID,
objectOrAny = TypeName.OBJECT,
boxedInt = TypeName.INT.box(),
- int = TypeName.INT
+ int = TypeName.INT,
+ list = ClassName.get("java.util", "List")
)
}
}
@@ -57,6 +61,7 @@
val voidOrUnit: TypeName,
val objectOrAny: ClassName,
val boxedInt: TypeName,
- val int: TypeName
+ val int: TypeName,
+ val list: ClassName
)
}