Skip to content

Commit

Permalink
KSP: Ignore class element nullability for isAssignable (#9075)
Browse files Browse the repository at this point in the history
* KSP: Ignore class element nullability for isAssignable

* Correct other case

* Correct other case
  • Loading branch information
dstepanov authored Apr 6, 2023
1 parent cc4964d commit 62f68a4
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,6 @@ internal open class KotlinClassElement(

override fun isTypeVariable() = typeVariable

@OptIn(KspExperimental::class)
override fun isAssignable(type: String): Boolean {
val otherDeclaration = visitorContext.resolver.getClassDeclarationByName(type)
if (otherDeclaration != null) {
Expand All @@ -481,11 +480,12 @@ internal open class KotlinClassElement(
if (thisFullName == otherFullName) {
return true
}
val otherKotlinType = otherDeclaration.asStarProjectedType()
if (otherKotlinType == kotlinType) {
val otherKotlinType = otherDeclaration.asStarProjectedType().makeNullable()
val kotlinTypeNullable = kotlinType.makeNullable()
if (otherKotlinType == kotlinTypeNullable) {
return true
}
if (otherKotlinType.isAssignableFrom(kotlinType)) {
if (otherKotlinType.isAssignableFrom(kotlinTypeNullable)) {
return true
}
}
Expand All @@ -499,12 +499,12 @@ internal open class KotlinClassElement(
visitorContext.resolver.getKSNameFromString(type)
) ?: return false
val kotlinClassByName = visitorContext.resolver.getKotlinClassByName(kotlinName) ?: return false
return kotlinClassByName.asStarProjectedType().isAssignableFrom(kotlinType.starProjection())
return kotlinClassByName.asStarProjectedType().makeNullable().isAssignableFrom(kotlinType.starProjection().makeNullable())
}

override fun isAssignable(type: ClassElement): Boolean {
if (type is KotlinClassElement) {
return type.kotlinType.isAssignableFrom(kotlinType)
return type.kotlinType.starProjection().makeNullable().isAssignableFrom(kotlinType.starProjection().makeNullable())
}
return super.isAssignable(type)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1872,19 +1872,54 @@ class Test {
fun method2() : java.util.List<String>? {
return null
}
@Executable
fun method3() : kotlin.collections.List<String>? {
return listOf()
}
}
''', ce -> {
return ce.findMethod("method1").get().getReturnType().isAssignable(Iterable.class)
&& ce.findMethod("method2").get().getReturnType().isAssignable(Iterable.class)
&& ce.findMethod("method3").get().getReturnType().isAssignable(Iterable.class)
&& ((KotlinClassElement) ce.findMethod("method1").get().getReturnType()).isAssignable2(Iterable.class.name)
&& ((KotlinClassElement) ce.findMethod("method2").get().getReturnType()).isAssignable2(Iterable.class.name)
&& ((KotlinClassElement) ce.findMethod("method3").get().getReturnType()).isAssignable2(Iterable.class.name)
})

expect:
isAssignable
}

void "test type isAssignable between nullable and not nullable"() {
when:
boolean isAssignable = buildClassElementMapped('test.Cart', '''
package test
data class CartItem(
val id: Long?,
val name: String,
val cart: Cart?
) {
constructor(name: String) : this(null, name, null)
}
data class Cart(
val id: Long?,
val items: List<CartItem>?
) {
constructor(items: List<CartItem>) : this(null, items)
fun cartItemsNotNullable() : List<CartItem> = listOf()
}
''', cl -> cl.getPrimaryConstructor().get().parameters[1].getType().isAssignable(cl.findMethod("cartItemsNotNullable").get().getReturnType()))
then:
isAssignable
}

private void assertListGenericArgument(ClassElement type, Closure cl) {
def arg1 = type.getAllTypeArguments().get(List.class.name).get("E")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2166,4 +2166,36 @@ class Holder<A : Animal>(
animal instanceof GenericPlaceholder
animal.isTypeVariable()
}

void "test list property"() {
given:
BeanIntrospection introspection = buildBeanIntrospection('test.Cart', '''
package test
import io.micronaut.core.annotation.Introspected
@io.micronaut.core.annotation.Introspected
data class CartItem(
val id: Long?,
val name: String,
val cart: Cart?
) {
constructor(name: String) : this(null, name, null)
}
@io.micronaut.core.annotation.Introspected
data class Cart(
val id: Long?,
val items: List<CartItem>?
) {
constructor(items: List<CartItem>) : this(null, items)
fun cartItemsNotNullable() : List<CartItem> = listOf()
}
''')
def bean = introspection.instantiate(1L, new ArrayList())
bean = introspection.getProperty("items").get().withValue(bean, new ArrayList())
expect:
bean
}
}

0 comments on commit 62f68a4

Please sign in to comment.