FE: slowly refactor extractQualifiersFromAnnotations 2

This commit is contained in:
pyos
2021-08-10 22:41:22 +02:00
committed by teamcityserver
parent 9af8abb8b9
commit 5c8d3180f7
@@ -277,16 +277,17 @@ private class SignatureParts(
val annotationsNullability = annotationTypeQualifierResolver.extractNullability(composedAnnotation) { val annotationsNullability = annotationTypeQualifierResolver.extractNullability(composedAnnotation) {
(this is LazyJavaAnnotationDescriptor && (isFreshlySupportedTypeUseAnnotation || typeParameterBounds) && !areImprovementsInStrictMode) || (this is LazyJavaAnnotationDescriptor && (isFreshlySupportedTypeUseAnnotation || typeParameterBounds) && !areImprovementsInStrictMode) ||
(this is PossiblyExternalAnnotationDescriptor && isIdeExternalAnnotation) (this is PossiblyExternalAnnotationDescriptor && isIdeExternalAnnotation)
}.takeUnless { type == null } }
if (annotationsNullability != null) { if (type != null && annotationsNullability != null) {
return JavaTypeQualifiers( return JavaTypeQualifiers(
annotationsNullability.qualifier, annotationsMutability, annotationsNullability.qualifier, annotationsMutability,
annotationsNullability.qualifier == NullabilityQualifier.NOT_NULL && typeOrBound.isTypeParameter(), annotationsNullability.qualifier == NullabilityQualifier.NOT_NULL && type.isTypeParameter(),
annotationsNullability.isForWarningOnly annotationsNullability.isForWarningOnly
) )
} }
// TODO: check whether the code below works properly for star projections (when typeOrBound != type)
val defaultTypeQualifier = ( val defaultTypeQualifier = (
if (isHeadTypeConstructor) if (isHeadTypeConstructor)
containerContext.defaultTypeQualifiers?.get(containerApplicabilityType) containerContext.defaultTypeQualifiers?.get(containerApplicabilityType)
@@ -299,42 +300,43 @@ private class SignatureParts(
) )
)?.takeIf { (it.affectsTypeParameterBasedTypes || !typeOrBound.isTypeParameter()) && (it.affectsStarProjection || type != null) } )?.takeIf { (it.affectsTypeParameterBasedTypes || !typeOrBound.isTypeParameter()) && (it.affectsStarProjection || type != null) }
val (nullabilityFromBoundsForTypeBasedOnTypeParameter, isTypeParameterWithNotNullableBounds) = val referencedParameterBoundsNullability =
typeOrBound.nullabilityInfoBoundsForTypeParameterUsage() (typeOrBound.constructor.declarationDescriptor as? TypeParameterDescriptor)?.boundsNullability()
val nullabilityInfo = computeNullabilityInfoInTheAbsenceOfExplicitAnnotation(
nullabilityFromBoundsForTypeBasedOnTypeParameter,
defaultTypeQualifier,
typeParameterForArgument
)
// For type parameter uses, we have *three* options:
// T!! - NOT_NULL, isNotNullTypeParameter = true
// happens if T is bounded by @NotNull (technically !! is redundant) or context says unannotated
// type parameters are non-null;
// T - NOT_NULL, isNotNullTypeParameter = false
// happens if T is bounded by @Nullable or context says unannotated types in general are non-null;
// T? - NULLABLE, isNotNullTypeParameter = false
// happens if context says unannotated types in general are nullable.
// For other types, this is more straightforward (just take nullability from the context).
// TODO: clean up the representation of those cases in JavaTypeQualifiers
val defaultNullability =
referencedParameterBoundsNullability?.copy(qualifier = NullabilityQualifier.NOT_NULL)
?: defaultTypeQualifier?.nullabilityQualifier
val isNotNullTypeParameter = val isNotNullTypeParameter =
isTypeParameterWithNotNullableBounds || defaultTypeQualifier?.makesTypeParameterNotNull == true referencedParameterBoundsNullability?.qualifier == NullabilityQualifier.NOT_NULL ||
(typeOrBound.isTypeParameter() && defaultTypeQualifier?.makesTypeParameterNotNull == true)
val nullabilityInfo = computeNullabilityInfoInTheAbsenceOfExplicitAnnotation(defaultNullability, typeParameterForArgument)
return JavaTypeQualifiers( return JavaTypeQualifiers(
nullabilityInfo?.qualifier, annotationsMutability, nullabilityInfo?.qualifier, annotationsMutability,
isNotNullTypeParameter = isNotNullTypeParameter && typeOrBound.isTypeParameter(), isNotNullTypeParameter,
isNullabilityQualifierForWarning = nullabilityInfo?.isForWarningOnly == true nullabilityInfo?.isForWarningOnly == true
) )
} }
private fun computeNullabilityInfoInTheAbsenceOfExplicitAnnotation( private fun computeNullabilityInfoInTheAbsenceOfExplicitAnnotation(
nullabilityFromBoundsForTypeBasedOnTypeParameter: NullabilityQualifierWithMigrationStatus?, result: NullabilityQualifierWithMigrationStatus?,
defaultTypeQualifier: JavaDefaultQualifiers?,
typeParameterForArgument: TypeParameterDescriptor? typeParameterForArgument: TypeParameterDescriptor?
): NullabilityQualifierWithMigrationStatus? { ): NullabilityQualifierWithMigrationStatus? {
val result =
nullabilityFromBoundsForTypeBasedOnTypeParameter
?: defaultTypeQualifier?.nullabilityQualifier?.let { nullabilityQualifierWithMigrationStatus ->
NullabilityQualifierWithMigrationStatus(
nullabilityQualifierWithMigrationStatus.qualifier,
nullabilityQualifierWithMigrationStatus.isForWarningOnly
)
}
val boundsFromTypeParameterForArgument = typeParameterForArgument?.boundsNullability() ?: return result val boundsFromTypeParameterForArgument = typeParameterForArgument?.boundsNullability() ?: return result
if (defaultTypeQualifier == null && result == null && boundsFromTypeParameterForArgument.qualifier == NullabilityQualifier.NULLABLE) { if (result == null && boundsFromTypeParameterForArgument.qualifier == NullabilityQualifier.NULLABLE) {
return NullabilityQualifierWithMigrationStatus( return NullabilityQualifierWithMigrationStatus(
NullabilityQualifier.FORCE_FLEXIBILITY, NullabilityQualifier.FORCE_FLEXIBILITY,
boundsFromTypeParameterForArgument.isForWarningOnly boundsFromTypeParameterForArgument.isForWarningOnly
@@ -350,6 +352,7 @@ private class SignatureParts(
a: NullabilityQualifierWithMigrationStatus, a: NullabilityQualifierWithMigrationStatus,
b: NullabilityQualifierWithMigrationStatus b: NullabilityQualifierWithMigrationStatus
): NullabilityQualifierWithMigrationStatus { ): NullabilityQualifierWithMigrationStatus {
// TODO: this probably behaves really weirdly when some of those are warnings.
if (a.qualifier == NullabilityQualifier.FORCE_FLEXIBILITY) return b if (a.qualifier == NullabilityQualifier.FORCE_FLEXIBILITY) return b
if (b.qualifier == NullabilityQualifier.FORCE_FLEXIBILITY) return a if (b.qualifier == NullabilityQualifier.FORCE_FLEXIBILITY) return a
if (a.qualifier == NullabilityQualifier.NULLABLE) return b if (a.qualifier == NullabilityQualifier.NULLABLE) return b
@@ -361,21 +364,6 @@ private class SignatureParts(
return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
} }
private fun KotlinType.nullabilityInfoBoundsForTypeParameterUsage(): Pair<NullabilityQualifierWithMigrationStatus?, Boolean> {
val typeParameterBoundsNullability =
(constructor.declarationDescriptor as? TypeParameterDescriptor)?.boundsNullability() ?: 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.isForWarningOnly),
typeParameterBoundsNullability.qualifier == NullabilityQualifier.NOT_NULL
)
}
private fun TypeParameterDescriptor.boundsNullability(): NullabilityQualifierWithMigrationStatus? { 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 || upperBounds.all(KotlinType::isError)) return null if (this !is LazyJavaTypeParameterDescriptor || upperBounds.all(KotlinType::isError)) return null