Make ksp method element isVarargs mirror the behavior in kapt.
Do not label ksp method element as vararg if the element is a suspend
function, or the vararg isn't the last element. Each parameter element
can be evaluated individually on whether they are varargs.
Bug:285051174
Test: tested with XExecutableElementTest
Change-Id: I6d914fd54d178b52e332ce9f4decdf20d05086c0
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/KotlinPoetExt.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/KotlinPoetExt.kt
index d8258a7..23230b8 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/KotlinPoetExt.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/KotlinPoetExt.kt
@@ -75,7 +75,6 @@
addModifiers(KModifier.SUSPEND)
}
// TODO(b/251316420): Add type variable names
- val isVarArgs = executableElement.isVarArgs()
val parameterTypes = resolvedType.parameterTypes.let {
// Drop the synthetic Continuation param of suspend functions, always at the last
// position.
@@ -86,7 +85,7 @@
val typeName: XTypeName
val modifiers: Array<KModifier>
// TODO(b/253268357): In Kotlin the vararg is not always the last param
- if (isVarArgs && index == parameterTypes.size - 1) {
+ if (executableElement.parameters.get(index).isVarArgs()) {
typeName = (paramType as XArrayType).componentType.asTypeName()
modifiers = arrayOf(KModifier.VARARG)
} else {
@@ -108,4 +107,4 @@
)
}
}
-}
\ No newline at end of file
+}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XExecutableParameterElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XExecutableParameterElement.kt
index 8454bd9..08343c8 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XExecutableParameterElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XExecutableParameterElement.kt
@@ -37,6 +37,11 @@
fun isKotlinPropertyParam(): Boolean
/**
+ * Returns `true` if this parameter is a vararg.
+ */
+ fun isVarArgs(): Boolean
+
+ /**
* The enclosing [XExecutableElement] this parameter belongs to.
*/
override val enclosingElement: XExecutableElement
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt
index 88fe3b7..8c78886 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt
@@ -40,6 +40,10 @@
enclosingElement.isExtensionFunction() &&
enclosingElement.parameters.first() == this
+ override fun isVarArgs() =
+ kotlinMetadata?.isVarArgs() ?: (enclosingElement.isVarArgs() &&
+ enclosingElement.parameters.last() == this)
+
override fun isKotlinPropertyParam() =
enclosingElement is JavacMethodElement &&
enclosingElement.isKotlinPropertyMethod()
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
index 9e8131c..14a4a40 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
@@ -377,6 +377,7 @@
get() = kmValueParameter.flags
val name: String
get() = kmValueParameter.name
+ fun isVarArgs() = kmValueParameter.varargElementType != null
fun isNullable() = type.isNullable()
fun hasDefault() = Flag.ValueParameter.DECLARES_DEFAULT_VALUE(flags)
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt
index f47d467..17a4ee4 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt
@@ -65,7 +65,11 @@
}
override fun isVarArgs(): Boolean {
- return declaration.parameters.any { it.isVararg }
+ // TODO(b/254135327): Revisit with the introduction of a target language.
+ if (this is KspMethodElement && this.isSuspendFunction()) {
+ return false
+ }
+ return declaration.parameters.lastOrNull()?.isVararg ?: false
}
companion object {
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt
index a840aa4..3c52674 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt
@@ -40,6 +40,8 @@
override fun isKotlinPropertyParam() = false
+ override fun isVarArgs() = parameter.isVararg
+
override val name: String
get() = parameter.name?.asString() ?: "_no_param_name"
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt
index de2c250..6a62daf 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt
@@ -52,6 +52,8 @@
override fun isKotlinPropertyParam() = false
+ override fun isVarArgs() = false
+
override val name: String by lazy {
// KAPT uses `$completion` but it doesn't check for conflicts, we do. Be aware that before
// Kotlin 1.8.0 the param was named 'continuation'.
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
index 2067b96..ead1d25 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
@@ -245,6 +245,8 @@
override fun isKotlinPropertyParam() = true
+ override fun isVarArgs() = false
+
override val name: String by lazy {
val originalName = enclosingElement.accessor.parameter.name?.asString()
originalName.sanitizeAsJavaParameterName(0)
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticReceiverParameterElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticReceiverParameterElement.kt
index 0ebf74c..d72cc4e 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticReceiverParameterElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticReceiverParameterElement.kt
@@ -46,6 +46,8 @@
override fun isKotlinPropertyParam() = false
+ override fun isVarArgs() = false
+
override val name: String by lazy {
// KAPT uses `$this$<functionName>`
"$" + "this" + "$" + enclosingElement.name
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
index 91ff9e3..994be2f 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
@@ -126,7 +126,9 @@
"""
interface Subject {
fun method(vararg inputs: String)
- suspend fun suspendMethod(vararg inputs: String);
+ suspend fun suspendMethod(vararg inputs: String)
+ fun method2(vararg inputs: String, arg: Int)
+ fun String.extFun(vararg inputs: String)
}
""".trimIndent()
)
@@ -134,11 +136,34 @@
sources = listOf(subject)
) {
val element = it.processingEnv.requireTypeElement("Subject")
- assertThat(element.getMethodByJvmName("method").isVarArgs()).isTrue()
- if (it.isKsp) {
- assertThat(element.getMethodByJvmName("suspendMethod").isVarArgs()).isTrue()
- } else {
- assertThat(element.getMethodByJvmName("suspendMethod").isVarArgs()).isFalse()
+
+ element.getMethodByJvmName("method").let { method ->
+ assertThat(method.isVarArgs()).isTrue()
+ assertThat(method.parameters).hasSize(1)
+ assertThat(method.parameters.single().isVarArgs()).isTrue()
+ }
+
+ element.getMethodByJvmName("suspendMethod").let { suspendMethod ->
+ assertThat(suspendMethod.isVarArgs()).isFalse()
+ assertThat(suspendMethod.parameters).hasSize(2)
+ assertThat(
+ suspendMethod.parameters.first { it.name == "inputs" }.isVarArgs()
+ ).isTrue()
+ }
+
+ element.getMethodByJvmName("extFun").let { extFun ->
+ assertThat(extFun.isVarArgs()).isTrue()
+ assertThat(extFun.parameters).hasSize(2)
+ // kapt messed with parameter names, sometimes the synthetic parameter can use the
+ // second parameter's name.
+ assertThat(extFun.parameters.get(1).isVarArgs()).isTrue()
+ }
+
+ element.getMethodByJvmName("method2").let { method2 ->
+ assertThat(method2.isVarArgs()).isFalse()
+ assertThat(method2.parameters).hasSize(2)
+ assertThat(method2.parameters.first { it.name == "inputs" }.isVarArgs())
+ .isTrue()
}
}
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt
index 6eeeb49..a737a73 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt
@@ -20,6 +20,7 @@
import androidx.room.compiler.codegen.XCodeBlock
import androidx.room.compiler.codegen.XPropertySpec
import androidx.room.compiler.codegen.XTypeSpec
+import androidx.room.compiler.processing.XExecutableParameterElement
import androidx.room.compiler.processing.XMethodElement
import androidx.room.compiler.processing.XMethodType
import androidx.room.compiler.processing.XSuspendMethodType
@@ -59,7 +60,7 @@
abstract fun extractReturnType(): XType
- abstract fun extractParams(): List<XVariableElement>
+ abstract fun extractParams(): List<XExecutableParameterElement>
fun extractQueryParams(query: ParsedQuery): List<QueryParameter> {
return extractParams().map { variableElement ->
@@ -305,4 +306,4 @@
)
}
}
-}
\ No newline at end of file
+}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/TransactionMethodProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/TransactionMethodProcessor.kt
index 71f283c..8743265 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/TransactionMethodProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/TransactionMethodProcessor.kt
@@ -69,12 +69,10 @@
TransactionMethod.CallType.CONCRETE
}
- val isVarArgs = executableElement.isVarArgs()
val parameters = delegate.extractParams()
- val processedParamNames = parameters.mapIndexed { index, param ->
+ val processedParamNames = parameters.map { param ->
// Apply spread operator when delegating to a vararg parameter in Kotlin.
- if (context.codeLanguage == CodeLanguage.KOTLIN &&
- isVarArgs && index == parameters.size - 1) {
+ if (context.codeLanguage == CodeLanguage.KOTLIN && param.isVarArgs()) {
"*${param.name}"
} else {
param.name