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
+7
-3
@@ -11,8 +11,11 @@ import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
data class JavaDefaultQualifiers(
|
||||
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_FQNAME = FqName("javax.annotation.meta.TypeQualifier")
|
||||
@@ -45,7 +48,8 @@ val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf(
|
||||
),
|
||||
JSPECIFY_DEFAULT_NOT_NULL to JavaDefaultQualifiers(
|
||||
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL),
|
||||
DEFAULT_JSPECIFY_APPLICABILITY
|
||||
DEFAULT_JSPECIFY_APPLICABILITY,
|
||||
affectsTypeParameterBasedTypes = false
|
||||
),
|
||||
JSPECIFY_DEFAULT_NULLNESS_UNKNOWN to JavaDefaultQualifiers(
|
||||
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.FORCE_FLEXIBILITY),
|
||||
|
||||
+1
-1
@@ -16,4 +16,4 @@ class JavaTypeQualifiersByElementType(val defaultQualifiers: QualifierByApplicab
|
||||
): JavaDefaultQualifiers? {
|
||||
return defaultQualifiers[applicabilityType]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+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
|
||||
|
||||
val defaultTypeQualifier =
|
||||
if (isHeadTypeConstructor)
|
||||
(if (isHeadTypeConstructor)
|
||||
containerContext.defaultTypeQualifiers?.get(containerApplicabilityType)
|
||||
else
|
||||
defaultQualifiersForType
|
||||
defaultQualifiersForType)?.takeIf {
|
||||
it.affectsTypeParameterBasedTypes || !isTypeParameter()
|
||||
}
|
||||
|
||||
val (nullabilityFromBoundsForTypeBasedOnTypeParameter, isTypeParameterWithNotNullableBounds) =
|
||||
nullabilityInfoBoundsForTypeParameterUsage()
|
||||
|
||||
val annotationsNullability = composedAnnotation.extractNullability()
|
||||
val nullabilityInfo =
|
||||
composedAnnotation.extractNullability()
|
||||
annotationsNullability
|
||||
?: nullabilityFromBoundsForTypeBasedOnTypeParameter
|
||||
?: defaultTypeQualifier?.nullabilityQualifier?.let { nullabilityQualifierWithMigrationStatus ->
|
||||
NullabilityQualifierWithMigrationStatus(
|
||||
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(
|
||||
nullabilityInfo?.qualifier,
|
||||
uniqueNotNull(
|
||||
@@ -349,11 +362,34 @@ class SignatureEnhancement(
|
||||
MutabilityQualifier.MUTABLE
|
||||
)
|
||||
),
|
||||
isNotNullTypeParameter = nullabilityInfo?.qualifier == NullabilityQualifier.NOT_NULL && isTypeParameter(),
|
||||
isNotNullTypeParameter = isNotNullTypeParameter && isTypeParameter(),
|
||||
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? =
|
||||
this.firstNotNullResult { extractNullability(it, onlyForJspecify = typeParameterBounds) }
|
||||
|
||||
@@ -463,7 +499,6 @@ class SignatureEnhancement(
|
||||
isAnyNonNullTypeParameter = isAnyNonNullTypeParameter
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private open class PartEnhancementResult(
|
||||
@@ -516,3 +551,8 @@ private data class TypeAndDefaultQualifiers(
|
||||
val type: KotlinType,
|
||||
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