FIR/FE: extract common code for handling known nullability annotations
This commit is contained in:
+5
-7
@@ -184,8 +184,7 @@ internal class EnhancementSignatureParts(
|
||||
|
||||
private fun FirTypeRef?.extractQualifiersFromAnnotations(
|
||||
isHeadTypeConstructor: Boolean,
|
||||
defaultQualifiersForType: JavaDefaultQualifiers?,
|
||||
javaTypeEnhancementState: JavaTypeEnhancementState
|
||||
defaultQualifiersForType: JavaDefaultQualifiers?
|
||||
): JavaTypeQualifiers {
|
||||
val composedAnnotation =
|
||||
if (isHeadTypeConstructor && typeContainer != null)
|
||||
@@ -207,7 +206,7 @@ internal class EnhancementSignatureParts(
|
||||
else
|
||||
defaultQualifiersForType
|
||||
|
||||
val nullabilityInfo = composedAnnotation.extractNullability(typeQualifierResolver, javaTypeEnhancementState).also {
|
||||
val nullabilityInfo = composedAnnotation.extractNullability(typeQualifierResolver).also {
|
||||
if (it?.qualifier == NullabilityQualifier.NOT_NULL) {
|
||||
attributesCache[this] = composedAnnotation.computeTypeAttributesForJavaType()
|
||||
}
|
||||
@@ -242,8 +241,7 @@ internal class EnhancementSignatureParts(
|
||||
session: FirSession,
|
||||
fromSupertypes: Collection<FirTypeRef>,
|
||||
defaultQualifiersForType: JavaDefaultQualifiers?,
|
||||
isHeadTypeConstructor: Boolean,
|
||||
javaTypeEnhancementState: JavaTypeEnhancementState
|
||||
isHeadTypeConstructor: Boolean
|
||||
): JavaTypeQualifiers {
|
||||
val superQualifiers = fromSupertypes.map { it.extractQualifiers(session) }
|
||||
val mutabilityFromSupertypes = superQualifiers.mapNotNull { it.mutability }.toSet()
|
||||
@@ -252,7 +250,7 @@ internal class EnhancementSignatureParts(
|
||||
.mapNotNull { it.extractQualifiers(session).nullability }
|
||||
.toSet()
|
||||
|
||||
val own = extractQualifiersFromAnnotations(isHeadTypeConstructor, defaultQualifiersForType, javaTypeEnhancementState)
|
||||
val own = extractQualifiersFromAnnotations(isHeadTypeConstructor, defaultQualifiersForType)
|
||||
val ownNullability = own.takeIf { !it.isNullabilityQualifierForWarning }?.nullability
|
||||
val ownNullabilityForWarning = own.nullability
|
||||
|
||||
@@ -306,7 +304,7 @@ internal class EnhancementSignatureParts(
|
||||
val verticalSlice = indexedFromSupertypes.mapNotNull { it.getOrNull(index)?.type }
|
||||
|
||||
// Only the head type constructor is safely co-variant
|
||||
type.computeQualifiersForOverride(session, verticalSlice, defaultQualifiers, isHeadTypeConstructor, javaTypeEnhancementState)
|
||||
type.computeQualifiersForOverride(session, verticalSlice, defaultQualifiers, isHeadTypeConstructor)
|
||||
}
|
||||
|
||||
return IndexedJavaTypeQualifiers(computedResult)
|
||||
|
||||
+3
-10
@@ -21,7 +21,6 @@ class FirJavaEnhancementContext private constructor(
|
||||
|
||||
fun extractDefaultNullabilityQualifier(
|
||||
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
javaTypeEnhancementState: JavaTypeEnhancementState,
|
||||
annotationCall: FirAnnotationCall
|
||||
): JavaDefaultQualifiers? {
|
||||
typeQualifierResolver.resolveQualifierBuiltInDefaultAnnotation(annotationCall)?.let { return it }
|
||||
@@ -38,10 +37,8 @@ fun extractDefaultNullabilityQualifier(
|
||||
return null
|
||||
}
|
||||
|
||||
val nullabilityQualifier = typeQualifier.extractNullability(
|
||||
typeQualifierResolver, javaTypeEnhancementState
|
||||
)?.copy(isForWarningOnly = jsr305ReportLevel.isWarning) ?: return null
|
||||
|
||||
val nullabilityQualifier = typeQualifier.extractNullability(typeQualifierResolver)
|
||||
?.copy(isForWarningOnly = jsr305ReportLevel.isWarning) ?: return null
|
||||
return JavaDefaultQualifiers(nullabilityQualifier, applicability)
|
||||
}
|
||||
|
||||
@@ -54,11 +51,7 @@ fun FirJavaEnhancementContext.computeNewDefaultTypeQualifiers(
|
||||
|
||||
val defaultQualifiers =
|
||||
additionalAnnotations.mapNotNull { annotationCall ->
|
||||
extractDefaultNullabilityQualifier(
|
||||
typeQualifierResolver,
|
||||
javaTypeEnhancementState,
|
||||
annotationCall
|
||||
)
|
||||
extractDefaultNullabilityQualifier(typeQualifierResolver, annotationCall)
|
||||
}
|
||||
|
||||
if (defaultQualifiers.isEmpty()) return defaultTypeQualifiers
|
||||
|
||||
@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildStarProjection
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildTypeProjectionWithVariance
|
||||
import org.jetbrains.kotlin.fir.types.jvm.FirJavaTypeRef
|
||||
import org.jetbrains.kotlin.load.java.JavaDefaultQualifiers
|
||||
import org.jetbrains.kotlin.load.java.*
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClassifierType
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaType
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.*
|
||||
@@ -355,3 +355,9 @@ internal fun List<FirAnnotationCall>.computeTypeAttributesForJavaType(): ConeAtt
|
||||
-> add(CompilerConeAttributes.EnhancedNullability)
|
||||
}
|
||||
}
|
||||
|
||||
private val NOT_NULL_ANNOTATION_IDS = NOT_NULL_ANNOTATIONS.map { ClassId.topLevel(it) }
|
||||
private val JAVAX_NONNULL_ANNOTATION_ID = ClassId.topLevel(JAVAX_NONNULL_ANNOTATION)
|
||||
private val JAVAX_CHECKFORNULL_ANNOTATION_ID = ClassId.topLevel(JAVAX_CHECKFORNULL_ANNOTATION)
|
||||
private val COMPATQUAL_NONNULL_ANNOTATION_ID = ClassId.topLevel(COMPATQUAL_NONNULL_ANNOTATION)
|
||||
private val ANDROIDX_RECENTLY_NON_NULL_ANNOTATION_ID = ClassId.topLevel(ANDROIDX_RECENTLY_NON_NULL_ANNOTATION)
|
||||
|
||||
+5
-76
@@ -6,86 +6,15 @@
|
||||
package org.jetbrains.kotlin.fir.java.enhancement
|
||||
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.arguments
|
||||
import org.jetbrains.kotlin.fir.expressions.classId
|
||||
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.load.java.*
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifierWithMigrationStatus
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
fun List<FirAnnotationCall>.extractNullability(
|
||||
annotationTypeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
javaTypeEnhancementState: JavaTypeEnhancementState
|
||||
annotationTypeQualifierResolver: FirAnnotationTypeQualifierResolver
|
||||
): NullabilityQualifierWithMigrationStatus? =
|
||||
this.firstNotNullOfOrNull { annotationCall ->
|
||||
annotationCall.extractNullability(annotationTypeQualifierResolver, javaTypeEnhancementState)
|
||||
}
|
||||
this.firstNotNullOfOrNull { it.extractNullability(annotationTypeQualifierResolver) }
|
||||
|
||||
|
||||
fun FirAnnotationCall.extractNullability(
|
||||
annotationTypeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
javaTypeEnhancementState: JavaTypeEnhancementState
|
||||
): NullabilityQualifierWithMigrationStatus? {
|
||||
this.extractNullabilityFromKnownAnnotations(javaTypeEnhancementState)?.let { return it }
|
||||
|
||||
val typeQualifierAnnotation =
|
||||
annotationTypeQualifierResolver.resolveTypeQualifierAnnotation(this)
|
||||
?: return null
|
||||
|
||||
val jsr305ReportLevel = annotationTypeQualifierResolver.resolveJsr305AnnotationState(this)
|
||||
if (jsr305ReportLevel.isIgnore) return null
|
||||
|
||||
return typeQualifierAnnotation.extractNullabilityFromKnownAnnotations(javaTypeEnhancementState)?.copy(isForWarningOnly = jsr305ReportLevel.isWarning)
|
||||
}
|
||||
|
||||
private fun FirAnnotationCall.extractNullabilityFromKnownAnnotations(javaTypeEnhancementState: JavaTypeEnhancementState): NullabilityQualifierWithMigrationStatus? {
|
||||
val annotationClassId = classId ?: return null
|
||||
val reportLevel = javaTypeEnhancementState.getReportLevelForAnnotation(annotationClassId.asSingleFqName())
|
||||
|
||||
if (reportLevel == ReportLevel.IGNORE) return null
|
||||
|
||||
return when (annotationClassId) {
|
||||
in NULLABLE_ANNOTATION_IDS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE, reportLevel.isWarning)
|
||||
in NOT_NULL_ANNOTATION_IDS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL, reportLevel.isWarning)
|
||||
JSPECIFY_NULLABLE_ANNOTATION_ID -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE, reportLevel.isWarning)
|
||||
JSPECIFY_NULLNESS_UNKNOWN_ANNOTATION_ID ->
|
||||
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.FORCE_FLEXIBILITY, reportLevel.isWarning)
|
||||
JAVAX_NONNULL_ANNOTATION_ID -> extractNullabilityTypeFromArgument()
|
||||
COMPATQUAL_NULLABLE_ANNOTATION_ID -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE, reportLevel.isWarning)
|
||||
COMPATQUAL_NONNULL_ANNOTATION_ID -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL, reportLevel.isWarning)
|
||||
ANDROIDX_RECENTLY_NON_NULL_ANNOTATION_ID -> NullabilityQualifierWithMigrationStatus(
|
||||
NullabilityQualifier.NOT_NULL,
|
||||
isForWarningOnly = reportLevel.isWarning
|
||||
)
|
||||
ANDROIDX_RECENTLY_NULLABLE_ANNOTATION_ID -> NullabilityQualifierWithMigrationStatus(
|
||||
NullabilityQualifier.NULLABLE,
|
||||
isForWarningOnly = reportLevel.isWarning
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirAnnotationCall.extractNullabilityTypeFromArgument(): NullabilityQualifierWithMigrationStatus? {
|
||||
val enumValue = this.arguments.firstOrNull()?.toResolvedCallableSymbol()?.callableId?.callableName
|
||||
// if no argument is specified, use default value: NOT_NULL
|
||||
?: return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
||||
|
||||
return when (enumValue.asString()) {
|
||||
"ALWAYS" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
||||
"MAYBE", "NEVER" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
|
||||
"UNKNOWN" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.FORCE_FLEXIBILITY)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private val NULLABLE_ANNOTATION_IDS = NULLABLE_ANNOTATIONS.map { ClassId.topLevel(it) }
|
||||
val NOT_NULL_ANNOTATION_IDS = NOT_NULL_ANNOTATIONS.map { ClassId.topLevel(it) }
|
||||
val JAVAX_NONNULL_ANNOTATION_ID = ClassId.topLevel(JAVAX_NONNULL_ANNOTATION)
|
||||
val JAVAX_CHECKFORNULL_ANNOTATION_ID = ClassId.topLevel(JAVAX_CHECKFORNULL_ANNOTATION)
|
||||
private val COMPATQUAL_NULLABLE_ANNOTATION_ID = ClassId.topLevel(COMPATQUAL_NULLABLE_ANNOTATION)
|
||||
val COMPATQUAL_NONNULL_ANNOTATION_ID = ClassId.topLevel(COMPATQUAL_NONNULL_ANNOTATION)
|
||||
val ANDROIDX_RECENTLY_NON_NULL_ANNOTATION_ID = ClassId.topLevel(ANDROIDX_RECENTLY_NON_NULL_ANNOTATION)
|
||||
private val ANDROIDX_RECENTLY_NULLABLE_ANNOTATION_ID = ClassId.topLevel(ANDROIDX_RECENTLY_NULLABLE_ANNOTATION)
|
||||
private val JSPECIFY_NULLABLE_ANNOTATION_ID = ClassId.topLevel(JSPECIFY_NULLABLE)
|
||||
private val JSPECIFY_NULLNESS_UNKNOWN_ANNOTATION_ID = ClassId.topLevel(JSPECIFY_NULLNESS_UNKNOWN)
|
||||
annotationTypeQualifierResolver: FirAnnotationTypeQualifierResolver
|
||||
): NullabilityQualifierWithMigrationStatus? =
|
||||
annotationTypeQualifierResolver.extractNullability(this) { false }
|
||||
|
||||
Reference in New Issue
Block a user