diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 2fa4497c419..466fdfe2b36 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -286,7 +286,7 @@ public interface Errors { DiagnosticFactory1 EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 EXPERIMENTAL_ANNOTATION_WITH_WRONG_RETENTION = DiagnosticFactory0.create(ERROR); - DiagnosticFactory0 EXPERIMENTAL_ANNOTATION_ON_GETTER = DiagnosticFactory0.create(ERROR); + DiagnosticFactory1 EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 EXPERIMENTAL_ANNOTATION_ON_OVERRIDE = DiagnosticFactory0.create(ERROR); DiagnosticFactory1 EXPERIMENTAL_UNSIGNED_LITERALS = DiagnosticFactory1.create(WARNING); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 221f180da38..7c0e09ac7db 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -170,7 +170,7 @@ public class DefaultErrorMessages { MAP.put(EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET, "Opt-in requirement marker annotation cannot be used on the following code elements: {0}. Please remove these targets", STRING); MAP.put(EXPERIMENTAL_ANNOTATION_WITH_WRONG_RETENTION, "Opt-in requirement marker annotation cannot be used with SOURCE retention. Please replace retention with BINARY"); - MAP.put(EXPERIMENTAL_ANNOTATION_ON_GETTER, "Opt-in requirement marker annotation cannot be used on getter. Please annotate property instead"); + MAP.put(EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET, "Opt-in requirement marker annotation cannot be used on {0}", STRING); MAP.put(EXPERIMENTAL_ANNOTATION_ON_OVERRIDE, "Opt-in requirement marker annotation on override requires the same marker on base declaration"); MAP.put(EXPERIMENTAL_UNSIGNED_LITERALS, "{0}", STRING); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalMarkerDeclarationAnnotationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalMarkerDeclarationAnnotationChecker.kt index ddc506caa73..8329a93d690 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalMarkerDeclarationAnnotationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalMarkerDeclarationAnnotationChecker.kt @@ -64,16 +64,31 @@ class ExperimentalMarkerDeclarationAnnotationChecker(private val module: ModuleD } val annotationClass = annotation.annotationClass ?: continue if (annotationClass.annotations.any { it.fqName in ExperimentalUsageChecker.EXPERIMENTAL_FQ_NAMES }) { + val annotationUseSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget() if (KotlinTarget.PROPERTY_GETTER in actualTargets || - entry.useSiteTarget?.getAnnotationUseSiteTarget() == AnnotationUseSiteTarget.PROPERTY_GETTER + annotationUseSiteTarget == AnnotationUseSiteTarget.PROPERTY_GETTER ) { - trace.report(Errors.EXPERIMENTAL_ANNOTATION_ON_GETTER.on(entry)) + trace.report(Errors.EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET.on(entry, "getter")) + } + if (KotlinTarget.VALUE_PARAMETER in actualTargets && annotationUseSiteTarget == null || + annotationUseSiteTarget == AnnotationUseSiteTarget.RECEIVER || + annotationUseSiteTarget == AnnotationUseSiteTarget.SETTER_PARAMETER || + annotationUseSiteTarget == AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER + ) { + trace.report(Errors.EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET.on(entry, "parameter")) + } + if (KotlinTarget.LOCAL_VARIABLE in actualTargets) { + trace.report(Errors.EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET.on(entry, "variable")) + } + if (annotationUseSiteTarget == AnnotationUseSiteTarget.FIELD || + annotationUseSiteTarget == AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD + ) { + trace.report(Errors.EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET.on(entry, "field")) } val annotated = entry.getStrictParentOfType() ?: continue - val useSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget() if (annotated is KtCallableDeclaration && annotated !is KtPropertyAccessor && - useSiteTarget == null && + annotationUseSiteTarget == null && annotated.hasModifier(KtTokens.OVERRIDE_KEYWORD) ) { val descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, annotated) diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.fir.kt index 70267d713d7..31484c4ba77 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.fir.kt @@ -41,7 +41,7 @@ annotation class E4 annotation class E5 @RequiresOptIn(level = RequiresOptIn.Level.WARNING) -@Target(PROPERTY, FUNCTION, PROPERTY_SETTER, VALUE_PARAMETER, FIELD) +@Target(PROPERTY, FUNCTION, PROPERTY_SETTER, VALUE_PARAMETER, FIELD, LOCAL_VARIABLE) @Retention(AnnotationRetention.BINARY) annotation class E6 @@ -83,9 +83,13 @@ class Derived : Base { override fun @receiver:E6 String.withReceiver() {} } -abstract class Another : Base { +abstract class Another(@param:E6 val x: String) : Base { @delegate:E6 override val bar: Int by lazy { 42 } + + fun baz(@E6 param: Int) { + @E6 val x = param + } } interface A { diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.kt index e35df2476ed..8c3225d4e8c 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.kt @@ -41,17 +41,17 @@ annotation class E4 annotation class E5 @RequiresOptIn(level = RequiresOptIn.Level.WARNING) -@Target(PROPERTY, FUNCTION, PROPERTY_SETTER, VALUE_PARAMETER, FIELD) +@Target(PROPERTY, FUNCTION, PROPERTY_SETTER, VALUE_PARAMETER, FIELD, LOCAL_VARIABLE) @Retention(AnnotationRetention.BINARY) annotation class E6 var some: Int - @E4 + @E4 get() = 42 @E5 set(value) {} -@get:E4 +@get:E4 val another: Int = 42 class My { @@ -74,18 +74,22 @@ class Derived : Base { @E6 override val bar: Int = 42 - @set:E6 @setparam:E6 + @set:E6 @setparam:E6 override var baz: Int = 13 @E6 override fun foo() {} - override fun @receiver:E6 String.withReceiver() {} + override fun @receiver:E6 String.withReceiver() {} } -abstract class Another : Base { - @delegate:E6 +abstract class Another(@param:E6 val x: String) : Base { + @delegate:E6 override val bar: Int by lazy { 42 } + + fun baz(@E6 param: Int) { + @E6 val x = param + } } interface A { diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.txt index 75b3a2a7518..271fa2ba27c 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.txt @@ -12,9 +12,11 @@ package api { } public abstract class Another : api.Base { - public constructor Another() + public constructor Another(/*0*/ @api.E6 x: kotlin.String) @delegate:api.E6 public open override /*1*/ val bar: kotlin.Int public abstract override /*1*/ /*fake_override*/ val baz: kotlin.Int + public final val x: kotlin.String + public final fun baz(/*0*/ @api.E6 param: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean @api.E6 public abstract override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int @@ -113,7 +115,7 @@ package api { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } - @kotlin.RequiresOptIn(level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD}) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) public final annotation class E6 : kotlin.Annotation { + @kotlin.RequiresOptIn(level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD, AnnotationTarget.LOCAL_VARIABLE}) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) public final annotation class E6 : kotlin.Annotation { public constructor E6() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int