FIR/FE: extract common AnnotationTypeQualifierResolver code

TODO: extract the equivalent code that uses it...
This commit is contained in:
pyos
2021-08-08 20:31:13 +02:00
committed by teamcityserver
parent 29a240b261
commit 9349d4b0d2
6 changed files with 148 additions and 250 deletions
@@ -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 }
}
}
}
}
@@ -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 }
}
}
}
}
}
@@ -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,