diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index eb93faa4e04..ab1f73af2d9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -286,6 +286,8 @@ 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_UNSIGNED_LITERALS = DiagnosticFactory1.create(WARNING); DiagnosticFactory1 EXPERIMENTAL_UNSIGNED_LITERALS_ERROR = DiagnosticFactory1.create(ERROR); 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 006b7ef3298..660d39d8108 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -170,6 +170,8 @@ 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_UNSIGNED_LITERALS, "{0}", STRING); MAP.put(EXPERIMENTAL_UNSIGNED_LITERALS_ERROR, "{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 2f389d2e965..f3eab1ed637 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalMarkerDeclarationAnnotationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalMarkerDeclarationAnnotationChecker.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.resolve.checkers import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget import org.jetbrains.kotlin.diagnostics.Errors @@ -19,12 +20,15 @@ import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.constants.ArrayValue import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.KClassValue +import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.getAnnotationRetention import org.jetbrains.kotlin.utils.addToStdlib.safeAs class ExperimentalMarkerDeclarationAnnotationChecker(private val module: ModuleDescriptor) : AdditionalAnnotationChecker { - private val WRONG_TARGETS_FOR_MARKER = setOf(KotlinTarget.EXPRESSION, KotlinTarget.FILE) + companion object { + private val WRONG_TARGETS_FOR_MARKER = setOf(KotlinTarget.EXPRESSION, KotlinTarget.FILE) + } override fun checkEntries( entries: List, @@ -34,11 +38,11 @@ class ExperimentalMarkerDeclarationAnnotationChecker(private val module: ModuleD var isAnnotatedWithExperimental = false for (entry in entries) { - val annotation = trace.bindingContext.get(BindingContext.ANNOTATION, entry) - when (annotation?.fqName) { + val annotation = trace.bindingContext.get(BindingContext.ANNOTATION, entry) ?: continue + when (annotation.fqName) { in ExperimentalUsageChecker.USE_EXPERIMENTAL_FQ_NAMES -> { val annotationClasses = - annotation!!.allValueArguments[ExperimentalUsageChecker.USE_EXPERIMENTAL_ANNOTATION_CLASS] + annotation.allValueArguments[ExperimentalUsageChecker.USE_EXPERIMENTAL_ANNOTATION_CLASS] .safeAs()?.value.orEmpty() checkUseExperimentalUsage(annotationClasses, trace, entry) } @@ -46,6 +50,13 @@ class ExperimentalMarkerDeclarationAnnotationChecker(private val module: ModuleD isAnnotatedWithExperimental = true } } + if (annotation.annotationClass?.annotations?.any { it.fqName in ExperimentalUsageChecker.EXPERIMENTAL_FQ_NAMES } == true) { + if (KotlinTarget.PROPERTY_GETTER in actualTargets || + entry.useSiteTarget?.getAnnotationUseSiteTarget() == AnnotationUseSiteTarget.PROPERTY_GETTER + ) { + trace.report(Errors.EXPERIMENTAL_ANNOTATION_ON_GETTER.on(entry)) + } + } } if (isAnnotatedWithExperimental) { diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.fir.kt index e729db8d180..ad889d7b125 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.fir.kt @@ -7,7 +7,7 @@ import kotlin.annotation.AnnotationTarget.* @RequiresOptIn(level = RequiresOptIn.Level.WARNING) @Target(CLASS, ANNOTATION_CLASS, TYPE_PARAMETER, PROPERTY, FIELD, LOCAL_VARIABLE, VALUE_PARAMETER, CONSTRUCTOR, FUNCTION, - PROPERTY_GETTER, PROPERTY_SETTER, TYPE, TYPEALIAS) + PROPERTY_SETTER, TYPE, TYPEALIAS) @Retention(AnnotationRetention.BINARY) annotation class E1 @@ -21,6 +21,20 @@ annotation class E2 annotation class E3 @RequiresOptIn(level = RequiresOptIn.Level.WARNING) -@Target(FILE, EXPRESSION) -@Retention(AnnotationRetention.SOURCE) +@Target(PROPERTY_GETTER) +@Retention(AnnotationRetention.BINARY) annotation class E4 + +@RequiresOptIn(level = RequiresOptIn.Level.WARNING) +@Target(PROPERTY_SETTER) +@Retention(AnnotationRetention.BINARY) +annotation class E5 + +var some: Int + @E4 + get() = 42 + @E5 + set(value) {} + +@get:E4 +val another: Int = 42 diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.kt index 4e6747fb202..48828fc6700 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.kt @@ -7,7 +7,7 @@ import kotlin.annotation.AnnotationTarget.* @RequiresOptIn(level = RequiresOptIn.Level.WARNING) @Target(CLASS, ANNOTATION_CLASS, TYPE_PARAMETER, PROPERTY, FIELD, LOCAL_VARIABLE, VALUE_PARAMETER, CONSTRUCTOR, FUNCTION, - PROPERTY_GETTER, PROPERTY_SETTER, TYPE, TYPEALIAS) + PROPERTY_SETTER, TYPE, TYPEALIAS) @Retention(AnnotationRetention.BINARY) annotation class E1 @@ -21,6 +21,21 @@ annotation class E2 annotation class E3 @RequiresOptIn(level = RequiresOptIn.Level.WARNING) -@Target(FILE, EXPRESSION) -@Retention(AnnotationRetention.SOURCE) +@Target(PROPERTY_GETTER) +@Retention(AnnotationRetention.BINARY) annotation class E4 + +@RequiresOptIn(level = RequiresOptIn.Level.WARNING) +@Target(PROPERTY_SETTER) +@Retention(AnnotationRetention.BINARY) +annotation class E5 + +var some: Int + @E4 + get() = 42 + @E5 + set(value) {} + +@get:E4 +val another: Int = 42 + diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.txt index 9883d6e56d2..a4c71c6b7f8 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.txt @@ -1,8 +1,10 @@ package package api { + @get:api.E4 public val another: kotlin.Int = 42 + @get:api.E4 @set:api.E5 public var some: kotlin.Int - @kotlin.RequiresOptIn(level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY, AnnotationTarget.FIELD, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.TYPE, AnnotationTarget.TYPEALIAS}) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) public final annotation class E1 : kotlin.Annotation { + @kotlin.RequiresOptIn(level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY, AnnotationTarget.FIELD, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.TYPE, AnnotationTarget.TYPEALIAS}) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) public final annotation class E1 : kotlin.Annotation { public constructor E1() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int @@ -23,10 +25,17 @@ package api { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } - @kotlin.RequiresOptIn(level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.FILE, AnnotationTarget.EXPRESSION}) @kotlin.annotation.Retention(value = AnnotationRetention.SOURCE) public final annotation class E4 : kotlin.Annotation { + @kotlin.RequiresOptIn(level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.PROPERTY_GETTER}) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) public final annotation class E4 : kotlin.Annotation { public constructor E4() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } + + @kotlin.RequiresOptIn(level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.PROPERTY_SETTER}) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) public final annotation class E5 : kotlin.Annotation { + public constructor E5() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } }