Status Update
Comments
yb...@google.com <yb...@google.com> #2
Branch: androidx-master-dev
commit b90079595f33f58fece04026a97faa0d243acdb1
Author: Yuichi Araki <yaraki@google.com>
Date: Wed Sep 18 16:55:49 2019
Change the way to detect mismatch between POJO and query
This fixes cursor mismatch warnings with expandProjection.
Bug: 140759491
Test: QueryMethodProcessorTest
Change-Id: I7659002e5e0d1ef60fc1af2a625c0c36da0664d8
M room/compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
M room/compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
M room/compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
M room/compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
M room/compiler/src/test/kotlin/androidx/room/testing/TestProcessor.kt
st...@gmail.com <st...@gmail.com> #3
el...@google.com <el...@google.com>
ap...@google.com <ap...@google.com> #4
Branch: androidx-master-dev
commit bdde5a1a970ddc9007b28de4aa29d60ffa588f08
Author: Yigit Boyar <yboyar@google.com>
Date: Thu Apr 16 16:47:05 2020
Re-factor how errors are dismissed when query is re-written
This CL changes how we handle errors/warnings if query is
re-written.
There was a bug in expandProjection where we would report warnings
for things that Room already fixes automatically (
The solution to that problem (I7659002e5e0d1ef60fc1af2a625c0c36da0664d8)
solved it by deferring validating of columns until after re-write
decision is made. Unfortunately, this required changing PojoRowAdapter
to have a dummy mapping until it is validating, make it hard to use
as it does have a non-null mapping which is not useful.
This CL partially reverts that change and instead rely on the log
deferring logic we have in Context. This way, we don't need to break
the stability of PojoRowAdapter while still having the ability to
drop warnings that room fixes. This will also play nicer when we
have different query re-writing options that can use more information
about the query results.
Bug: 153387066
Bug: 140759491
Test: existing tests pass
Change-Id: I2ec967c763d33d7a3ff02c1a13c6953b460d1e5f
M room/compiler/src/main/kotlin/androidx/room/log/RLog.kt
M room/compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
M room/compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
M room/compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
el...@google.com <el...@google.com>
ap...@google.com <ap...@google.com> #5
Branch: androidx-main
commit 39908b855705e9e0d5f93e29323d7d96ccfdb103
Author: Yigit Boyar <yboyar@google.com>
Date: Fri Dec 18 21:54:23 2020
Handle primitives overriding generics in KSP
When a kotlin class specifies a non-nullable primitive type for a
super's generic argument, kotlin will duplicate methods that receive the
generic as an argument.
This CL changes the KSP override check to ignore those overrides so that
it also reports two methods. Note that this only happens for paremeters
and not return values. For return values, only the boxed one is generated.
To handle the return type boxing, we now use the overridden desclaration
when wrapping types, which lets us choose between primitive and
non-primitive by looking at the declaration.
Bug: 160258066
Bug: 160322705
Test: XExecutableElementTest
Change-Id: Id2fb76748ff014bcabe4543daed211d82d04bd4c
M room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodElement.kt
M room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodType.kt
M room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/ResolverExt.kt
M room/compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
ph...@gmail.com <ph...@gmail.com> #6
The fix doesn't work for a case where the generic type parameter is only used as a parameter to another generic type. I'm using the roomerror.zip from the opening post, with only these two modifications:
interface BaseDao<Key, Value> {
fun getItem(id: Key): Value?
fun delete(id: Collection<Key>) // Previously: fun delete(id: Key)
}
@Dao
interface FooDao: BaseDao<Long, Foo> {
@Query("select * from foo where id=:id")
override fun getItem(id: Long): Foo?
@Query("delete from foo where id IN (:id)") // Previously: @Query("delete from foo where id=:id")
override fun delete(id: Collection<Long>) // Previously: override fun delete(id: Long)
}
Note that if it weren't for the super interface, the delete function accepting Collection<Long>
would be treated perfectly fine by Room. But now it complains:
roomerror/app/build/tmp/kapt3/stubs/debug/com/roomerror/BaseDao.java:11: error: An abstract DAO method must be annotated with one and only one of the following annotations: Insert,Delete,Query,Update,RawQuery
public abstract void delete(@org.jetbrains.annotations.NotNull()
^
I imagine this happens because of some type erasure. For the same reason, it's incredibly difficult for me to work around this issue. If I use a signature with vararg id: Key
instead, Room is happy, but I can't call the function anymore. That's because my call site looks sth like this:
class Manager<Key, Value> {
private val dao: BaseDao<Key, Value>
private val stuff: List<Key>
fun clear() { dao.delete(*stuff.toTypedArray()) } // It seems impossible to convert stuff to vararg when Key is not reified.
}
ph...@gmail.com <ph...@gmail.com> #7
Just realized it might be cleaner to file this as a new bug, as it's not specific to primitives and rather it's specific to type erasure.
ph...@gmail.com <ph...@gmail.com> #8
I believe this test case for room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
might reproduce the underlying problem:
@Test
fun overrideMethodWithGenericTypeArgument() {
val src = Source.kotlin(
"ParentWithGenericTypeArgument.kt",
"""
interface ParentWithGenericTypeArgument: GenericInterface<String> {
override fun child(arg: Collection<String>)
}
interface GenericInterface<T> {
fun child(arg: Collection<T>)
}
""".trimIndent()
)
runProcessorTest(sources = listOf(src)) { invocation ->
val objectMethodNames = invocation.processingEnv.requireTypeElement(Any::class)
.getAllMethods().jvmNames()
fun XMethodElement.signature(
owner: XType
): String {
val methodType = this.asMemberOf(owner)
val params = methodType.parameterTypes.joinToString(",") {
it.typeName.toString()
}
return "$jvmName($params):${returnType.typeName}"
}
fun XTypeElement.allMethodSignatures(): List<String> = getAllMethods().filterNot {
it.jvmName in objectMethodNames
}.map { it.signature(this.type) }.toList()
invocation.processingEnv.requireTypeElement(
"ParentWithGenericTypeArgument"
).let { parent ->
assertWithMessage(parent.qualifiedName).that(
parent.allMethodSignatures()
).containsExactly(
"child(java.util.Collection<java.lang.String>):void"
)
}
}
}
In particular, room-compiler
fails to recognize that child(arg: Collection<String>)
overrides child(arg: Collection<T>)
. Kotlin clearly thinks that it does override, as it doesn't complain about the override
keyword.
ph...@gmail.com <ph...@gmail.com> #9
This problem happens because fun child(arg: Collection<T>)
is converted to void child(@NonNull Collection<? extends T>)
in Java, because Kotlin declares a covariant type parameter Collection<out T>
. This isn't the case for MutableCollection
, so using that instead make things work, though I consider that an ugly workaround.
Description
Component used:
Compiler
Version used:
2.2.4
Devices/Android versions reproduced on:
Any
Consider we have an interface in Kotlin:
And the implementation:
Compiling this yields:
An abstract DAO method must be annotated with one and only one of the following annotations: Insert,Delete,Query,Update,RawQuery public abstract Value getItem(Key id);
This is due to the Kotlin way of handling its primitives and even though the
Key
type will be set correctly tojava.lang.Long
but the method signature will begetItem(long id)
.