Provide more clear API around AnnotationChecker.applicableTargetSet

This commit is contained in:
Mikhail Glukhikh
2021-08-23 11:41:29 +03:00
committed by TeamCityServer
parent 19ab0ab2f8
commit 255eb87375
6 changed files with 14 additions and 10 deletions
@@ -297,7 +297,7 @@ public abstract class AnnotationCodegen {
Map<KotlinTarget, ElementType> annotationTargetMap = annotationTargetMaps.get(typeMapper.getJvmTarget()); Map<KotlinTarget, ElementType> annotationTargetMap = annotationTargetMaps.get(typeMapper.getJvmTarget());
if (annotationTargetMap == null) throw new AssertionError("No annotation target map for JVM target " + typeMapper.getJvmTarget()); if (annotationTargetMap == null) throw new AssertionError("No annotation target map for JVM target " + typeMapper.getJvmTarget());
Set<KotlinTarget> targets = AnnotationChecker.Companion.applicableTargetSet(classDescriptor); Set<KotlinTarget> targets = AnnotationChecker.Companion.applicableTargetSetFromTargetAnnotationOrNull(classDescriptor);
Set<ElementType> javaTargets; Set<ElementType> javaTargets;
if (targets == null) { if (targets == null) {
javaTargets = getJavaTargetList(classDescriptor); javaTargets = getJavaTargetList(classDescriptor);
@@ -50,7 +50,7 @@ object FileClassAnnotationsChecker : AdditionalAnnotationChecker {
val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue
val classDescriptor = descriptor.annotationClass ?: continue val classDescriptor = descriptor.annotationClass ?: continue
// This check matters for the applicable annotations only. // This check matters for the applicable annotations only.
val applicableTargets = AnnotationChecker.applicableTargetSet(classDescriptor) val applicableTargets = AnnotationChecker.applicableTargetSetFromTargetAnnotationOrNull(classDescriptor)
if (applicableTargets == null || !applicableTargets.contains(KotlinTarget.FILE)) continue if (applicableTargets == null || !applicableTargets.contains(KotlinTarget.FILE)) continue
fileAnnotationsToCheck.add(Pair(entry, classDescriptor)) fileAnnotationsToCheck.add(Pair(entry, classDescriptor))
} }
@@ -205,8 +205,8 @@ class RepeatableAnnotationChecker(
annotationClass: ClassDescriptor, annotationClass: ClassDescriptor,
reportOn: KtAnnotationEntry, reportOn: KtAnnotationEntry,
): Diagnostic? { ): Diagnostic? {
val annotationTargets = AnnotationChecker.applicableTargetSet(annotationClass) ?: KotlinTarget.DEFAULT_TARGET_SET val annotationTargets = AnnotationChecker.applicableTargetSet(annotationClass)
val containerTargets = AnnotationChecker.applicableTargetSet(containerClass) ?: KotlinTarget.DEFAULT_TARGET_SET val containerTargets = AnnotationChecker.applicableTargetSet(containerClass)
// See https://docs.oracle.com/javase/specs/jls/se16/html/jls-9.html#jls-9.6.3. // See https://docs.oracle.com/javase/specs/jls/se16/html/jls-9.html#jls-9.6.3.
// (TBH, the rules about TYPE/TYPE_USE and TYPE_PARAMETER/TYPE_USE don't seem to make a lot of sense, but it's JLS // (TBH, the rules about TYPE/TYPE_USE and TYPE_PARAMETER/TYPE_USE don't seem to make a lot of sense, but it's JLS
@@ -297,16 +297,21 @@ class AnnotationChecker(
val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: return KotlinTarget.DEFAULT_TARGET_SET val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: return KotlinTarget.DEFAULT_TARGET_SET
// For descriptor with error type, all targets are considered as possible // For descriptor with error type, all targets are considered as possible
if (descriptor.type.isError) return KotlinTarget.ALL_TARGET_SET if (descriptor.type.isError) return KotlinTarget.ALL_TARGET_SET
return descriptor.annotationClass?.let(this::applicableTargetSet) ?: KotlinTarget.DEFAULT_TARGET_SET return descriptor.annotationClass?.let(this::applicableTargetSetFromTargetAnnotationOrNull) ?: KotlinTarget.DEFAULT_TARGET_SET
} }
@JvmStatic @JvmStatic
fun applicableTargetSet(descriptor: AnnotationDescriptor): Set<KotlinTarget> { fun applicableTargetSet(descriptor: AnnotationDescriptor): Set<KotlinTarget> {
val classDescriptor = descriptor.annotationClass ?: return emptySet() val classDescriptor = descriptor.annotationClass ?: return emptySet()
return applicableTargetSet(classDescriptor) ?: KotlinTarget.DEFAULT_TARGET_SET return applicableTargetSet(classDescriptor)
} }
fun applicableTargetSet(classDescriptor: ClassDescriptor): Set<KotlinTarget>? { fun applicableTargetSet(classDescriptor: ClassDescriptor): Set<KotlinTarget> {
val targetEntryDescriptor = classDescriptor.annotations.findAnnotation(StandardNames.FqNames.target)
return targetEntryDescriptor?.let { loadAnnotationTargets(it) } ?: KotlinTarget.DEFAULT_TARGET_SET
}
fun applicableTargetSetFromTargetAnnotationOrNull(classDescriptor: ClassDescriptor): Set<KotlinTarget>? {
val targetEntryDescriptor = classDescriptor.annotations.findAnnotation(StandardNames.FqNames.target) ?: return null val targetEntryDescriptor = classDescriptor.annotations.findAnnotation(StandardNames.FqNames.target) ?: return null
return loadAnnotationTargets(targetEntryDescriptor) return loadAnnotationTargets(targetEntryDescriptor)
} }
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.resolve.checkers
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
@@ -27,7 +26,7 @@ class AnnotationClassTargetAndRetentionChecker : DeclarationChecker {
if (declaration !is KtClassOrObject) return if (declaration !is KtClassOrObject) return
if (!DescriptorUtils.isAnnotationClass(descriptor)) return if (!DescriptorUtils.isAnnotationClass(descriptor)) return
val targets = AnnotationChecker.applicableTargetSet(descriptor) ?: return val targets = AnnotationChecker.applicableTargetSetFromTargetAnnotationOrNull(descriptor) ?: return
val retention = descriptor.getAnnotationRetention() ?: KotlinRetention.RUNTIME val retention = descriptor.getAnnotationRetention() ?: KotlinRetention.RUNTIME
if (targets.contains(KotlinTarget.EXPRESSION) && retention != KotlinRetention.SOURCE) { if (targets.contains(KotlinTarget.EXPRESSION) && retention != KotlinRetention.SOURCE) {
@@ -59,7 +59,7 @@ class ExperimentalMarkerDeclarationAnnotationChecker(private val module: ModuleD
} }
val annotationClass = annotation.annotationClass ?: continue val annotationClass = annotation.annotationClass ?: continue
if (annotationClass.annotations.any { it.fqName in OptInNames.EXPERIMENTAL_FQ_NAMES }) { if (annotationClass.annotations.any { it.fqName in OptInNames.EXPERIMENTAL_FQ_NAMES }) {
val applicableTargets = AnnotationChecker.applicableTargetSet(annotationClass) ?: KotlinTarget.DEFAULT_TARGET_SET val applicableTargets = AnnotationChecker.applicableTargetSet(annotationClass)
val possibleTargets = applicableTargets.intersect(actualTargets) val possibleTargets = applicableTargets.intersect(actualTargets)
val annotationUseSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget() val annotationUseSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget()
if (PROPERTY_GETTER in possibleTargets || if (PROPERTY_GETTER in possibleTargets ||