Merge changes I271171cf,I8d690387 into androidx-master-dev
* changes:
Introduce KspPrimitive Type
Add ability to get TypeName from JVM signature
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/JavaPoetExt.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/JavaPoetExt.kt
index 8b3859b..268a5f7 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/JavaPoetExt.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/JavaPoetExt.kt
@@ -63,6 +63,28 @@
}
/**
+ * Returns the unboxed TypeName for this if it can be unboxed, otherwise, returns this.
+ */
+internal fun TypeName.tryUnbox(): TypeName {
+ return if (isBoxedPrimitive) {
+ unbox()
+ } else {
+ this
+ }
+}
+
+/**
+ * Returns the boxed TypeName for this if it can be unboxed, otherwise, returns this.
+ */
+internal fun TypeName.tryBox(): TypeName {
+ return try {
+ box()
+ } catch (err: AssertionError) {
+ this
+ }
+}
+
+/**
* Helper class to create overrides for XExecutableElements with final parameters and correct
* parameter names read from Kotlin Metadata.
*/
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtils.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtils.kt
index 2105173..05f2e59 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtils.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtils.kt
@@ -17,6 +17,9 @@
package androidx.room.compiler.processing.javac.kotlin
import com.google.auto.common.MoreTypes
+import com.squareup.javapoet.ArrayTypeName
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.TypeName
import javax.lang.model.element.Element
import javax.lang.model.element.ExecutableElement
import javax.lang.model.element.NestingKind
@@ -95,6 +98,53 @@
else -> error("Unknown primitive type $this")
}
+// see https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.2-200
+internal fun String.typeNameFromJvmSignature(): TypeName {
+ check(isNotEmpty())
+ return when (this[0]) {
+ 'B' -> TypeName.BYTE
+ 'C' -> TypeName.CHAR
+ 'D' -> TypeName.DOUBLE
+ 'F' -> TypeName.FLOAT
+ 'I' -> TypeName.INT
+ 'J' -> TypeName.LONG
+ 'S' -> TypeName.SHORT
+ 'Z' -> TypeName.BOOLEAN
+ 'L' -> {
+ val end = lastIndexOf(";")
+ check(end > 0) {
+ "invalid input $this"
+ }
+ val simpleNamesSeparator = lastIndexOf('/')
+ val simpleNamesStart = if (simpleNamesSeparator < 0) {
+ 1 // first char is 'L'
+ } else {
+ simpleNamesSeparator + 1
+ }
+ val packageName = if (simpleNamesSeparator < 0) {
+ // no package name
+ ""
+ } else {
+ substring(1, simpleNamesSeparator).replace('/', '.')
+ }
+ val firstSimpleNameSeparator = indexOf('$', startIndex = simpleNamesStart)
+ return if (firstSimpleNameSeparator < 0) {
+ // not nested
+ ClassName.get(packageName, substring(simpleNamesStart, end))
+ } else {
+ // nested class
+ val firstSimpleName = substring(simpleNamesStart, firstSimpleNameSeparator)
+ val restOfSimpleNames = substring(firstSimpleNameSeparator + 1, end)
+ .split('$')
+ .toTypedArray()
+ ClassName.get(packageName, firstSimpleName, *restOfSimpleNames)
+ }
+ }
+ '[' -> ArrayTypeName.of(substring(1).typeNameFromJvmSignature())
+ else -> error("unexpected jvm signature $this")
+ }
+}
+
internal fun TypeMirror.descriptor(): String = accept(JvmDescriptorTypeVisitor, Unit)
@Suppress("unused")
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeExt.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeExt.kt
index fe0ba08..7a39e00 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeExt.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeExt.kt
@@ -118,4 +118,8 @@
return checkNotNull(type?.resolve()) {
"KSTypeArgument.type should not have been null, please file a bug. $this"
}
+}
+
+internal fun KSTypeReference.isTypeParameterReference(): Boolean {
+ return this.resolve().declaration is KSTypeParameter
}
\ No newline at end of file
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 6df5430..4e308fb 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,12 @@
) : XAnnotationBox<T> {
override fun getAsType(methodName: String): XType? {
val value = getFieldValue<KSType>(methodName)
- return value?.let(env::wrap)
+ return value?.let(env::wrapDeclared)
}
override fun getAsTypeList(methodName: String): List<XType> {
val values = getFieldValue<List<KSType>>(methodName) ?: return emptyList()
- return values.map(env::wrap)
+ return values.map(env::wrapDeclared)
}
override fun <R : Annotation> getAsAnnotationBox(methodName: String): XAnnotationBox<R> {
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspDeclaredType.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspDeclaredType.kt
index 8b630ed..85752cd 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspDeclaredType.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspDeclaredType.kt
@@ -18,8 +18,8 @@
import androidx.room.compiler.processing.XDeclaredType
import androidx.room.compiler.processing.XType
-import com.squareup.javapoet.TypeName
import com.google.devtools.ksp.symbol.KSType
+import com.squareup.javapoet.TypeName
internal open class KspDeclaredType(
env: KspProcessingEnv,
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 7e2d647..728033e 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
@@ -43,7 +43,12 @@
resolver = env.resolver,
functionDeclaration = method.declaration,
ksType = method.containing.declaration.asStarProjectedType()
- ).let(env::wrap)
+ ).let {
+ env.wrap(
+ originatingReference = parameter.type!!, // as member of doesn't allow nulls
+ ksType = it
+ )
+ }
}
override fun asMemberOf(other: XDeclaredType): XType {
@@ -55,7 +60,12 @@
resolver = env.resolver,
functionDeclaration = method.declaration,
ksType = other.ksType
- ).let(env::wrap)
+ ).let {
+ env.wrap(
+ originatingReference = parameter.type!!, // as member of doesn't allow nulls
+ ksType = it
+ )
+ }
}
override fun kindName(): String {
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspFieldElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspFieldElement.kt
index 5bdbddd..e997671 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspFieldElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspFieldElement.kt
@@ -47,7 +47,10 @@
}
override val type: XType by lazy {
- env.wrap(declaration.typeAsMemberOf(env.resolver, containing.type.ksType))
+ env.wrap(
+ originatingReference = declaration.type,
+ ksType = declaration.typeAsMemberOf(env.resolver, containing.type.ksType)
+ )
}
override fun asMemberOf(other: XDeclaredType): XType {
@@ -56,7 +59,10 @@
}
check(other is KspType)
val asMember = declaration.typeAsMemberOf(env.resolver, other.ksType)
- return env.wrap(asMember)
+ return env.wrap(
+ originatingReference = declaration.type,
+ ksType = asMember
+ )
}
fun copyTo(newContaining: KspTypeElement) = KspFieldElement(
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 74c2e38..ab01a0b 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
@@ -114,7 +114,7 @@
override fun isSuspendFunction() = true
override val returnType: XType by lazy {
- env.wrap(env.resolver.builtIns.anyType.makeNullable())
+ env.wrapDeclared(env.resolver.builtIns.anyType.makeNullable())
}
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 cca29f31..218643a 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
@@ -52,7 +52,8 @@
) : KspMethodType(env, origin, containing) {
override val returnType: XType by lazy {
env.wrap(
- origin.declaration.returnTypeAsMemberOf(
+ originatingReference = origin.declaration.returnType!!,
+ ksType = origin.declaration.returnTypeAsMemberOf(
resolver = env.resolver,
ksType = containing.ksType
)
@@ -70,8 +71,9 @@
get() = origin.returnType
override fun getSuspendFunctionReturnType(): XType {
- return env.wrap(
- origin.declaration.returnTypeAsMemberOf(
+ // suspend functions work w/ continuation so it is always declared
+ return env.wrapDeclared(
+ ksType = origin.declaration.returnTypeAsMemberOf(
resolver = env.resolver,
ksType = containing.ksType
)
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
new file mode 100644
index 0000000..21af989
--- /dev/null
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspPrimitiveType.kt
@@ -0,0 +1,45 @@
+/*
+ * 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 com.google.devtools.ksp.symbol.KSType
+import com.squareup.javapoet.TypeName
+
+/**
+ * This tries to mimic primitive types in Kotlin.
+ *
+ * Primitiveness of a type cannot always be driven from itself (e.g. its nullability).
+ * For instance, a kotlin.Int might be non-null but still be non primitive if it is derived from a
+ * generic type argument or is part of type parameters.
+ */
+internal class KspPrimitiveType(
+ env: KspProcessingEnv,
+ ksType: KSType
+) : KspType(env, ksType) {
+ override val typeName: TypeName by lazy {
+ // TODO once we generate type names in java realm, this custom conversion won't be necessary
+ // for now, temporarily, we only do conversion here in place
+ return@lazy checkNotNull(
+ KspTypeMapper.getPrimitiveJavaTypeName(
+ ksType.declaration.qualifiedName!!.asString()
+ )
+ ) {
+ "Internal error. Should've found a java primitive for " +
+ "${ksType.declaration.qualifiedName}"
+ }
+ }
+}
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 41d2747..c752c97 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
@@ -24,6 +24,7 @@
import androidx.room.compiler.processing.XType
import androidx.room.compiler.processing.XTypeElement
import androidx.room.compiler.processing.javac.XTypeElementStore
+import com.google.devtools.ksp.getClassDeclarationByName
import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.processing.Resolver
@@ -32,6 +33,7 @@
import com.google.devtools.ksp.symbol.KSTypeArgument
import com.google.devtools.ksp.symbol.KSTypeParameter
import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.Nullability
import com.google.devtools.ksp.symbol.Variance
internal class KspProcessingEnv(
@@ -44,7 +46,7 @@
private val typeElementStore =
XTypeElementStore { qName ->
resolver.getClassDeclarationByName(
- resolver.getKSNameFromString(qName)
+ KspTypeMapper.swapWithKotlinType(qName)
)?.let {
KspTypeElement(
env = this,
@@ -64,8 +66,12 @@
}
override fun findType(qName: String): XType? {
- return resolver.findClass(qName)?.let {
- wrap(it.asStarProjectedType())
+ val kotlinTypeName = KspTypeMapper.swapWithKotlinType(qName)
+ return resolver.findClass(kotlinTypeName)?.let {
+ wrap(
+ allowPrimitives = KspTypeMapper.isJavaPrimitiveType(qName),
+ ksType = it.asStarProjectedType()
+ )
}
}
@@ -90,7 +96,7 @@
variance = Variance.INVARIANT
)
}
- return wrap(
+ return wrapDeclared(
type.declaration.asType(typeArguments)
)
}
@@ -112,21 +118,44 @@
)
}
- fun wrap(ksType: KSType): KspDeclaredType {
- return if (ksType.declaration.qualifiedName?.asString() == KOTLIN_ARRAY_Q_NAME) {
- KspArrayType(
- env = this,
- ksType = ksType
- )
- } else {
- KspDeclaredType(this, ksType)
- }
+ /**
+ * 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
}
- fun wrap(ksTypeReference: KSTypeReference): KspDeclaredType {
- return wrap(ksTypeReference.resolve())
+ /**
+ * Wraps the given `ksType`.
+ *
+ * The [originatingReference] is used to calculate whether the given [ksType] can be a
+ * primitive or not.
+ */
+ fun wrap(
+ originatingReference: KSTypeReference,
+ ksType: KSType
+ ): KspType {
+ return wrap(
+ ksType = ksType,
+ allowPrimitives = !originatingReference.isTypeParameterReference()
+ )
}
+ /**
+ * Wraps the given [typeReference] in to a [KspType].
+ */
+ fun wrap(
+ typeReference: KSTypeReference
+ ) = wrap(
+ originatingReference = typeReference,
+ ksType = typeReference.resolve()
+ )
+
fun wrap(ksTypeParam: KSTypeParameter, ksTypeArgument: KSTypeArgument): KspTypeArgumentType {
return KspTypeArgumentType(
env = this,
@@ -135,6 +164,33 @@
)
}
+ /**
+ * Wraps the given KSType into a KspType.
+ *
+ * Certain Kotlin types might be primitives in Java but such information cannot be derived
+ * just by looking at the type itself.
+ * 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 {
+ val qName = ksType.declaration.qualifiedName?.asString()
+ if (allowPrimitives && qName != null && ksType.nullability == Nullability.NOT_NULL) {
+ // check for primitives
+ val javaPrimitive = KspTypeMapper.getPrimitiveJavaTypeName(qName)
+ if (javaPrimitive != null) {
+ return KspPrimitiveType(this, ksType)
+ }
+ }
+ return if (qName == KOTLIN_ARRAY_Q_NAME) {
+ KspArrayType(
+ env = this,
+ ksType = ksType
+ )
+ } else {
+ KspDeclaredType(this, ksType)
+ }
+ }
+
fun wrapClassDeclaration(declaration: KSClassDeclaration): KspTypeElement {
return KspTypeElement(
env = 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 fecc613..3b825dd 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
@@ -118,7 +118,17 @@
override fun isTypeOf(other: KClass<*>): Boolean {
// closest to what MoreTypes#isTypeOf does.
- return rawType.typeName.toString() == other.qualifiedName
+ // TODO once we move TypeNames to java realm, we will be able to check just using that
+ // (+ boxing). Fow now, this code stays flexible and checks for all variations as
+ // only primitives use java types now.
+ val rawTypeName = rawType.typeName
+ // other might be something like Kotlin.Int which would map to primitive int (when
+ // invoked with .java) hence we need to check the qualified name for both.
+ // similar case for lists.
+ val javaQName = other.java.canonicalName
+ val kotlinQName = other.qualifiedName
+ val myQName = rawTypeName.toString()
+ return myQName == javaQName || myQName == kotlinQName
}
override fun isSameType(other: XType): Boolean {
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 8730aa1..c3bfde7 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
@@ -26,7 +26,6 @@
import androidx.room.compiler.processing.ksp.KspAnnotated.UseSiteFilter.Companion.NO_USE_SITE
import androidx.room.compiler.processing.ksp.synthetic.KspSyntheticConstructorForJava
import androidx.room.compiler.processing.ksp.synthetic.KspSyntheticPropertyMethodElement
-import com.squareup.javapoet.ClassName
import com.google.devtools.ksp.getAllSuperTypes
import com.google.devtools.ksp.getDeclaredFunctions
import com.google.devtools.ksp.getDeclaredProperties
@@ -37,6 +36,7 @@
import com.google.devtools.ksp.symbol.KSPropertyDeclaration
import com.google.devtools.ksp.symbol.Modifier
import com.google.devtools.ksp.symbol.Origin
+import com.squareup.javapoet.ClassName
internal class KspTypeElement(
env: KspProcessingEnv,
@@ -72,7 +72,7 @@
}
override val type: KspDeclaredType by lazy {
- env.wrap(declaration.asStarProjectedType())
+ env.wrapDeclared(declaration.asStarProjectedType())
}
override val superType: XType? by lazy {
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeMapper.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeMapper.kt
new file mode 100644
index 0000000..2ffa3e5
--- /dev/null
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeMapper.kt
@@ -0,0 +1,65 @@
+/*
+ * 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 com.squareup.javapoet.TypeName
+
+/**
+ * Maps java specific types to their kotlin counterparts.
+ * see: https://github.com/google/ksp/issues/126
+ * see: https://github.com/google/ksp/issues/125
+ *
+ * `Resolver.getClassDeclarationByName` returns the java representation of a class even when a
+ * kotlin version of the same class exists. e.g. It returns a KSClassDeclaration representing
+ * `java.lang.String` if queried with `java.lang.String`. Even though this makes sense by itself,
+ * it is inconsistent with the kotlin compiler which will resolve all instances of
+ * `java.lang.String` to `kotlin.String` (even if it is in Java source code).
+ *
+ * Until KSP provides compiler consistent behavior, this helper utility does the mapping for us.
+ *
+ * This list is built from https://kotlinlang.org/docs/reference/java-interop.html#mapped-types.
+ * Hopefully, it will be temporary until KSP provides a utility to do the same conversion.
+ */
+object KspTypeMapper {
+ private val mapping = mutableMapOf<String, String>()
+ private val kotlinTypeToJavaPrimitiveMapping = mapOf(
+ "kotlin.Byte" to TypeName.BYTE,
+ "kotlin.Short" to TypeName.SHORT,
+ "kotlin.Int" to TypeName.INT,
+ "kotlin.Long" to TypeName.LONG,
+ "kotlin.Char" to TypeName.CHAR,
+ "kotlin.Float" to TypeName.FLOAT,
+ "kotlin.Double" to TypeName.DOUBLE,
+ "kotlin.Boolean" to TypeName.BOOLEAN
+ )
+
+ init {
+ // https://kotlinlang.org/docs/reference/java-interop.html#mapped-types
+ kotlinTypeToJavaPrimitiveMapping.forEach {
+ mapping[it.value.toString()] = it.key
+ }
+ // TODO Add non primitives after TypeNames move to the java type realm.
+ }
+
+ fun swapWithKotlinType(javaType: String): String = mapping[javaType] ?: javaType
+
+ fun getPrimitiveJavaTypeName(kotlinType: String) = kotlinTypeToJavaPrimitiveMapping[kotlinType]
+
+ fun isJavaPrimitiveType(qName: String) = mapping[qName]?.let {
+ kotlinTypeToJavaPrimitiveMapping[it]
+ } != null
+}
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 1b5f8f4..42deaa39 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,7 @@
)
)
)
- env.wrap(contType)
+ env.wrapDeclared(contType)
}
override fun asMemberOf(other: XDeclaredType): XType {
@@ -83,7 +83,7 @@
Variance.CONTRAVARIANT
)
val contType = continuation.asType(listOf(returnTypeAsTypeArgument))
- return env.wrap(contType)
+ return env.wrapDeclared(contType)
}
override fun kindName(): String {
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 7b15858..dd1b778 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
@@ -174,7 +174,7 @@
}
override val returnType: XType by lazy {
- env.wrap(
+ env.wrapDeclared(
env.resolver.builtIns.unitType
)
}
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 92d3afe..0e88d66 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
@@ -25,6 +25,7 @@
import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
import com.squareup.javapoet.ParameterizedTypeName
+import com.squareup.javapoet.TypeName
import com.squareup.javapoet.WildcardTypeName
import org.junit.Test
import org.junit.runner.RunWith
@@ -202,7 +203,7 @@
invocation.types.string
)
assertThat(method.parameters[1].type.typeName).isEqualTo(
- invocation.types.int
+ TypeName.INT
)
assertThat(method.isSuspendFunction()).isTrue()
assertThat(method.returnType.typeName).isEqualTo(invocation.types.objectOrAny)
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 2ea0df4..a5a7bc6 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
@@ -139,13 +139,16 @@
}
""".trimIndent()
)
- runProcessorTest(
+ runProcessorTestIncludingKsp(
listOf(source)
) { invocation ->
PRIMITIVE_TYPES.forEach {
val targetType = invocation.processingEnv.findType(it.key)
assertThat(targetType?.typeName).isEqualTo(it.value)
- assertThat(targetType?.boxed()?.typeName).isEqualTo(it.value.box())
+ if (!invocation.isKsp) {
+ // TODO re-enable once we move typenames to the java realm
+ assertThat(targetType?.boxed()?.typeName).isEqualTo(it.value.box())
+ }
}
}
}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtilsTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtilsTest.kt
index 8a3c47f..2c297e0 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtilsTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtilsTest.kt
@@ -19,9 +19,11 @@
import com.google.auto.common.MoreElements
import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
-import com.google.testing.compile.CompileTester
import com.google.testing.compile.JavaFileObjects
import com.google.testing.compile.JavaSourcesSubjectFactory
+import com.squareup.javapoet.ArrayTypeName
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.TypeName
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -96,7 +98,7 @@
"field4:Ljava/util/List;"
)
)
- }.compilesWithoutError()
+ }
}
@Test
@@ -153,7 +155,7 @@
"method9()Ljava/lang/String;"
)
)
- }.compilesWithoutError()
+ }
}
@Test
@@ -179,7 +181,7 @@
) { descriptors ->
assertThat(descriptors)
.isEqualTo(setOf("method1(ZI)V", "method2(C)B", "method3(DF)V", "method4(JS)V"))
- }.compilesWithoutError()
+ }
}
@Test
@@ -215,7 +217,7 @@
"method4()Ljava/util/Map;"
)
)
- }.compilesWithoutError()
+ }
}
@Test
@@ -247,7 +249,7 @@
"method2()Landroidx/room/test/DataClass;"
)
)
- }.compilesWithoutError()
+ }
}
@Test
@@ -296,7 +298,7 @@
"method4()Landroidx/room/test/DataClass\$StaticInnerData;"
)
)
- }.compilesWithoutError()
+ }
}
@Test
@@ -336,7 +338,72 @@
"method4([I)V"
)
)
- }.compilesWithoutError()
+ }
+ }
+
+ @Test
+ fun typeNameFromDescriptor() {
+ val extraJfo =
+ """
+ import androidx.room.test.Describe;
+ class Custom {
+ static class Nested1 {
+ static class Nested2 {
+ @Describe
+ Custom c;
+ @Describe
+ Custom.Nested1 n1;
+ @Describe
+ Custom.Nested1.Nested2 n2;
+ }
+ }
+ }
+ """.toJFO("Custom")
+ singleRun(
+ """
+ package androidx.room.test;
+
+ class Foo {
+ @Describe
+ int x;
+
+ @Describe
+ java.util.Map map;
+
+ @Describe
+ java.util.Map.Entry entry;
+
+ @Describe
+ int[] intArray;
+
+ @Describe
+ int[][] intArrayOfArray;
+ }
+ """.toJFO("androidx.room.test.Foo"),
+ extraJfo
+ ) {
+ assertThat(
+ it.map {
+ // the format is name:type so we strip everything before `:`
+ it.split(':')[1].typeNameFromJvmSignature()
+ }
+ ).containsExactly(
+ TypeName.INT,
+ ClassName.get(Map::class.java),
+ ClassName.get(Map.Entry::class.java),
+ ArrayTypeName.of(
+ TypeName.INT
+ ),
+ ArrayTypeName.of(
+ ArrayTypeName.of(
+ TypeName.INT
+ )
+ ),
+ ClassName.get("", "Custom"),
+ ClassName.get("", "Custom", "Nested1"),
+ ClassName.get("", "Custom", "Nested1", "Nested2"),
+ )
+ }
}
private fun String.toJFO(qName: String): JavaFileObject =
@@ -346,27 +413,31 @@
private fun singleRun(
vararg jfo: JavaFileObject,
handler: (Set<String>) -> Unit
- ): CompileTester {
- return Truth.assertAbout(JavaSourcesSubjectFactory.javaSources())
+ ) {
+ Truth.assertAbout(JavaSourcesSubjectFactory.javaSources())
.that(listOf(describeAnnotation) + jfo)
.processedWith(object : AbstractProcessor() {
override fun process(
annotations: Set<TypeElement>,
roundEnv: RoundEnvironment
): Boolean {
- roundEnv.getElementsAnnotatedWith(annotations.first()).map { element ->
- when (element.kind) {
- FIELD -> MoreElements.asVariable(element).descriptor()
- METHOD, CONSTRUCTOR -> MoreElements.asExecutable(element).descriptor()
- else -> error("Unsupported element to describe.")
- }
- }.toSet().let(handler)
+ if (annotations.isNotEmpty()) {
+ roundEnv.getElementsAnnotatedWith(annotations.first()).map { element ->
+ when (element.kind) {
+ FIELD ->
+ MoreElements.asVariable(element).descriptor()
+ METHOD, CONSTRUCTOR ->
+ MoreElements.asExecutable(element).descriptor()
+ else -> error("Unsupported element to describe.")
+ }
+ }.toSet().let(handler)
+ }
return true
}
- override fun getSupportedOptions(): Set<String> {
+ override fun getSupportedAnnotationTypes(): Set<String> {
return setOf("androidx.room.test.Describe")
}
- })
+ }).compilesWithoutError()
}
}
\ No newline at end of file
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 3944482..5b6e65f 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
@@ -27,7 +27,7 @@
import com.google.devtools.ksp.getClassDeclarationByName
import com.google.devtools.ksp.getDeclaredFunctions
import com.google.devtools.ksp.symbol.KSPropertyDeclaration
-import com.google.devtools.ksp.symbol.KSTypeReference
+import com.squareup.javapoet.TypeName
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -88,14 +88,14 @@
listOf(src),
succeed = false
) { invocation ->
- invocation.requirePropertyType("errorType").let { type ->
+ invocation.requireDeclaredPropertyType("errorType").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.requirePropertyType("listOfErrorType").let { type ->
+ invocation.requireDeclaredPropertyType("listOfErrorType").let { type ->
assertThat(type.isError()).isFalse()
assertThat(type.typeArguments).hasSize(1)
type.typeArguments.single().let { typeArg ->
@@ -120,7 +120,7 @@
listOf(src),
succeed = true
) { invocation ->
- invocation.requirePropertyType("listOfNullableStrings").let { type ->
+ invocation.requireDeclaredPropertyType("listOfNullableStrings").let { type ->
assertThat(type.nullability).isEqualTo(NONNULL)
assertThat(type.typeArguments).hasSize(1)
assertThat(type.asTypeElement().className).isEqualTo(
@@ -136,7 +136,7 @@
}
}
- invocation.requirePropertyType("listOfInts").let { type ->
+ invocation.requireDeclaredPropertyType("listOfInts").let { type ->
assertThat(type.nullability).isEqualTo(NONNULL)
assertThat(type.typeArguments).hasSize(1)
type.typeArguments.single().let { typeArg ->
@@ -172,13 +172,17 @@
listOf(src),
succeed = true
) { invocation ->
- val nullableStringList = invocation.requirePropertyType("listOfNullableStrings")
- val nonNullStringList = invocation.requirePropertyType("listOfNonNullStrings")
+ val nullableStringList = invocation
+ .requireDeclaredPropertyType("listOfNullableStrings")
+ val nonNullStringList = invocation
+ .requireDeclaredPropertyType("listOfNonNullStrings")
assertThat(nullableStringList).isNotEqualTo(nonNullStringList)
assertThat(nonNullStringList).isNotEqualTo(nullableStringList)
- val nullableStringList_2 = invocation.requirePropertyType("listOfNullableStrings_2")
- val nonNullStringList_2 = invocation.requirePropertyType("listOfNonNullStrings_2")
+ val nullableStringList_2 = invocation
+ .requireDeclaredPropertyType("listOfNullableStrings_2")
+ val nonNullStringList_2 = invocation
+ .requireDeclaredPropertyType("listOfNonNullStrings_2")
assertThat(nullableStringList).isEqualTo(nullableStringList_2)
assertThat(nonNullStringList).isEqualTo(nonNullStringList_2)
@@ -216,21 +220,21 @@
succeed = true
) { invocation ->
invocation.requirePropertyType("simple").let {
- assertThat(it.rawType.typeName).isEqualTo(ClassName.get("kotlin", "Int"))
+ assertThat(it.rawType.typeName).isEqualTo(TypeName.INT)
}
- invocation.requirePropertyType("list").let { list ->
+ invocation.requireDeclaredPropertyType("list").let { list ->
assertThat(list.rawType).isNotEqualTo(list)
assertThat(list.typeArguments).isNotEmpty()
assertThat(list.rawType.typeName)
.isEqualTo(ClassName.get("kotlin.collections", "List"))
}
- invocation.requirePropertyType("map").let { map ->
+ invocation.requireDeclaredPropertyType("map").let { map ->
assertThat(map.rawType).isNotEqualTo(map)
assertThat(map.typeArguments).hasSize(2)
assertThat(map.rawType.typeName)
.isEqualTo(ClassName.get("kotlin.collections", "Map"))
}
- invocation.requirePropertyType("listOfMaps").let { listOfMaps ->
+ invocation.requireDeclaredPropertyType("listOfMaps").let { listOfMaps ->
assertThat(listOfMaps.rawType).isNotEqualTo(listOfMaps)
assertThat(listOfMaps.typeArguments).hasSize(1)
}
@@ -450,7 +454,7 @@
.single()
.type
.let {
- invocation.wrap(typeRef = it!!)
+ invocation.processingEnv.wrapDeclared(it!!.resolve())
}
}
assertThat(typeArgs["Bar"]!!.typeName)
@@ -486,7 +490,9 @@
?.first {
it.simpleName.asString() == "wildcardMethod"
} ?: throw AssertionError("cannot find test method")
- val paramType = invocation.wrap(method.parameters.first().type!!)
+ val paramType = invocation.processingEnv.wrapDeclared(
+ method.parameters.first().type!!.resolve()
+ )
val arg1 = paramType.typeArguments.single()
assertThat(arg1.typeName)
.isEqualTo(
@@ -498,17 +504,22 @@
}
}
- private fun TestInvocation.requirePropertyType(name: String): KspDeclaredType {
- (processingEnv as KspProcessingEnv).resolver.getAllFiles().forEach { file ->
- val prop = file.declarations.first {
- it.simpleName.asString() == name
- } as KSPropertyDeclaration
- return wrap(prop.type)
- }
- throw IllegalStateException("cannot find any property with name $name")
+ private fun TestInvocation.requirePropertyType(name: String): KspType {
+ val prop = requireProperty(name)
+ return (processingEnv as KspProcessingEnv).wrap(prop.type)
}
- private fun TestInvocation.wrap(typeRef: KSTypeReference): KspDeclaredType {
- return (processingEnv as KspProcessingEnv).wrap(typeRef)
+ private fun TestInvocation.requireDeclaredPropertyType(name: String): KspDeclaredType {
+ val prop = requireProperty(name)
+ return (processingEnv as KspProcessingEnv).wrapDeclared(prop.type.resolve())
+ }
+
+ private fun TestInvocation.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
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 5e0d428..ab5c68a 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
@@ -42,8 +42,6 @@
voidOrUnit = KotlinTypeNames.UNIT_CLASS_NAME,
objectOrAny = KotlinTypeNames.ANY_CLASS_NAME,
boxedInt = KotlinTypeNames.INT_CLASS_NAME,
- int = KotlinTypeNames.INT_CLASS_NAME,
- long = KotlinTypeNames.LONG_CLASS_NAME,
list = KotlinTypeNames.LIST_CLASS_NAME,
mutableSet = KotlinTypeNames.MUTABLESET_CLASS_NAME
)
@@ -53,8 +51,6 @@
voidOrUnit = TypeName.VOID,
objectOrAny = TypeName.OBJECT,
boxedInt = TypeName.INT.box(),
- int = TypeName.INT,
- long = TypeName.LONG,
list = ClassName.get("java.util", "List"),
mutableSet = ClassName.get("java.util", "Set")
)
@@ -70,8 +66,8 @@
val voidOrUnit: TypeName,
val objectOrAny: ClassName,
val boxedInt: TypeName,
- val int: TypeName,
- val long: TypeName,
+ val int: TypeName = TypeName.INT,
+ val long: TypeName = TypeName.LONG,
val list: ClassName,
val mutableSet: TypeName
)