[Jspecify] Use bounds of type parameters for warnings reporting as well
This commit is contained in:
+10
-10
@@ -14,23 +14,23 @@ public class Test {}
|
|||||||
// FILE: main.kt
|
// FILE: main.kt
|
||||||
// jspecify_nullness_mismatch
|
// jspecify_nullness_mismatch
|
||||||
fun main(a1: NullnessUnspecifiedTypeParameter<Any>, a2: NullnessUnspecifiedTypeParameter<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>Any?<!>>, x: Test): Unit {
|
fun main(a1: NullnessUnspecifiedTypeParameter<Any>, a2: NullnessUnspecifiedTypeParameter<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>Any?<!>>, x: Test): Unit {
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
a1.foo(null)
|
a1.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
a1.foo(1)
|
a1.foo(1)
|
||||||
|
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
a2.foo(null)
|
a2.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
a2.foo(1)
|
a2.foo(1)
|
||||||
|
|
||||||
|
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
|
||||||
|
a1.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
// jspecify_nullness_mismatch
|
// jspecify_nullness_mismatch
|
||||||
a1.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, null)
|
a1.bar(x, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
// jspecify_nullness_mismatch{mute}
|
|
||||||
a1.bar(x, null)
|
|
||||||
a1.bar(x, 1)
|
a1.bar(x, 1)
|
||||||
|
|
||||||
|
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
|
||||||
|
a2.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
// jspecify_nullness_mismatch
|
// jspecify_nullness_mismatch
|
||||||
a2.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, null)
|
a2.bar(x, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
// jspecify_nullness_mismatch{mute}
|
|
||||||
a2.bar(x, null)
|
|
||||||
a2.bar(x, 1)
|
a2.bar(x, 1)
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-9
@@ -14,22 +14,23 @@ public class Test {}
|
|||||||
// FILE: main.kt
|
// FILE: main.kt
|
||||||
// jspecify_nullness_mismatch
|
// jspecify_nullness_mismatch
|
||||||
fun main(a1: NullnessUnspecifiedTypeParameter<Any>, a2: NullnessUnspecifiedTypeParameter<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>Any?<!>>, x: Test): Unit {
|
fun main(a1: NullnessUnspecifiedTypeParameter<Any>, a2: NullnessUnspecifiedTypeParameter<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>Any?<!>>, x: Test): Unit {
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
a1.foo(null)
|
a1.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
a1.foo(1)
|
a1.foo(1)
|
||||||
|
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
a2.foo(null)
|
a2.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
a2.foo(1)
|
a2.foo(1)
|
||||||
|
|
||||||
|
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
|
||||||
|
a1.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
// jspecify_nullness_mismatch
|
// jspecify_nullness_mismatch
|
||||||
a1.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, null)
|
a1.bar(x, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
a1.bar(x, null)
|
|
||||||
a1.bar(x, 1)
|
a1.bar(x, 1)
|
||||||
|
|
||||||
|
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
|
||||||
|
a2.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
// jspecify_nullness_mismatch
|
// jspecify_nullness_mismatch
|
||||||
a2.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, null)
|
a2.bar(x, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
// jspecify_nullness_mismatch{mute}
|
|
||||||
a2.bar(x, null)
|
|
||||||
a2.bar(x, 1)
|
a2.bar(x, 1)
|
||||||
}
|
}
|
||||||
Vendored
+10
-10
@@ -37,20 +37,20 @@ public class CKN extends C<@Nullable CK> {}
|
|||||||
// FILE: main.kt
|
// FILE: main.kt
|
||||||
fun main(ak: AK, akn: AKN, bk: BK, ck: CK, ckn: CKN): Unit {
|
fun main(ak: AK, akn: AKN, bk: BK, ck: CK, ckn: CKN): Unit {
|
||||||
ak.foo(ak)
|
ak.foo(ak)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
ak.foo(null)
|
ak.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
|
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
akn.foo(null)
|
akn.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
|
|
||||||
bk.foo(bk)
|
bk.foo(bk)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
bk.foo(null)
|
bk.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
|
|
||||||
ck.foo(ck)
|
ck.foo(ck)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
ck.foo(null)
|
ck.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
|
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
ckn.foo(null)
|
ckn.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
}
|
}
|
||||||
Vendored
+10
-10
@@ -37,20 +37,20 @@ public class CKN extends C<@Nullable CK> {}
|
|||||||
// FILE: main.kt
|
// FILE: main.kt
|
||||||
fun main(ak: AK, akn: AKN, bk: BK, ck: CK, ckn: CKN): Unit {
|
fun main(ak: AK, akn: AKN, bk: BK, ck: CK, ckn: CKN): Unit {
|
||||||
ak.foo(ak)
|
ak.foo(ak)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
ak.foo(null)
|
ak.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
|
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
akn.foo(null)
|
akn.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
|
|
||||||
bk.foo(bk)
|
bk.foo(bk)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
bk.foo(null)
|
bk.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
|
|
||||||
ck.foo(ck)
|
ck.foo(ck)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
ck.foo(null)
|
ck.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
|
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
ckn.foo(null)
|
ckn.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
|
||||||
}
|
}
|
||||||
+4
-4
@@ -38,10 +38,10 @@ fun main(
|
|||||||
// jspecify_nullness_mismatch
|
// jspecify_nullness_mismatch
|
||||||
a.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>aNotNullNullNull<!>)
|
a.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>aNotNullNullNull<!>)
|
||||||
|
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
b.bar(aNotNullNotNullNotNull)
|
b.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>aNotNullNotNullNotNull<!>)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
b.bar(aNotNullNotNullNull)
|
b.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>aNotNullNotNullNull<!>)
|
||||||
b.bar(aNotNullNullNotNull)
|
b.bar(aNotNullNullNotNull)
|
||||||
b.bar(aNotNullNullNull)
|
b.bar(aNotNullNullNull)
|
||||||
}
|
}
|
||||||
+4
-4
@@ -38,10 +38,10 @@ fun main(
|
|||||||
// jspecify_nullness_mismatch
|
// jspecify_nullness_mismatch
|
||||||
a.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>aNotNullNullNull<!>)
|
a.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>aNotNullNullNull<!>)
|
||||||
|
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
b.bar(aNotNullNotNullNotNull)
|
b.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>aNotNullNotNullNotNull<!>)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
b.bar(aNotNullNotNullNull)
|
b.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>aNotNullNotNullNull<!>)
|
||||||
b.bar(aNotNullNullNotNull)
|
b.bar(aNotNullNullNotNull)
|
||||||
b.bar(aNotNullNullNull)
|
b.bar(aNotNullNullNull)
|
||||||
}
|
}
|
||||||
+2
-2
@@ -14,5 +14,5 @@ typealias C2<T> = MapLike<T>
|
|||||||
|
|
||||||
val test1 = C(1, C(2, null))
|
val test1 = C(1, C(2, null))
|
||||||
val test2 = C(1, <!TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH!>C(<!TYPE_MISMATCH, TYPE_MISMATCH!>""<!>, null)<!>)
|
val test2 = C(1, <!TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH!>C(<!TYPE_MISMATCH, TYPE_MISMATCH!>""<!>, null)<!>)
|
||||||
val test23 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION_BASED_ON_JAVA_ANNOTATIONS!>C2(if (true) 1 else null)<!>
|
val test23 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION_BASED_ON_JAVA_ANNOTATIONS!>C2(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>if (true) 1 else null<!>)<!>
|
||||||
val test234 = C2(<!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION_BASED_ON_JAVA_ANNOTATIONS!>C2(if (true) 1 else null)<!>)
|
val test234 = C2(<!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION_BASED_ON_JAVA_ANNOTATIONS!>C2(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>if (true) 1 else null<!>)<!>)
|
||||||
|
|||||||
+32
-20
@@ -411,23 +411,24 @@ class SignatureEnhancement(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val boundsFromTypeParameterForArgument = typeParameterForArgument?.boundsNullability() ?: return result
|
val boundsFromTypeParameterForArgument = typeParameterForArgument?.boundsNullability() ?: return result
|
||||||
if (result == null) return NullabilityQualifierWithMigrationStatus(boundsFromTypeParameterForArgument)
|
if (result == null) return boundsFromTypeParameterForArgument
|
||||||
|
|
||||||
return NullabilityQualifierWithMigrationStatus(
|
return mostSpecific(boundsFromTypeParameterForArgument, result)
|
||||||
mostSpecific(boundsFromTypeParameterForArgument, result.qualifier)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mostSpecific(a: NullabilityQualifier, b: NullabilityQualifier): NullabilityQualifier {
|
private fun mostSpecific(
|
||||||
if (a == NullabilityQualifier.FORCE_FLEXIBILITY) return b
|
a: NullabilityQualifierWithMigrationStatus,
|
||||||
if (b == NullabilityQualifier.FORCE_FLEXIBILITY) return a
|
b: NullabilityQualifierWithMigrationStatus
|
||||||
if (a == NullabilityQualifier.NULLABLE) return b
|
): NullabilityQualifierWithMigrationStatus {
|
||||||
if (b == NullabilityQualifier.NULLABLE) return a
|
if (a.qualifier == NullabilityQualifier.FORCE_FLEXIBILITY) return b
|
||||||
assert(a == b && a == NullabilityQualifier.NOT_NULL) {
|
if (b.qualifier == NullabilityQualifier.FORCE_FLEXIBILITY) return a
|
||||||
|
if (a.qualifier == NullabilityQualifier.NULLABLE) return b
|
||||||
|
if (b.qualifier == NullabilityQualifier.NULLABLE) return a
|
||||||
|
assert(a.qualifier == b.qualifier && a.qualifier == NullabilityQualifier.NOT_NULL) {
|
||||||
"Expected everything is NOT_NULL, but $a and $b are found"
|
"Expected everything is NOT_NULL, but $a and $b are found"
|
||||||
}
|
}
|
||||||
|
|
||||||
return NullabilityQualifier.NOT_NULL
|
return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KotlinType.nullabilityInfoBoundsForTypeParameterUsage(): Pair<NullabilityQualifierWithMigrationStatus?, Boolean> {
|
private fun KotlinType.nullabilityInfoBoundsForTypeParameterUsage(): Pair<NullabilityQualifierWithMigrationStatus?, Boolean> {
|
||||||
@@ -440,20 +441,31 @@ class SignatureEnhancement(
|
|||||||
// void foo(T t); // should be loaded as "fun foo(t: T)" but not as "fun foo(t: T?)"
|
// void foo(T t); // should be loaded as "fun foo(t: T)" but not as "fun foo(t: T?)"
|
||||||
// }
|
// }
|
||||||
return Pair(
|
return Pair(
|
||||||
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL),
|
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL, typeParameterBoundsNullability.isForWarningOnly),
|
||||||
typeParameterBoundsNullability == NullabilityQualifier.NOT_NULL
|
typeParameterBoundsNullability.qualifier == NullabilityQualifier.NOT_NULL
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun TypeParameterDescriptor.boundsNullability(): NullabilityQualifier? {
|
private fun TypeParameterDescriptor.boundsNullability(): NullabilityQualifierWithMigrationStatus? {
|
||||||
// Do not use bounds from Kotlin-defined type parameters
|
// Do not use bounds from Kotlin-defined type parameters
|
||||||
if (this !is LazyJavaTypeParameterDescriptor) return null
|
if (this !is LazyJavaTypeParameterDescriptor || upperBounds.all(KotlinType::isError)) return null
|
||||||
return when {
|
|
||||||
upperBounds.all(KotlinType::isError) -> null
|
if (upperBounds.all(KotlinType::isNullabilityFlexible)) {
|
||||||
upperBounds.all(KotlinType::isNullabilityFlexible) -> null
|
if (upperBounds.any { it is FlexibleTypeWithEnhancement && !it.enhancement.isNullable() }) {
|
||||||
upperBounds.any { !it.isNullable() } -> NullabilityQualifier.NOT_NULL
|
return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL, isForWarningOnly = true)
|
||||||
else -> NullabilityQualifier.NULLABLE
|
}
|
||||||
|
|
||||||
|
if (upperBounds.any { it is FlexibleTypeWithEnhancement && it.enhancement.isNullable() }) {
|
||||||
|
return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE, isForWarningOnly = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val resultingQualifier =
|
||||||
|
if (upperBounds.any { !it.isNullable() }) NullabilityQualifier.NOT_NULL else NullabilityQualifier.NULLABLE
|
||||||
|
|
||||||
|
return NullabilityQualifierWithMigrationStatus(resultingQualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Annotations.extractNullability(
|
private fun Annotations.extractNullability(
|
||||||
|
|||||||
Reference in New Issue
Block a user