FIR Java enhancement: get rid of FirAnnotationCall.resolvedFqName

This commit is contained in:
Mikhail Glukhikh
2019-10-22 18:16:20 +03:00
parent be6100527b
commit e14b63dfe1
5 changed files with 61 additions and 32 deletions
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.resolvedFqName
import org.jetbrains.kotlin.fir.expressions.classId
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
import org.jetbrains.kotlin.fir.java.toConeKotlinTypeWithNullability
import org.jetbrains.kotlin.fir.java.toFirJavaTypeRef
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.load.java.MUTABLE_ANNOTATIONS
import org.jetbrains.kotlin.load.java.READ_ONLY_ANNOTATIONS
import org.jetbrains.kotlin.load.java.structure.JavaWildcardType
import org.jetbrains.kotlin.load.java.typeEnhancement.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.utils.Jsr305State
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -179,9 +179,9 @@ internal class EnhancementSignatureParts(
else
this?.annotations.orEmpty()
fun <T : Any> List<FqName>.ifPresent(qualifier: T) =
if (any { fqName ->
composedAnnotation.any { it.resolvedFqName == fqName }
fun <T : Any> List<ClassId>.ifPresent(qualifier: T) =
if (any { classId ->
composedAnnotation.any { it.classId == classId }
}
) qualifier else null
@@ -205,10 +205,10 @@ internal class EnhancementSignatureParts(
return JavaTypeQualifiers(
nullabilityInfo?.qualifier,
uniqueNotNull(
READ_ONLY_ANNOTATIONS.ifPresent(
READ_ONLY_ANNOTATION_IDS.ifPresent(
MutabilityQualifier.READ_ONLY
),
MUTABLE_ANNOTATIONS.ifPresent(
MUTABLE_ANNOTATION_IDS.ifPresent(
MutabilityQualifier.MUTABLE
)
),
@@ -297,5 +297,10 @@ internal class EnhancementSignatureParts(
val wereChanges: Boolean,
val containsFunctionN: Boolean
)
companion object {
private val READ_ONLY_ANNOTATION_IDS = READ_ONLY_ANNOTATIONS.map { ClassId.topLevel(it) }
private val MUTABLE_ANNOTATION_IDS = MUTABLE_ANNOTATIONS.map { ClassId.topLevel(it) }
}
}
@@ -12,7 +12,9 @@ import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.load.java.*
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME
import org.jetbrains.kotlin.load.java.lazy.NullabilityQualifierWithApplicability
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.utils.Jsr305State
import org.jetbrains.kotlin.utils.ReportLevel
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
@@ -37,7 +39,7 @@ class FirAnnotationTypeQualifierResolver(private val session: FirSession, privat
// TODO: memoize this function
private fun computeTypeQualifierNickname(klass: FirRegularClass): FirAnnotationCall? {
if (klass.annotations.none { it.resolvedFqName == TYPE_QUALIFIER_NICKNAME_FQNAME }) return null
if (klass.annotations.none { it.classId == TYPE_QUALIFIER_NICKNAME_ID }) return null
return klass.annotations.firstNotNullResult(this::resolveTypeQualifierAnnotation)
}
@@ -67,7 +69,8 @@ class FirAnnotationTypeQualifierResolver(private val session: FirSession, privat
return null
}
return BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS[annotationCall.resolvedFqName]?.let { (qualifier, applicability) ->
val annotationClassId = annotationCall.classId
return BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATION_IDS[annotationClassId]?.let { (qualifier, applicability) ->
val state = resolveJsr305ReportLevel(annotationCall).takeIf { it != ReportLevel.IGNORE } ?: return null
return NullabilityQualifierWithApplicability(qualifier.copy(isForWarningOnly = state.isWarning), applicability)
}
@@ -80,15 +83,15 @@ class FirAnnotationTypeQualifierResolver(private val session: FirSession, privat
val typeQualifierDefaultAnnotatedClass =
annotationCall.resolvedClass?.takeIf { klass ->
klass.annotations.any { it.resolvedFqName == TYPE_QUALIFIER_DEFAULT_FQNAME }
klass.annotations.any { it.classId == TYPE_QUALIFIER_DEFAULT_ID }
} ?: return null
val elementTypesMask =
annotationCall.resolvedClass!!
.annotations.find { it.resolvedFqName == TYPE_QUALIFIER_DEFAULT_FQNAME }!!
.annotations.find { it.classId == TYPE_QUALIFIER_DEFAULT_ID }!!
.arguments
.flatMap { argument ->
if (argument !is FirNamedArgumentExpression || argument.name == JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME)
if (argument !is FirNamedArgumentExpression || argument.name == DEFAULT_ANNOTATION_MEMBER_NAME)
argument.mapConstantToQualifierApplicabilityTypes()
else
emptyList()
@@ -110,13 +113,13 @@ class FirAnnotationTypeQualifierResolver(private val session: FirSession, privat
}
fun resolveJsr305CustomLevel(annotationCall: FirAnnotationCall): ReportLevel? {
jsr305State.user[annotationCall.resolvedFqName?.asString()]?.let { return it }
jsr305State.user[annotationCall.classId?.run { packageFqName.asString() + "." + relativeClassName.asString() }]?.let { return it }
return annotationCall.resolvedClass?.migrationAnnotationStatus()
}
private fun FirRegularClass.migrationAnnotationStatus(): ReportLevel? {
val enumEntryName = annotations.find {
it.resolvedFqName == MIGRATION_ANNOTATION_FQNAME
it.classId == MIGRATION_ANNOTATION_ID
}?.arguments?.firstOrNull()?.toResolvedCallableSymbol()?.callableId?.callableName ?: return null
jsr305State.migration?.let { return it }
@@ -148,5 +151,14 @@ class FirAnnotationTypeQualifierResolver(private val session: FirSession, privat
}
private val FirRegularClass.isAnnotatedWithTypeQualifier: Boolean
get() = this.symbol.classId.asSingleFqName() in BUILT_IN_TYPE_QUALIFIER_FQ_NAMES ||
annotations.any { it.resolvedFqName == TYPE_QUALIFIER_FQNAME }
get() = this.symbol.classId in BUILT_IN_TYPE_QUALIFIER_IDS ||
annotations.any { it.classId == TYPE_QUALIFIER_ID }
private val TYPE_QUALIFIER_ID = ClassId.topLevel(TYPE_QUALIFIER_FQNAME)
private val BUILT_IN_TYPE_QUALIFIER_IDS = BUILT_IN_TYPE_QUALIFIER_FQ_NAMES.map { ClassId.topLevel(it) }
private val TYPE_QUALIFIER_DEFAULT_ID = ClassId.topLevel(TYPE_QUALIFIER_DEFAULT_FQNAME)
private val MIGRATION_ANNOTATION_ID = ClassId.topLevel(MIGRATION_ANNOTATION_FQNAME)
private val TYPE_QUALIFIER_NICKNAME_ID = ClassId.topLevel(TYPE_QUALIFIER_NICKNAME_FQNAME)
private val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATION_IDS =
BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS.mapKeys { ClassId.topLevel(it.key) }
@@ -31,7 +31,8 @@ import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.DEFAULT_NULL_FQ_NAME
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.DEFAULT_VALUE_FQ_NAME
import org.jetbrains.kotlin.load.java.descriptors.AnnotationDefaultValue
import org.jetbrains.kotlin.load.java.descriptors.NullDefaultValue
import org.jetbrains.kotlin.load.java.descriptors.StringDefaultValue
@@ -288,15 +289,18 @@ internal fun ConeKotlinType.lexicalCastFrom(session: FirSession, value: String):
}
internal fun FirValueParameter.getDefaultValueFromAnnotation(): AnnotationDefaultValue? {
annotations.find { it.resolvedFqName == JvmAnnotationNames.DEFAULT_VALUE_FQ_NAME }
annotations.find { it.classId == DEFAULT_VALUE_ID }
?.arguments?.firstOrNull()
?.safeAs<FirConstExpression<*>>()?.value?.safeAs<String>()
?.let { return StringDefaultValue(it) }
if (annotations.any { it.resolvedFqName == JvmAnnotationNames.DEFAULT_NULL_FQ_NAME }) {
if (annotations.any { it.classId == DEFAULT_NULL_ID }) {
return NullDefaultValue
}
return null
}
private val DEFAULT_VALUE_ID = ClassId.topLevel(DEFAULT_VALUE_FQ_NAME)
private val DEFAULT_NULL_ID = ClassId.topLevel(DEFAULT_NULL_FQ_NAME)
@@ -6,11 +6,12 @@
package org.jetbrains.kotlin.fir.java.enhancement
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.resolvedFqName
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
import org.jetbrains.kotlin.utils.Jsr305State
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
@@ -40,25 +41,25 @@ fun FirAnnotationCall.extractNullability(
}
private fun FirAnnotationCall.extractNullabilityFromKnownAnnotations(jsr305State: Jsr305State): NullabilityQualifierWithMigrationStatus? {
val annotationFqName = resolvedFqName ?: return null
val annotationClassId = classId ?: return null
return when {
annotationFqName in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
annotationFqName in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
annotationFqName == JAVAX_NONNULL_ANNOTATION -> extractNullabilityTypeFromArgument()
annotationClassId in NULLABLE_ANNOTATION_IDS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
annotationClassId in NOT_NULL_ANNOTATION_IDS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
annotationClassId == JAVAX_NONNULL_ANNOTATION_ID -> extractNullabilityTypeFromArgument()
annotationFqName == COMPATQUAL_NULLABLE_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations ->
annotationClassId == COMPATQUAL_NULLABLE_ANNOTATION_ID && jsr305State.enableCompatqualCheckerFrameworkAnnotations ->
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
annotationFqName == COMPATQUAL_NONNULL_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations ->
annotationClassId == COMPATQUAL_NONNULL_ANNOTATION_ID && jsr305State.enableCompatqualCheckerFrameworkAnnotations ->
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
annotationFqName == ANDROIDX_RECENTLY_NON_NULL_ANNOTATION -> NullabilityQualifierWithMigrationStatus(
annotationClassId == ANDROIDX_RECENTLY_NON_NULL_ANNOTATION_ID -> NullabilityQualifierWithMigrationStatus(
NullabilityQualifier.NOT_NULL,
isForWarningOnly = true
)
annotationFqName == ANDROIDX_RECENTLY_NULLABLE_ANNOTATION -> NullabilityQualifierWithMigrationStatus(
annotationClassId == ANDROIDX_RECENTLY_NULLABLE_ANNOTATION_ID -> NullabilityQualifierWithMigrationStatus(
NullabilityQualifier.NULLABLE,
isForWarningOnly = true
)
@@ -78,3 +79,11 @@ private fun FirAnnotationCall.extractNullabilityTypeFromArgument(): NullabilityQ
else -> null
}
}
private val NULLABLE_ANNOTATION_IDS = NULLABLE_ANNOTATIONS.map { ClassId.topLevel(it) }
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 COMPATQUAL_NULLABLE_ANNOTATION_ID = ClassId.topLevel(COMPATQUAL_NULLABLE_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)
private val ANDROIDX_RECENTLY_NULLABLE_ANNOTATION_ID = ClassId.topLevel(ANDROIDX_RECENTLY_NULLABLE_ANNOTATION)