FIR/FE: extract common AnnotationTypeQualifierResolver code
TODO: extract the equivalent code that uses it...
This commit is contained in:
+20
-143
@@ -5,161 +5,38 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.java.enhancement
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.load.java.*
|
||||
import org.jetbrains.kotlin.load.java.AbstractAnnotationTypeQualifierResolver
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.load.java.JavaTypeEnhancementState
|
||||
import org.jetbrains.kotlin.load.java.ReportLevel
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
class FirAnnotationTypeQualifierResolver(private val session: FirSession, private val javaTypeEnhancementState: JavaTypeEnhancementState) {
|
||||
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
||||
class FirAnnotationTypeQualifierResolver(private val session: FirSession, javaTypeEnhancementState: JavaTypeEnhancementState) :
|
||||
AbstractAnnotationTypeQualifierResolver<FirAnnotationCall>(javaTypeEnhancementState)
|
||||
{
|
||||
override val FirAnnotationCall.annotations: Iterable<FirAnnotationCall>
|
||||
get() = coneClassLikeType?.lookupTag?.toSymbol(session)?.fir?.annotations.orEmpty()
|
||||
|
||||
class TypeQualifierWithApplicability(
|
||||
private val typeQualifier: FirAnnotationCall,
|
||||
private val applicability: Int
|
||||
) {
|
||||
operator fun component1() = typeQualifier
|
||||
operator fun component2() = AnnotationQualifierApplicabilityType.values().filter(this::isApplicableTo)
|
||||
override val FirAnnotationCall.key: Any
|
||||
get() = coneClassLikeType!!.lookupTag
|
||||
|
||||
private fun isApplicableTo(elementType: AnnotationQualifierApplicabilityType) =
|
||||
isApplicableConsideringMask(AnnotationQualifierApplicabilityType.TYPE_USE) || isApplicableConsideringMask(
|
||||
elementType
|
||||
)
|
||||
override val FirAnnotationCall.fqName: FqName?
|
||||
get() = coneClassLikeType?.lookupTag?.classId?.asSingleFqName()
|
||||
|
||||
private fun isApplicableConsideringMask(elementType: AnnotationQualifierApplicabilityType) =
|
||||
(applicability and (1 shl elementType.ordinal)) != 0
|
||||
}
|
||||
|
||||
// TODO: memoize this function
|
||||
private fun computeTypeQualifierNickname(klass: FirRegularClass): FirAnnotationCall? {
|
||||
if (klass.annotations.none { it.classId == TYPE_QUALIFIER_NICKNAME_ID }) return null
|
||||
|
||||
return klass.annotations.firstNotNullOfOrNull(this::resolveTypeQualifierAnnotation)
|
||||
}
|
||||
|
||||
private fun resolveTypeQualifierNickname(klass: FirRegularClass): FirAnnotationCall? {
|
||||
if (klass.classKind != ClassKind.ANNOTATION_CLASS) return null
|
||||
|
||||
return computeTypeQualifierNickname(klass)
|
||||
}
|
||||
|
||||
private val FirAnnotationCall.resolvedClass: FirRegularClass?
|
||||
get() = (coneClassLikeType?.lookupTag?.toSymbol(this@FirAnnotationTypeQualifierResolver.session) as? FirRegularClassSymbol)?.fir
|
||||
|
||||
fun resolveTypeQualifierAnnotation(annotationCall: FirAnnotationCall): FirAnnotationCall? {
|
||||
if (javaTypeEnhancementState.jsr305.isDisabled) {
|
||||
return null
|
||||
override fun FirAnnotationCall.enumArguments(onlyValue: Boolean): Iterable<String> =
|
||||
arguments.flatMap { argument ->
|
||||
if (!onlyValue || argument !is FirNamedArgumentExpression || argument.name == DEFAULT_ANNOTATION_MEMBER_NAME)
|
||||
argument.toEnumNames()
|
||||
else
|
||||
emptyList()
|
||||
}
|
||||
|
||||
val annotationClass = annotationCall.resolvedClass ?: return null
|
||||
if (annotationClass.isAnnotatedWithTypeQualifier) return annotationCall
|
||||
|
||||
return resolveTypeQualifierNickname(annotationClass)
|
||||
}
|
||||
|
||||
fun resolveQualifierBuiltInDefaultAnnotation(annotationCall: FirAnnotationCall): JavaDefaultQualifiers? {
|
||||
if (javaTypeEnhancementState.jsr305.isDisabled) {
|
||||
return null
|
||||
}
|
||||
|
||||
val annotationClassId = annotationCall.classId
|
||||
return BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATION_IDS[annotationClassId]?.let { qualifierForDefaultingAnnotation ->
|
||||
val state = resolveJsr305ReportLevel(annotationCall).takeIf { it != ReportLevel.IGNORE } ?: return null
|
||||
qualifierForDefaultingAnnotation.copy(
|
||||
nullabilityQualifier = qualifierForDefaultingAnnotation.nullabilityQualifier.copy(isForWarningOnly = state.isWarning)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun resolveTypeQualifierDefaultAnnotation(annotationCall: FirAnnotationCall): TypeQualifierWithApplicability? {
|
||||
if (javaTypeEnhancementState.jsr305.isDisabled) {
|
||||
return null
|
||||
}
|
||||
|
||||
val typeQualifierDefaultAnnotatedClass =
|
||||
annotationCall.resolvedClass?.takeIf { klass ->
|
||||
klass.annotations.any { it.classId == TYPE_QUALIFIER_DEFAULT_ID }
|
||||
} ?: return null
|
||||
|
||||
val elementTypesMask =
|
||||
annotationCall.resolvedClass!!
|
||||
.annotations.find { it.classId == TYPE_QUALIFIER_DEFAULT_ID }!!
|
||||
.arguments
|
||||
.flatMap { argument ->
|
||||
if (argument !is FirNamedArgumentExpression || argument.name == DEFAULT_ANNOTATION_MEMBER_NAME)
|
||||
argument.mapConstantToQualifierApplicabilityTypes()
|
||||
else
|
||||
emptyList()
|
||||
}
|
||||
.fold(0) { acc: Int, applicabilityType -> acc or (1 shl applicabilityType.ordinal) }
|
||||
|
||||
val typeQualifier = typeQualifierDefaultAnnotatedClass.annotations.firstOrNull { resolveTypeQualifierAnnotation(it) != null }
|
||||
?: return null
|
||||
|
||||
return TypeQualifierWithApplicability(
|
||||
typeQualifier,
|
||||
elementTypesMask
|
||||
)
|
||||
}
|
||||
|
||||
fun resolveJsr305ReportLevel(annotationCall: FirAnnotationCall): ReportLevel {
|
||||
resolveJsr305CustomLevel(annotationCall)?.let { return it }
|
||||
return javaTypeEnhancementState.jsr305.globalLevel
|
||||
}
|
||||
|
||||
fun resolveJsr305CustomLevel(annotationCall: FirAnnotationCall): ReportLevel? {
|
||||
javaTypeEnhancementState.jsr305.userDefinedLevelForSpecificAnnotation[annotationCall.classId?.run { FqName(packageFqName.asString() + "." + relativeClassName.asString()) }]?.let { return it }
|
||||
return annotationCall.resolvedClass?.migrationAnnotationStatus()
|
||||
}
|
||||
|
||||
private fun FirRegularClass.migrationAnnotationStatus(): ReportLevel? {
|
||||
val enumEntryName = annotations.find {
|
||||
it.classId == MIGRATION_ANNOTATION_ID
|
||||
}?.arguments?.firstOrNull()?.toResolvedCallableSymbol()?.callableId?.callableName ?: return null
|
||||
|
||||
javaTypeEnhancementState.jsr305.migrationLevel?.let { return it }
|
||||
|
||||
return when (enumEntryName.asString()) {
|
||||
"STRICT" -> ReportLevel.STRICT
|
||||
"WARN" -> ReportLevel.WARN
|
||||
"IGNORE" -> ReportLevel.IGNORE
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirExpression.mapConstantToQualifierApplicabilityTypes(): List<AnnotationQualifierApplicabilityType> =
|
||||
private fun FirExpression.toEnumNames(): List<String> =
|
||||
when (this) {
|
||||
is FirArrayOfCall -> arguments.flatMap { it.mapConstantToQualifierApplicabilityTypes() }
|
||||
else -> listOfNotNull(
|
||||
when (toResolvedCallableSymbol()?.callableId?.callableName?.asString()) {
|
||||
"METHOD" -> AnnotationQualifierApplicabilityType.METHOD_RETURN_TYPE
|
||||
"FIELD" -> AnnotationQualifierApplicabilityType.FIELD
|
||||
"PARAMETER" -> AnnotationQualifierApplicabilityType.VALUE_PARAMETER
|
||||
"TYPE_USE" -> AnnotationQualifierApplicabilityType.TYPE_USE
|
||||
else -> null
|
||||
}
|
||||
)
|
||||
is FirArrayOfCall -> arguments.flatMap { it.toEnumNames() }
|
||||
else -> listOfNotNull(toResolvedCallableSymbol()?.callableId?.callableName?.asString())
|
||||
}
|
||||
|
||||
val isDisabled: Boolean = javaTypeEnhancementState.jsr305.isDisabled
|
||||
|
||||
}
|
||||
|
||||
private val FirRegularClass.isAnnotatedWithTypeQualifier: Boolean
|
||||
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) }
|
||||
|
||||
+2
-2
@@ -31,7 +31,7 @@ fun extractDefaultNullabilityQualifier(
|
||||
?: return null
|
||||
|
||||
val jsr305ReportLevel = with(typeQualifierResolver) {
|
||||
resolveJsr305CustomLevel(annotationCall) ?: resolveJsr305ReportLevel(typeQualifier)
|
||||
resolveJsr305CustomState(annotationCall) ?: resolveJsr305AnnotationState(typeQualifier)
|
||||
}
|
||||
|
||||
if (jsr305ReportLevel.isIgnore) {
|
||||
@@ -50,7 +50,7 @@ fun FirJavaEnhancementContext.computeNewDefaultTypeQualifiers(
|
||||
javaTypeEnhancementState: JavaTypeEnhancementState,
|
||||
additionalAnnotations: List<FirAnnotationCall>
|
||||
): JavaTypeQualifiersByElementType? {
|
||||
if (typeQualifierResolver.isDisabled) return defaultTypeQualifiers
|
||||
if (javaTypeEnhancementState.jsr305.isDisabled) return defaultTypeQualifiers
|
||||
|
||||
val defaultQualifiers =
|
||||
additionalAnnotations.mapNotNull { annotationCall ->
|
||||
|
||||
@@ -33,7 +33,7 @@ fun FirAnnotationCall.extractNullability(
|
||||
annotationTypeQualifierResolver.resolveTypeQualifierAnnotation(this)
|
||||
?: return null
|
||||
|
||||
val jsr305ReportLevel = annotationTypeQualifierResolver.resolveJsr305ReportLevel(this)
|
||||
val jsr305ReportLevel = annotationTypeQualifierResolver.resolveJsr305AnnotationState(this)
|
||||
if (jsr305ReportLevel.isIgnore) return null
|
||||
|
||||
return typeQualifierAnnotation.extractNullabilityFromKnownAnnotations(javaTypeEnhancementState)?.copy(isForWarningOnly = jsr305ReportLevel.isWarning)
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.load.java
|
||||
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
typealias TypeQualifierWithApplicability<Annotation> = Pair<Annotation, Set<AnnotationQualifierApplicabilityType>>
|
||||
|
||||
abstract class AbstractAnnotationTypeQualifierResolver<Annotation : Any>(
|
||||
private val javaTypeEnhancementState: JavaTypeEnhancementState
|
||||
) {
|
||||
protected abstract val Annotation.annotations: Iterable<Annotation>
|
||||
protected abstract val Annotation.key: Any // TODO: figure out if keying `resolvedNicknames` by `fqName` is safe
|
||||
protected abstract val Annotation.fqName: FqName?
|
||||
protected abstract fun Annotation.enumArguments(onlyValue: Boolean): Iterable<String>
|
||||
|
||||
private fun Annotation.findAnnotation(fqName: FqName): Annotation? =
|
||||
annotations.find { it.fqName == fqName }
|
||||
|
||||
private fun Annotation.hasAnnotation(fqName: FqName): Boolean =
|
||||
annotations.any { it.fqName == fqName }
|
||||
|
||||
private val resolvedNicknames = ConcurrentHashMap<Any, Annotation>()
|
||||
|
||||
fun resolveTypeQualifierAnnotation(annotation: Annotation): Annotation? {
|
||||
if (javaTypeEnhancementState.jsr305.isDisabled) return null
|
||||
if (annotation.fqName in BUILT_IN_TYPE_QUALIFIER_FQ_NAMES || annotation.hasAnnotation(TYPE_QUALIFIER_FQNAME))
|
||||
return annotation
|
||||
if (!annotation.hasAnnotation(TYPE_QUALIFIER_NICKNAME_FQNAME))
|
||||
return null
|
||||
return resolvedNicknames.getOrPut(annotation.key) {
|
||||
// This won't store nulls (ConcurrentHashMap does not permit that), but presumably unless the code
|
||||
// is broken a nickname should be resolvable.
|
||||
annotation.annotations.firstNotNullOfOrNull(::resolveTypeQualifierAnnotation) ?: return null
|
||||
}
|
||||
}
|
||||
|
||||
fun resolveQualifierBuiltInDefaultAnnotation(annotation: Annotation): JavaDefaultQualifiers? {
|
||||
if (javaTypeEnhancementState.disabledDefaultAnnotations) {
|
||||
return null
|
||||
}
|
||||
|
||||
return BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS[annotation.fqName]?.let { qualifierForDefaultingAnnotation ->
|
||||
val state = resolveDefaultAnnotationState(annotation).takeIf { it != ReportLevel.IGNORE } ?: return null
|
||||
qualifierForDefaultingAnnotation.copy(
|
||||
nullabilityQualifier = qualifierForDefaultingAnnotation.nullabilityQualifier.copy(isForWarningOnly = state.isWarning)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveDefaultAnnotationState(annotation: Annotation): ReportLevel {
|
||||
val annotationFqname = annotation.fqName
|
||||
if (annotationFqname != null && annotationFqname in JSPECIFY_DEFAULT_ANNOTATIONS) {
|
||||
return javaTypeEnhancementState.getReportLevelForAnnotation(annotationFqname)
|
||||
}
|
||||
return resolveJsr305AnnotationState(annotation)
|
||||
}
|
||||
|
||||
// We explicitly state that while JSR-305 TYPE_USE annotations effectively should be applied to every type.
|
||||
// They are not applicable for type parameter bounds because it would be a breaking change otherwise.
|
||||
private fun Set<AnnotationQualifierApplicabilityType>.allIfTypeUse(): Set<AnnotationQualifierApplicabilityType> =
|
||||
if (AnnotationQualifierApplicabilityType.TYPE_USE in this)
|
||||
AnnotationQualifierApplicabilityType.values().toSet() - AnnotationQualifierApplicabilityType.TYPE_PARAMETER_BOUNDS + this
|
||||
else
|
||||
this
|
||||
|
||||
fun resolveTypeQualifierDefaultAnnotation(annotation: Annotation): TypeQualifierWithApplicability<Annotation>? {
|
||||
if (javaTypeEnhancementState.jsr305.isDisabled) return null
|
||||
val typeQualifierDefault = annotation.findAnnotation(TYPE_QUALIFIER_DEFAULT_FQNAME) ?: return null
|
||||
val typeQualifier = annotation.annotations.firstOrNull { resolveTypeQualifierAnnotation(it) != null } ?: return null
|
||||
val applicability = typeQualifierDefault.enumArguments(onlyValue = true)
|
||||
.mapNotNullTo(mutableSetOf()) { JAVA_APPLICABILITY_TYPES[it] }
|
||||
return TypeQualifierWithApplicability(typeQualifier, applicability.allIfTypeUse())
|
||||
}
|
||||
|
||||
fun isTypeUseAnnotation(annotation: Annotation): Boolean {
|
||||
// Expect that Java's Target was mapped to Kotlin's Target.
|
||||
val target = annotation.findAnnotation(StandardNames.FqNames.target) ?: return false
|
||||
return target.enumArguments(onlyValue = false).any { it == KotlinTarget.TYPE.name }
|
||||
}
|
||||
|
||||
fun resolveJsr305AnnotationState(annotation: Annotation): ReportLevel {
|
||||
resolveJsr305CustomState(annotation)?.let { return it }
|
||||
return javaTypeEnhancementState.jsr305.globalLevel
|
||||
}
|
||||
|
||||
fun resolveJsr305CustomState(annotation: Annotation): ReportLevel? {
|
||||
javaTypeEnhancementState.jsr305.userDefinedLevelForSpecificAnnotation[annotation.fqName]?.let { return it }
|
||||
val enumValue = annotation.findAnnotation(MIGRATION_ANNOTATION_FQNAME)?.enumArguments(onlyValue = false)?.firstOrNull()
|
||||
?: return null
|
||||
return javaTypeEnhancementState.jsr305.migrationLevel ?: when (enumValue) {
|
||||
"STRICT" -> ReportLevel.STRICT
|
||||
"WARN" -> ReportLevel.WARN
|
||||
"IGNORE" -> ReportLevel.IGNORE
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private companion object {
|
||||
val JAVA_APPLICABILITY_TYPES = buildMap<String, AnnotationQualifierApplicabilityType> {
|
||||
for (type in AnnotationQualifierApplicabilityType.values()) {
|
||||
getOrPut(type.javaTarget) { type }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-103
@@ -16,102 +16,27 @@
|
||||
|
||||
package org.jetbrains.kotlin.load.java
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.load.java.components.JavaAnnotationTargetMapper
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
typealias TypeQualifierWithApplicability = Pair<AnnotationDescriptor, Set<AnnotationQualifierApplicabilityType>>
|
||||
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
||||
class AnnotationTypeQualifierResolver(javaTypeEnhancementState: JavaTypeEnhancementState) :
|
||||
AbstractAnnotationTypeQualifierResolver<AnnotationDescriptor>(javaTypeEnhancementState) {
|
||||
|
||||
class AnnotationTypeQualifierResolver(storageManager: StorageManager, private val javaTypeEnhancementState: JavaTypeEnhancementState) {
|
||||
private val resolvedNicknames =
|
||||
storageManager.createMemoizedFunctionWithNullableValues { klass: ClassDescriptor ->
|
||||
if (klass.annotations.hasAnnotation(TYPE_QUALIFIER_NICKNAME_FQNAME))
|
||||
klass.annotations.firstNotNullOfOrNull(this::resolveTypeQualifierAnnotation)
|
||||
else
|
||||
null
|
||||
}
|
||||
override val AnnotationDescriptor.annotations: Iterable<AnnotationDescriptor>
|
||||
get() = annotationClass?.annotations ?: emptyList()
|
||||
|
||||
fun resolveTypeQualifierAnnotation(annotation: AnnotationDescriptor): AnnotationDescriptor? {
|
||||
if (javaTypeEnhancementState.jsr305.isDisabled) return null
|
||||
val annotationClass = annotation.annotationClass ?: return null
|
||||
if (annotation.fqName in BUILT_IN_TYPE_QUALIFIER_FQ_NAMES || annotationClass.annotations.hasAnnotation(TYPE_QUALIFIER_FQNAME))
|
||||
return annotation
|
||||
return resolvedNicknames(annotationClass)
|
||||
}
|
||||
override val AnnotationDescriptor.key: Any
|
||||
get() = annotationClass!!
|
||||
|
||||
fun resolveQualifierBuiltInDefaultAnnotation(annotation: AnnotationDescriptor): JavaDefaultQualifiers? {
|
||||
if (javaTypeEnhancementState.disabledDefaultAnnotations) {
|
||||
return null
|
||||
}
|
||||
override val AnnotationDescriptor.fqName: FqName?
|
||||
get() = fqName
|
||||
|
||||
return BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS[annotation.fqName]?.let { qualifierForDefaultingAnnotation ->
|
||||
val state = resolveDefaultAnnotationState(annotation).takeIf { it != ReportLevel.IGNORE } ?: return null
|
||||
qualifierForDefaultingAnnotation.copy(
|
||||
nullabilityQualifier = qualifierForDefaultingAnnotation.nullabilityQualifier.copy(isForWarningOnly = state.isWarning)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveDefaultAnnotationState(annotation: AnnotationDescriptor): ReportLevel {
|
||||
val annotationFqname = annotation.fqName
|
||||
if (annotationFqname != null && annotationFqname in JSPECIFY_DEFAULT_ANNOTATIONS) {
|
||||
return javaTypeEnhancementState.getReportLevelForAnnotation(annotationFqname)
|
||||
}
|
||||
return resolveJsr305AnnotationState(annotation)
|
||||
}
|
||||
|
||||
// We explicitly state that while JSR-305 TYPE_USE annotations effectively should be applied to every type.
|
||||
// They are not applicable for type parameter bounds because it would be a breaking change otherwise.
|
||||
private fun Set<AnnotationQualifierApplicabilityType>.allIfTypeUse(): Set<AnnotationQualifierApplicabilityType> =
|
||||
if (AnnotationQualifierApplicabilityType.TYPE_USE in this)
|
||||
AnnotationQualifierApplicabilityType.values().toSet() - AnnotationQualifierApplicabilityType.TYPE_PARAMETER_BOUNDS + this
|
||||
else
|
||||
this
|
||||
|
||||
fun resolveTypeQualifierDefaultAnnotation(annotation: AnnotationDescriptor): TypeQualifierWithApplicability? {
|
||||
if (javaTypeEnhancementState.jsr305.isDisabled) return null
|
||||
val annotationClass = annotation.annotationClass ?: return null
|
||||
val typeQualifierDefault = annotationClass.annotations.findAnnotation(TYPE_QUALIFIER_DEFAULT_FQNAME) ?: return null
|
||||
val typeQualifier = annotationClass.annotations.firstOrNull { resolveTypeQualifierAnnotation(it) != null } ?: return null
|
||||
val applicability = typeQualifierDefault.enumArguments(onlyValue = true)
|
||||
.mapNotNullTo(mutableSetOf()) { JAVA_APPLICABILITY_TYPES[it] }
|
||||
return TypeQualifierWithApplicability(typeQualifier, applicability.allIfTypeUse())
|
||||
}
|
||||
|
||||
fun isTypeUseAnnotation(annotation: AnnotationDescriptor): Boolean {
|
||||
val annotatedClass = annotation.annotationClass ?: return false
|
||||
val target = annotatedClass.annotations.findAnnotation(JvmAnnotationNames.TARGET_ANNOTATION) ?: return false
|
||||
return target.enumArguments(onlyValue = false).any { it == KotlinTarget.TYPE.name }
|
||||
}
|
||||
|
||||
fun resolveJsr305AnnotationState(annotation: AnnotationDescriptor): ReportLevel {
|
||||
resolveJsr305CustomState(annotation)?.let { return it }
|
||||
return javaTypeEnhancementState.jsr305.globalLevel
|
||||
}
|
||||
|
||||
fun resolveJsr305CustomState(annotation: AnnotationDescriptor): ReportLevel? {
|
||||
javaTypeEnhancementState.jsr305.userDefinedLevelForSpecificAnnotation[annotation.fqName]?.let { return it }
|
||||
return annotation.annotationClass?.migrationAnnotationStatus()
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.migrationAnnotationStatus(): ReportLevel? {
|
||||
val enumValue = annotations.findAnnotation(MIGRATION_ANNOTATION_FQNAME)?.enumArguments(onlyValue = false)?.firstOrNull()
|
||||
?: return null
|
||||
return javaTypeEnhancementState.jsr305.migrationLevel ?: when (enumValue) {
|
||||
"STRICT" -> ReportLevel.STRICT
|
||||
"WARN" -> ReportLevel.WARN
|
||||
"IGNORE" -> ReportLevel.IGNORE
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun AnnotationDescriptor.enumArguments(onlyValue: Boolean): Iterable<String> =
|
||||
override fun AnnotationDescriptor.enumArguments(onlyValue: Boolean): Iterable<String> =
|
||||
allValueArguments.flatMap { (parameter, argument) ->
|
||||
if (!onlyValue || parameter == JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME)
|
||||
argument.toEnumNames()
|
||||
@@ -125,21 +50,4 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager, private va
|
||||
is EnumValue -> listOf(enumEntryName.identifier)
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private companion object {
|
||||
val JAVA_APPLICABILITY_TYPES = buildMap<String, AnnotationQualifierApplicabilityType> {
|
||||
for (type in AnnotationQualifierApplicabilityType.values()) {
|
||||
getOrPut(type.javaTarget) { type }
|
||||
}
|
||||
}
|
||||
|
||||
val KOTLIN_APPLICABILITY_TYPES = buildMap<String, AnnotationQualifierApplicabilityType> {
|
||||
for (type in AnnotationQualifierApplicabilityType.values()) {
|
||||
for (target in JavaAnnotationTargetMapper.mapJavaTargetArgumentByName(type.javaTarget)) {
|
||||
getOrPut(target.name) { type }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -155,7 +155,7 @@ fun makeLazyJavaPackageFragmentProvider(
|
||||
singleModuleClassResolver: ModuleClassResolver,
|
||||
packagePartProvider: PackagePartProvider = PackagePartProvider.Empty
|
||||
): LazyJavaPackageFragmentProvider {
|
||||
val annotationTypeQualifierResolver = AnnotationTypeQualifierResolver(storageManager, JavaTypeEnhancementState.DEFAULT)
|
||||
val annotationTypeQualifierResolver = AnnotationTypeQualifierResolver(JavaTypeEnhancementState.DEFAULT)
|
||||
val javaTypeEnhancementState = JavaTypeEnhancementState.DEFAULT
|
||||
val javaResolverComponents = JavaResolverComponents(
|
||||
storageManager, javaClassFinder, reflectKotlinClassFinder, deserializedDescriptorResolver,
|
||||
|
||||
Reference in New Issue
Block a user