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.FirSession
import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall 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.JavaTypeParameterStack
import org.jetbrains.kotlin.fir.java.toConeKotlinTypeWithNullability import org.jetbrains.kotlin.fir.java.toConeKotlinTypeWithNullability
import org.jetbrains.kotlin.fir.java.toFirJavaTypeRef 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.READ_ONLY_ANNOTATIONS
import org.jetbrains.kotlin.load.java.structure.JavaWildcardType import org.jetbrains.kotlin.load.java.structure.JavaWildcardType
import org.jetbrains.kotlin.load.java.typeEnhancement.* 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.name.FqNameUnsafe
import org.jetbrains.kotlin.utils.Jsr305State import org.jetbrains.kotlin.utils.Jsr305State
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -179,9 +179,9 @@ internal class EnhancementSignatureParts(
else else
this?.annotations.orEmpty() this?.annotations.orEmpty()
fun <T : Any> List<FqName>.ifPresent(qualifier: T) = fun <T : Any> List<ClassId>.ifPresent(qualifier: T) =
if (any { fqName -> if (any { classId ->
composedAnnotation.any { it.resolvedFqName == fqName } composedAnnotation.any { it.classId == classId }
} }
) qualifier else null ) qualifier else null
@@ -205,10 +205,10 @@ internal class EnhancementSignatureParts(
return JavaTypeQualifiers( return JavaTypeQualifiers(
nullabilityInfo?.qualifier, nullabilityInfo?.qualifier,
uniqueNotNull( uniqueNotNull(
READ_ONLY_ANNOTATIONS.ifPresent( READ_ONLY_ANNOTATION_IDS.ifPresent(
MutabilityQualifier.READ_ONLY MutabilityQualifier.READ_ONLY
), ),
MUTABLE_ANNOTATIONS.ifPresent( MUTABLE_ANNOTATION_IDS.ifPresent(
MutabilityQualifier.MUTABLE MutabilityQualifier.MUTABLE
) )
), ),
@@ -297,5 +297,10 @@ internal class EnhancementSignatureParts(
val wereChanges: Boolean, val wereChanges: Boolean,
val containsFunctionN: 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.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.load.java.* 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.load.java.lazy.NullabilityQualifierWithApplicability
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.utils.Jsr305State import org.jetbrains.kotlin.utils.Jsr305State
import org.jetbrains.kotlin.utils.ReportLevel import org.jetbrains.kotlin.utils.ReportLevel
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
@@ -37,7 +39,7 @@ class FirAnnotationTypeQualifierResolver(private val session: FirSession, privat
// TODO: memoize this function // TODO: memoize this function
private fun computeTypeQualifierNickname(klass: FirRegularClass): FirAnnotationCall? { 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) return klass.annotations.firstNotNullResult(this::resolveTypeQualifierAnnotation)
} }
@@ -67,7 +69,8 @@ class FirAnnotationTypeQualifierResolver(private val session: FirSession, privat
return null 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 val state = resolveJsr305ReportLevel(annotationCall).takeIf { it != ReportLevel.IGNORE } ?: return null
return NullabilityQualifierWithApplicability(qualifier.copy(isForWarningOnly = state.isWarning), applicability) return NullabilityQualifierWithApplicability(qualifier.copy(isForWarningOnly = state.isWarning), applicability)
} }
@@ -80,15 +83,15 @@ class FirAnnotationTypeQualifierResolver(private val session: FirSession, privat
val typeQualifierDefaultAnnotatedClass = val typeQualifierDefaultAnnotatedClass =
annotationCall.resolvedClass?.takeIf { klass -> annotationCall.resolvedClass?.takeIf { klass ->
klass.annotations.any { it.resolvedFqName == TYPE_QUALIFIER_DEFAULT_FQNAME } klass.annotations.any { it.classId == TYPE_QUALIFIER_DEFAULT_ID }
} ?: return null } ?: return null
val elementTypesMask = val elementTypesMask =
annotationCall.resolvedClass!! annotationCall.resolvedClass!!
.annotations.find { it.resolvedFqName == TYPE_QUALIFIER_DEFAULT_FQNAME }!! .annotations.find { it.classId == TYPE_QUALIFIER_DEFAULT_ID }!!
.arguments .arguments
.flatMap { argument -> .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() argument.mapConstantToQualifierApplicabilityTypes()
else else
emptyList() emptyList()
@@ -110,13 +113,13 @@ class FirAnnotationTypeQualifierResolver(private val session: FirSession, privat
} }
fun resolveJsr305CustomLevel(annotationCall: FirAnnotationCall): ReportLevel? { 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() return annotationCall.resolvedClass?.migrationAnnotationStatus()
} }
private fun FirRegularClass.migrationAnnotationStatus(): ReportLevel? { private fun FirRegularClass.migrationAnnotationStatus(): ReportLevel? {
val enumEntryName = annotations.find { val enumEntryName = annotations.find {
it.resolvedFqName == MIGRATION_ANNOTATION_FQNAME it.classId == MIGRATION_ANNOTATION_ID
}?.arguments?.firstOrNull()?.toResolvedCallableSymbol()?.callableId?.callableName ?: return null }?.arguments?.firstOrNull()?.toResolvedCallableSymbol()?.callableId?.callableName ?: return null
jsr305State.migration?.let { return it } jsr305State.migration?.let { return it }
@@ -148,5 +151,14 @@ class FirAnnotationTypeQualifierResolver(private val session: FirSession, privat
} }
private val FirRegularClass.isAnnotatedWithTypeQualifier: Boolean private val FirRegularClass.isAnnotatedWithTypeQualifier: Boolean
get() = this.symbol.classId.asSingleFqName() in BUILT_IN_TYPE_QUALIFIER_FQ_NAMES || get() = this.symbol.classId in BUILT_IN_TYPE_QUALIFIER_IDS ||
annotations.any { it.resolvedFqName == TYPE_QUALIFIER_FQNAME } 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.*
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.ir.expressions.IrConstKind 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.AnnotationDefaultValue
import org.jetbrains.kotlin.load.java.descriptors.NullDefaultValue import org.jetbrains.kotlin.load.java.descriptors.NullDefaultValue
import org.jetbrains.kotlin.load.java.descriptors.StringDefaultValue 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? { internal fun FirValueParameter.getDefaultValueFromAnnotation(): AnnotationDefaultValue? {
annotations.find { it.resolvedFqName == JvmAnnotationNames.DEFAULT_VALUE_FQ_NAME } annotations.find { it.classId == DEFAULT_VALUE_ID }
?.arguments?.firstOrNull() ?.arguments?.firstOrNull()
?.safeAs<FirConstExpression<*>>()?.value?.safeAs<String>() ?.safeAs<FirConstExpression<*>>()?.value?.safeAs<String>()
?.let { return StringDefaultValue(it) } ?.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 NullDefaultValue
} }
return null 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 package org.jetbrains.kotlin.fir.java.enhancement
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall 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.fir.expressions.toResolvedCallableSymbol
import org.jetbrains.kotlin.load.java.* import org.jetbrains.kotlin.load.java.*
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifierWithMigrationStatus 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.Jsr305State
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
@@ -40,25 +41,25 @@ fun FirAnnotationCall.extractNullability(
} }
private fun FirAnnotationCall.extractNullabilityFromKnownAnnotations(jsr305State: Jsr305State): NullabilityQualifierWithMigrationStatus? { private fun FirAnnotationCall.extractNullabilityFromKnownAnnotations(jsr305State: Jsr305State): NullabilityQualifierWithMigrationStatus? {
val annotationFqName = resolvedFqName ?: return null val annotationClassId = classId ?: return null
return when { return when {
annotationFqName in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE) annotationClassId in NULLABLE_ANNOTATION_IDS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
annotationFqName in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) annotationClassId in NOT_NULL_ANNOTATION_IDS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
annotationFqName == JAVAX_NONNULL_ANNOTATION -> extractNullabilityTypeFromArgument() annotationClassId == JAVAX_NONNULL_ANNOTATION_ID -> extractNullabilityTypeFromArgument()
annotationFqName == COMPATQUAL_NULLABLE_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations -> annotationClassId == COMPATQUAL_NULLABLE_ANNOTATION_ID && jsr305State.enableCompatqualCheckerFrameworkAnnotations ->
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE) NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
annotationFqName == COMPATQUAL_NONNULL_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations -> annotationClassId == COMPATQUAL_NONNULL_ANNOTATION_ID && jsr305State.enableCompatqualCheckerFrameworkAnnotations ->
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
annotationFqName == ANDROIDX_RECENTLY_NON_NULL_ANNOTATION -> NullabilityQualifierWithMigrationStatus( annotationClassId == ANDROIDX_RECENTLY_NON_NULL_ANNOTATION_ID -> NullabilityQualifierWithMigrationStatus(
NullabilityQualifier.NOT_NULL, NullabilityQualifier.NOT_NULL,
isForWarningOnly = true isForWarningOnly = true
) )
annotationFqName == ANDROIDX_RECENTLY_NULLABLE_ANNOTATION -> NullabilityQualifierWithMigrationStatus( annotationClassId == ANDROIDX_RECENTLY_NULLABLE_ANNOTATION_ID -> NullabilityQualifierWithMigrationStatus(
NullabilityQualifier.NULLABLE, NullabilityQualifier.NULLABLE,
isForWarningOnly = true isForWarningOnly = true
) )
@@ -78,3 +79,11 @@ private fun FirAnnotationCall.extractNullabilityTypeFromArgument(): NullabilityQ
else -> null 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)
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.fir.expressions package org.jetbrains.kotlin.fir.expressions
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.expressions.impl.FirConstExpressionImpl import org.jetbrains.kotlin.fir.expressions.impl.FirConstExpressionImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirErrorExpressionImpl import org.jetbrains.kotlin.fir.expressions.impl.FirErrorExpressionImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirErrorLoop import org.jetbrains.kotlin.fir.expressions.impl.FirErrorLoop
@@ -16,13 +15,13 @@ import org.jetbrains.kotlin.fir.types.ConeClassErrorType
import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.ir.expressions.IrConstKind import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.ClassId
inline val FirAnnotationCall.coneClassLikeType: ConeClassLikeType? inline val FirAnnotationCall.coneClassLikeType: ConeClassLikeType?
get() = ((annotationTypeRef as? FirResolvedTypeRef)?.type as? ConeClassLikeType)?.takeIf { it !is ConeClassErrorType } get() = ((annotationTypeRef as? FirResolvedTypeRef)?.type as? ConeClassLikeType)?.takeIf { it !is ConeClassErrorType }
inline val FirAnnotationCall.resolvedFqName: FqName? inline val FirAnnotationCall.classId: ClassId?
get() = coneClassLikeType?.lookupTag?.classId?.asSingleFqName() get() = coneClassLikeType?.lookupTag?.classId
fun <T> FirConstExpressionImpl(psi: PsiElement?, kind: IrConstKind<T>, value: T?, errorReason: String): FirExpression = fun <T> FirConstExpressionImpl(psi: PsiElement?, kind: IrConstKind<T>, value: T?, errorReason: String): FirExpression =
value?.let { FirConstExpressionImpl(psi, kind, it) } ?: FirErrorExpressionImpl(psi, errorReason) value?.let { FirConstExpressionImpl(psi, kind, it) } ?: FirErrorExpressionImpl(psi, errorReason)