Support enhancement for type parameter based types
Load them as non-flexible when a relevant type parameter has non-flexible upper bound (Currently, it only works for case of codeanalysis annotations)
This commit is contained in:
committed by
Victor Petukhov
parent
fa2578c795
commit
e9e05c53e1
+43
@@ -0,0 +1,43 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
|
||||||
|
// FILE: A.java
|
||||||
|
|
||||||
|
import jspecify.annotations.*;
|
||||||
|
|
||||||
|
public class A<T extends @Nullable Object> {
|
||||||
|
public void foo(T t) {}
|
||||||
|
public <E extends @Nullable Object> void bar(E e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: B.java
|
||||||
|
|
||||||
|
import jspecify.annotations.*;
|
||||||
|
|
||||||
|
@DefaultNullable
|
||||||
|
public class B<T> {
|
||||||
|
public void foo(T t) {}
|
||||||
|
public <E> void bar(E e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
fun main(a1: A<Any?>, a2: A<String>, b1: B<Any?>, b2: B<String>) {
|
||||||
|
a1.foo(null)
|
||||||
|
a1.bar<String?>(null)
|
||||||
|
a1.bar<String>(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||||
|
a1.bar<String>("")
|
||||||
|
|
||||||
|
a2.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||||
|
a2.bar<String?>(null)
|
||||||
|
a2.bar<String>(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||||
|
a2.bar<String>("")
|
||||||
|
|
||||||
|
b1.foo(null)
|
||||||
|
b1.bar<String?>(null)
|
||||||
|
b1.bar<String>(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||||
|
b1.bar<String>("")
|
||||||
|
|
||||||
|
b2.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||||
|
b2.bar<String?>(null)
|
||||||
|
b2.bar<String>(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||||
|
b2.bar<String>("")
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun main(/*0*/ a1: A<kotlin.Any?>, /*1*/ a2: A<kotlin.String>, /*2*/ b1: B<kotlin.Any?>, /*3*/ b2: B<kotlin.String>): kotlin.Unit
|
||||||
|
|
||||||
|
public open class A</*0*/ T> {
|
||||||
|
public constructor A</*0*/ T>()
|
||||||
|
public open fun </*0*/ E> bar(/*0*/ e: E): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open fun foo(/*0*/ t: T): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
@jspecify.annotations.DefaultNullable public open class B</*0*/ T> {
|
||||||
|
public constructor B</*0*/ T>()
|
||||||
|
public open fun </*0*/ E> bar(/*0*/ e: E): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open fun foo(/*0*/ t: T): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
+4
-4
@@ -21,12 +21,12 @@ public class B<T> {
|
|||||||
// FILE: main.kt
|
// FILE: main.kt
|
||||||
|
|
||||||
fun main(a1: A<<!UPPER_BOUND_VIOLATED!>Any?<!>>, a2: A<String>, b1: B<<!UPPER_BOUND_VIOLATED!>Any?<!>>, b2: B<String>) {
|
fun main(a1: A<<!UPPER_BOUND_VIOLATED!>Any?<!>>, a2: A<String>, b1: B<<!UPPER_BOUND_VIOLATED!>Any?<!>>, b2: B<String>) {
|
||||||
a1.foo(null)
|
a1.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||||
a1.bar<<!UPPER_BOUND_VIOLATED!>String?<!>>(null)
|
a1.bar<<!UPPER_BOUND_VIOLATED!>String?<!>>(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||||
a1.bar<String>("")
|
a1.bar<String>("")
|
||||||
|
|
||||||
a2.foo(null)
|
a2.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||||
a2.bar<<!UPPER_BOUND_VIOLATED!>String?<!>>(null)
|
a2.bar<<!UPPER_BOUND_VIOLATED!>String?<!>>(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||||
a2.bar<String>("")
|
a2.bar<String>("")
|
||||||
|
|
||||||
b1.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
b1.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||||
|
|||||||
+2
-2
@@ -4,9 +4,9 @@ public fun main(/*0*/ a1: A<kotlin.Any?>, /*1*/ a2: A<kotlin.String>, /*2*/ b1:
|
|||||||
|
|
||||||
public open class A</*0*/ T : @jspecify.annotations.NotNull kotlin.Any> {
|
public open class A</*0*/ T : @jspecify.annotations.NotNull kotlin.Any> {
|
||||||
public constructor A</*0*/ T : @jspecify.annotations.NotNull kotlin.Any>()
|
public constructor A</*0*/ T : @jspecify.annotations.NotNull kotlin.Any>()
|
||||||
public open fun </*0*/ E : @jspecify.annotations.NotNull kotlin.Any> bar(/*0*/ e: E!): kotlin.Unit
|
public open fun </*0*/ E : @jspecify.annotations.NotNull kotlin.Any> bar(/*0*/ e: E): kotlin.Unit
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
public open fun foo(/*0*/ t: T!): kotlin.Unit
|
public open fun foo(/*0*/ t: T): kotlin.Unit
|
||||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
}
|
}
|
||||||
|
|||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
|
||||||
|
// FILE: A.java
|
||||||
|
|
||||||
|
import jspecify.annotations.*;
|
||||||
|
|
||||||
|
public class A<T> {
|
||||||
|
public void foo(T t) {}
|
||||||
|
|
||||||
|
@DefaultNotNull
|
||||||
|
public void bar(String s, T t) {} // t should not become not nullable
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
fun main(a1: A<Int>, a2: A<Int?>) {
|
||||||
|
a1.foo(null)
|
||||||
|
a1.foo(1)
|
||||||
|
|
||||||
|
a2.foo(null)
|
||||||
|
a2.foo(1)
|
||||||
|
|
||||||
|
a1.bar(<!NULL_FOR_NONNULL_TYPE!>null<!>, null)
|
||||||
|
a1.bar("", null)
|
||||||
|
a1.bar("", 1)
|
||||||
|
|
||||||
|
a2.bar(<!NULL_FOR_NONNULL_TYPE!>null<!>, null)
|
||||||
|
a2.bar("", null)
|
||||||
|
a2.bar("", 1)
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun main(/*0*/ a1: A<kotlin.Int>, /*1*/ a2: A<kotlin.Int?>): kotlin.Unit
|
||||||
|
|
||||||
|
public open class A</*0*/ T : kotlin.Any!> {
|
||||||
|
public constructor A</*0*/ T : kotlin.Any!>()
|
||||||
|
@jspecify.annotations.DefaultNotNull public open fun bar(/*0*/ s: kotlin.String, /*1*/ t: T!): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open fun foo(/*0*/ t: T!): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
+10
@@ -60,6 +60,11 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated extends
|
|||||||
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.kt");
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nonPlatformTypeParameter.kt")
|
||||||
|
public void testNonPlatformTypeParameter() throws Exception {
|
||||||
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/nonPlatformTypeParameter.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt");
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt");
|
||||||
@@ -69,6 +74,11 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated extends
|
|||||||
public void testTypeParameterBounds() throws Exception {
|
public void testTypeParameterBounds() throws Exception {
|
||||||
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt");
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("unknownNullnessTypeParameter.kt")
|
||||||
|
public void testUnknownNullnessTypeParameter() throws Exception {
|
||||||
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/unknownNullnessTypeParameter.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
|
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
|
||||||
|
|||||||
+10
@@ -60,6 +60,11 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTe
|
|||||||
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.kt");
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nonPlatformTypeParameter.kt")
|
||||||
|
public void testNonPlatformTypeParameter() throws Exception {
|
||||||
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/nonPlatformTypeParameter.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt");
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt");
|
||||||
@@ -69,6 +74,11 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTe
|
|||||||
public void testTypeParameterBounds() throws Exception {
|
public void testTypeParameterBounds() throws Exception {
|
||||||
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt");
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("unknownNullnessTypeParameter.kt")
|
||||||
|
public void testUnknownNullnessTypeParameter() throws Exception {
|
||||||
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/unknownNullnessTypeParameter.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
|
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
|
||||||
|
|||||||
Generated
+10
@@ -60,6 +60,11 @@ public class ForeignJava8AnnotationsTestGenerated extends AbstractForeignJava8An
|
|||||||
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.kt");
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nonPlatformTypeParameter.kt")
|
||||||
|
public void testNonPlatformTypeParameter() throws Exception {
|
||||||
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/nonPlatformTypeParameter.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt");
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt");
|
||||||
@@ -69,6 +74,11 @@ public class ForeignJava8AnnotationsTestGenerated extends AbstractForeignJava8An
|
|||||||
public void testTypeParameterBounds() throws Exception {
|
public void testTypeParameterBounds() throws Exception {
|
||||||
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt");
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("unknownNullnessTypeParameter.kt")
|
||||||
|
public void testUnknownNullnessTypeParameter() throws Exception {
|
||||||
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/unknownNullnessTypeParameter.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
|
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
|
||||||
|
|||||||
+10
@@ -60,6 +60,11 @@ public class JavacForeignJava8AnnotationsTestGenerated extends AbstractJavacFore
|
|||||||
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.kt");
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nonPlatformTypeParameter.kt")
|
||||||
|
public void testNonPlatformTypeParameter() throws Exception {
|
||||||
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/nonPlatformTypeParameter.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt");
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt");
|
||||||
@@ -69,6 +74,11 @@ public class JavacForeignJava8AnnotationsTestGenerated extends AbstractJavacFore
|
|||||||
public void testTypeParameterBounds() throws Exception {
|
public void testTypeParameterBounds() throws Exception {
|
||||||
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt");
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("unknownNullnessTypeParameter.kt")
|
||||||
|
public void testUnknownNullnessTypeParameter() throws Exception {
|
||||||
|
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/unknownNullnessTypeParameter.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
|
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
|
||||||
|
|||||||
+7
-3
@@ -11,8 +11,11 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
|
|
||||||
data class JavaDefaultQualifiers(
|
data class JavaDefaultQualifiers(
|
||||||
val nullabilityQualifier: NullabilityQualifierWithMigrationStatus,
|
val nullabilityQualifier: NullabilityQualifierWithMigrationStatus,
|
||||||
val qualifierApplicabilityTypes: Collection<AnnotationQualifierApplicabilityType>
|
val qualifierApplicabilityTypes: Collection<AnnotationQualifierApplicabilityType>,
|
||||||
)
|
val affectsTypeParameterBasedTypes: Boolean = nullabilityQualifier.qualifier == NullabilityQualifier.NOT_NULL
|
||||||
|
) {
|
||||||
|
val makesTypeParameterNotNull get() = nullabilityQualifier.qualifier == NullabilityQualifier.NOT_NULL && affectsTypeParameterBasedTypes
|
||||||
|
}
|
||||||
|
|
||||||
val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname")
|
val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname")
|
||||||
val TYPE_QUALIFIER_FQNAME = FqName("javax.annotation.meta.TypeQualifier")
|
val TYPE_QUALIFIER_FQNAME = FqName("javax.annotation.meta.TypeQualifier")
|
||||||
@@ -45,7 +48,8 @@ val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf(
|
|||||||
),
|
),
|
||||||
JSPECIFY_DEFAULT_NOT_NULL to JavaDefaultQualifiers(
|
JSPECIFY_DEFAULT_NOT_NULL to JavaDefaultQualifiers(
|
||||||
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL),
|
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL),
|
||||||
DEFAULT_JSPECIFY_APPLICABILITY
|
DEFAULT_JSPECIFY_APPLICABILITY,
|
||||||
|
affectsTypeParameterBasedTypes = false
|
||||||
),
|
),
|
||||||
JSPECIFY_DEFAULT_NULLNESS_UNKNOWN to JavaDefaultQualifiers(
|
JSPECIFY_DEFAULT_NULLNESS_UNKNOWN to JavaDefaultQualifiers(
|
||||||
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.FORCE_FLEXIBILITY),
|
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.FORCE_FLEXIBILITY),
|
||||||
|
|||||||
+45
-5
@@ -325,13 +325,20 @@ class SignatureEnhancement(
|
|||||||
fun <T : Any> uniqueNotNull(x: T?, y: T?) = if (x == null || y == null || x == y) x ?: y else null
|
fun <T : Any> uniqueNotNull(x: T?, y: T?) = if (x == null || y == null || x == y) x ?: y else null
|
||||||
|
|
||||||
val defaultTypeQualifier =
|
val defaultTypeQualifier =
|
||||||
if (isHeadTypeConstructor)
|
(if (isHeadTypeConstructor)
|
||||||
containerContext.defaultTypeQualifiers?.get(containerApplicabilityType)
|
containerContext.defaultTypeQualifiers?.get(containerApplicabilityType)
|
||||||
else
|
else
|
||||||
defaultQualifiersForType
|
defaultQualifiersForType)?.takeIf {
|
||||||
|
it.affectsTypeParameterBasedTypes || !isTypeParameter()
|
||||||
|
}
|
||||||
|
|
||||||
|
val (nullabilityFromBoundsForTypeBasedOnTypeParameter, isTypeParameterWithNotNullableBounds) =
|
||||||
|
nullabilityInfoBoundsForTypeParameterUsage()
|
||||||
|
|
||||||
|
val annotationsNullability = composedAnnotation.extractNullability()
|
||||||
val nullabilityInfo =
|
val nullabilityInfo =
|
||||||
composedAnnotation.extractNullability()
|
annotationsNullability
|
||||||
|
?: nullabilityFromBoundsForTypeBasedOnTypeParameter
|
||||||
?: defaultTypeQualifier?.nullabilityQualifier?.let { nullabilityQualifierWithMigrationStatus ->
|
?: defaultTypeQualifier?.nullabilityQualifier?.let { nullabilityQualifierWithMigrationStatus ->
|
||||||
NullabilityQualifierWithMigrationStatus(
|
NullabilityQualifierWithMigrationStatus(
|
||||||
nullabilityQualifierWithMigrationStatus.qualifier,
|
nullabilityQualifierWithMigrationStatus.qualifier,
|
||||||
@@ -339,6 +346,12 @@ class SignatureEnhancement(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val isNotNullTypeParameter =
|
||||||
|
if (annotationsNullability != null)
|
||||||
|
annotationsNullability.qualifier == NullabilityQualifier.NOT_NULL
|
||||||
|
else
|
||||||
|
isTypeParameterWithNotNullableBounds || defaultTypeQualifier?.makesTypeParameterNotNull == true
|
||||||
|
|
||||||
return JavaTypeQualifiers(
|
return JavaTypeQualifiers(
|
||||||
nullabilityInfo?.qualifier,
|
nullabilityInfo?.qualifier,
|
||||||
uniqueNotNull(
|
uniqueNotNull(
|
||||||
@@ -349,11 +362,34 @@ class SignatureEnhancement(
|
|||||||
MutabilityQualifier.MUTABLE
|
MutabilityQualifier.MUTABLE
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
isNotNullTypeParameter = nullabilityInfo?.qualifier == NullabilityQualifier.NOT_NULL && isTypeParameter(),
|
isNotNullTypeParameter = isNotNullTypeParameter && isTypeParameter(),
|
||||||
isNullabilityQualifierForWarning = nullabilityInfo?.isForWarningOnly == true
|
isNullabilityQualifierForWarning = nullabilityInfo?.isForWarningOnly == true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun KotlinType.nullabilityInfoBoundsForTypeParameterUsage(): Pair<NullabilityQualifierWithMigrationStatus?, Boolean> {
|
||||||
|
val typeParameterBoundsNullability =
|
||||||
|
(constructor.declarationDescriptor as? TypeParameterDescriptor)?.boundsNullability() ?: return Pair(null, false)
|
||||||
|
|
||||||
|
if (typeParameterBoundsNullability == NullabilityQualifier.FORCE_FLEXIBILITY) return Pair(null, false)
|
||||||
|
|
||||||
|
// If type parameter has a nullable (non-flexible) upper bound
|
||||||
|
// We shouldn't mark its type usages as nullable:
|
||||||
|
// interface A<T extends @Nullable Object> {
|
||||||
|
// void foo(T t); // should be loaded as "fun foo(t: T)" but not as "fun foo(t: T?)"
|
||||||
|
// }
|
||||||
|
return Pair(
|
||||||
|
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL),
|
||||||
|
typeParameterBoundsNullability == NullabilityQualifier.NOT_NULL
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun TypeParameterDescriptor.boundsNullability(): NullabilityQualifier = when {
|
||||||
|
upperBounds.all(KotlinType::isNullabilityFlexible) -> NullabilityQualifier.FORCE_FLEXIBILITY
|
||||||
|
upperBounds.any { !it.isNullable() } -> NullabilityQualifier.NOT_NULL
|
||||||
|
else -> NullabilityQualifier.NULLABLE
|
||||||
|
}
|
||||||
|
|
||||||
private fun Annotations.extractNullability(): NullabilityQualifierWithMigrationStatus? =
|
private fun Annotations.extractNullability(): NullabilityQualifierWithMigrationStatus? =
|
||||||
this.firstNotNullResult { extractNullability(it, onlyForJspecify = typeParameterBounds) }
|
this.firstNotNullResult { extractNullability(it, onlyForJspecify = typeParameterBounds) }
|
||||||
|
|
||||||
@@ -463,7 +499,6 @@ class SignatureEnhancement(
|
|||||||
isAnyNonNullTypeParameter = isAnyNonNullTypeParameter
|
isAnyNonNullTypeParameter = isAnyNonNullTypeParameter
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private open class PartEnhancementResult(
|
private open class PartEnhancementResult(
|
||||||
@@ -516,3 +551,8 @@ private data class TypeAndDefaultQualifiers(
|
|||||||
val type: KotlinType,
|
val type: KotlinType,
|
||||||
val defaultQualifiers: JavaDefaultQualifiers?
|
val defaultQualifiers: JavaDefaultQualifiers?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun KotlinType.isNullabilityFlexible(): Boolean {
|
||||||
|
val flexibility = unwrap() as? FlexibleType ?: return false
|
||||||
|
return flexibility.lowerBound.isMarkedNullable != flexibility.upperBound.isMarkedNullable
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user