diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java index 4e7294e2c8f..14c2b434fea 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java @@ -198,7 +198,7 @@ public abstract class AnnotationCodegen { private void generateTargetAnnotation(@NotNull ClassDescriptor classDescriptor, @NotNull Set annotationDescriptorsAlreadyPresent) { String descriptor = Type.getType(Target.class).getDescriptor(); if (!annotationDescriptorsAlreadyPresent.add(descriptor)) return; - Set targets = AnnotationChecker.Companion.possibleTargetSet(classDescriptor); + Set targets = AnnotationChecker.Companion.applicableTargetSet(classDescriptor); Set javaTargets; if (targets == null) { javaTargets = getJavaTargetList(classDescriptor); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt index a7c8c9fa1d7..e83471285f2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt @@ -51,7 +51,7 @@ public class AnnotationChecker(private val additionalCheckers: Iterable, actualTargets: List, trace: BindingTrace) { + private fun checkEntries(entries: List, actualTargets: TargetList, trace: BindingTrace) { val entryTypes: MutableSet = hashSetOf() for (entry in entries) { checkAnnotationEntry(entry, actualTargets, trace) @@ -69,26 +69,39 @@ public class AnnotationChecker(private val additionalCheckers: Iterable, trace: BindingTrace) { - val possibleTargets = possibleTargetSet(entry, trace) - if (actualTargets.any { it in possibleTargets }) return - trace.report(Errors.WRONG_ANNOTATION_TARGET.on(entry, actualTargets.firstOrNull()?.description ?: "unidentified target")) + private fun checkAnnotationEntry(entry: JetAnnotationEntry, actualTargets: TargetList, trace: BindingTrace) { + val applicableTargets = applicableTargetSet(entry, trace) + val useSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget() + + if (actualTargets.declarationSite.any { + it in applicableTargets && (useSiteTarget == null || KotlinTarget.USE_SITE_MAPPING[useSiteTarget] == it) + }) return + + if (useSiteTarget != null && actualTargets.useSite.any { + it in applicableTargets && KotlinTarget.USE_SITE_MAPPING[useSiteTarget] == it + }) return + + trace.report(Errors.WRONG_ANNOTATION_TARGET.on(entry, actualTargets.declarationSite.firstOrNull()?.description ?: "unidentified target")) } companion object { - private fun possibleTargetSet(entry: JetAnnotationEntry, trace: BindingTrace): Set { + private val PROPERTY_USE_SITE_TARGETS = listOf( + KotlinTarget.FIELD, KotlinTarget.PROPERTY_GETTER, KotlinTarget.PROPERTY_SETTER, KotlinTarget.VALUE_PARAMETER) + private val VALUE_PARAMETER_USE_SITE_TARGETS = PROPERTY_USE_SITE_TARGETS + KotlinTarget.PROPERTY + + private fun applicableTargetSet(entry: JetAnnotationEntry, trace: BindingTrace): Set { val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: return KotlinTarget.DEFAULT_TARGET_SET // For descriptor with error type, all targets are considered as possible if (descriptor.type.isError) return KotlinTarget.ALL_TARGET_SET val classDescriptor = TypeUtils.getClassDescriptor(descriptor.type) ?: return KotlinTarget.DEFAULT_TARGET_SET - return possibleTargetSet(classDescriptor) ?: KotlinTarget.DEFAULT_TARGET_SET + return applicableTargetSet(classDescriptor) ?: KotlinTarget.DEFAULT_TARGET_SET } - public fun possibleTargetSet(classDescriptor: ClassDescriptor): Set? { + public fun applicableTargetSet(classDescriptor: ClassDescriptor): Set? { val targetEntryDescriptor = classDescriptor.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.target) ?: return null val valueArguments = targetEntryDescriptor.allValueArguments @@ -98,41 +111,71 @@ public class AnnotationChecker(private val additionalCheckers: Iterable { + public fun getDeclarationSiteActualTargetList(annotated: JetElement, descriptor: ClassDescriptor?): List { + return getActualTargetList(annotated, descriptor).declarationSite + } + + private fun getActualTargetList(annotated: JetElement, descriptor: ClassDescriptor?): TargetList { return when (annotated) { - is JetClassOrObject -> descriptor?.let { KotlinTarget.classActualTargets(it) } ?: listOf(CLASSIFIER) + is JetClassOrObject -> descriptor?.let { TargetList(KotlinTarget.classActualTargets(it)) } ?: targetList(CLASSIFIER) is JetProperty -> if (annotated.isLocal) { - listOf(LOCAL_VARIABLE) + extendedTargetList(PROPERTY_USE_SITE_TARGETS, LOCAL_VARIABLE) } else if (annotated.parent is JetClassOrObject || annotated.parent is JetClassBody) { - listOf(MEMBER_PROPERTY, PROPERTY, FIELD) + extendedTargetList(PROPERTY_USE_SITE_TARGETS, MEMBER_PROPERTY, PROPERTY, FIELD) } else { - listOf(TOP_LEVEL_PROPERTY, PROPERTY, FIELD) + extendedTargetList(PROPERTY_USE_SITE_TARGETS, TOP_LEVEL_PROPERTY, PROPERTY, FIELD) } - is JetParameter -> if (annotated.hasValOrVar()) listOf(PROPERTY_PARAMETER, MEMBER_PROPERTY, PROPERTY, FIELD) else listOf(VALUE_PARAMETER) - is JetConstructor<*> -> listOf(CONSTRUCTOR) - is JetFunction -> + is JetParameter -> { + if (annotated.hasValOrVar()) { + extendedTargetList(VALUE_PARAMETER_USE_SITE_TARGETS, PROPERTY_PARAMETER, MEMBER_PROPERTY, PROPERTY, FIELD) + } + else { + extendedTargetList(VALUE_PARAMETER_USE_SITE_TARGETS, VALUE_PARAMETER) + } + } + is JetConstructor<*> -> targetList(CONSTRUCTOR) + is JetFunction -> { + val extendedTargets = listOf(KotlinTarget.VALUE_PARAMETER) if (annotated.isLocal) { - listOf(LOCAL_FUNCTION, FUNCTION) + extendedTargetList(extendedTargets, LOCAL_FUNCTION, FUNCTION) } else if (annotated.parent is JetClassOrObject || annotated.parent is JetClassBody) { - listOf(MEMBER_FUNCTION, FUNCTION) + extendedTargetList(extendedTargets, MEMBER_FUNCTION, FUNCTION) } else { - listOf(TOP_LEVEL_FUNCTION, FUNCTION) + extendedTargetList(extendedTargets, TOP_LEVEL_FUNCTION, FUNCTION) } - is JetPropertyAccessor -> if (annotated.isGetter) listOf(PROPERTY_GETTER) else listOf(PROPERTY_SETTER) - is JetPackageDirective -> listOf(PACKAGE) - is JetTypeReference -> listOf(TYPE) - is JetFile -> listOf(FILE) - is JetTypeParameter -> listOf(TYPE_PARAMETER) - is JetTypeProjection -> if (annotated.projectionKind == JetProjectionKind.STAR) listOf(STAR_PROJECTION) else listOf(TYPE_PROJECTION) - is JetClassInitializer -> listOf(INITIALIZER) - else -> listOf() + } + is JetPropertyAccessor -> if (annotated.isGetter) targetList(PROPERTY_GETTER) else targetList(PROPERTY_SETTER) + is JetPackageDirective -> targetList(PACKAGE) + is JetTypeReference -> targetList(TYPE) + is JetFile -> targetList(FILE) + is JetTypeParameter -> targetList(TYPE_PARAMETER) + is JetTypeProjection -> { + if (annotated.projectionKind == JetProjectionKind.STAR) { + targetList(STAR_PROJECTION) + } + else { + targetList(TYPE_PROJECTION) + } + } + is JetClassInitializer -> targetList(INITIALIZER) + else -> targetList() } } + + private class TargetList(val declarationSite: List, val useSite: List = emptyList()) + + private fun targetList(vararg target: KotlinTarget): TargetList { + return TargetList(listOf(*target), emptyList()) + } + + private fun extendedTargetList(extended: List, vararg target: KotlinTarget): TargetList { + return TargetList(listOf(*target), extended) + } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt index ed583743c8d..0dece5ca3aa 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt @@ -208,7 +208,7 @@ public object ModifierCheckerCore { } } } - val actualTargets = AnnotationChecker.getActualTargetList(listOwner, descriptor as? ClassDescriptor) + val actualTargets = AnnotationChecker.getDeclarationSiteActualTargetList(listOwner, descriptor as? ClassDescriptor) val list = listOwner.modifierList ?: return checkModifierList(list, trace, descriptor?.containingDeclaration, actualTargets) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/KotlinTarget.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/KotlinTarget.kt index c13f49f849e..dc7e154c3f9 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/KotlinTarget.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/KotlinTarget.kt @@ -102,5 +102,16 @@ public enum class KotlinTarget(val description: String, val isDefault: Boolean = } ClassKind.ENUM_ENTRY -> listOf(ENUM_ENTRY, PROPERTY, FIELD) } + + public val USE_SITE_MAPPING: Map = mapOf( + AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER to VALUE_PARAMETER, + AnnotationUseSiteTarget.FIELD to FIELD, + AnnotationUseSiteTarget.PROPERTY to PROPERTY, + AnnotationUseSiteTarget.FILE to FILE, + AnnotationUseSiteTarget.PROPERTY_GETTER to PROPERTY_GETTER, + AnnotationUseSiteTarget.PROPERTY_SETTER to PROPERTY_SETTER, + AnnotationUseSiteTarget.RECEIVER to VALUE_PARAMETER, + AnnotationUseSiteTarget.SETTER_PARAMETER to VALUE_PARAMETER) + } } \ No newline at end of file