Forbid experimental markers on various targets #KT-45845 Fixed

In this commit we forbid experimental markers on:
- local variables
- value parameters
- fields, including delegate fields
- property getters
This commit is contained in:
Mikhail Glukhikh
2021-06-07 16:28:34 +03:00
committed by teamcityserver
parent eb9c658c1c
commit 63bc3f9708
6 changed files with 42 additions and 17 deletions
@@ -286,7 +286,7 @@ public interface Errors {
DiagnosticFactory1<KtAnnotationEntry, String> EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> EXPERIMENTAL_ANNOTATION_WITH_WRONG_RETENTION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtAnnotationEntry> EXPERIMENTAL_ANNOTATION_ON_GETTER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<KtAnnotationEntry, String> EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<KtAnnotationEntry> EXPERIMENTAL_ANNOTATION_ON_OVERRIDE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, String> EXPERIMENTAL_UNSIGNED_LITERALS = DiagnosticFactory1.create(WARNING);
@@ -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);
@@ -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<KtAnnotated>() ?: 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)
@@ -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 {
@@ -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
<!EXPERIMENTAL_ANNOTATION_ON_GETTER!>@E4<!>
<!EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET!>@E4<!>
get() = 42
@E5
set(value) {}
<!EXPERIMENTAL_ANNOTATION_ON_GETTER!>@get:E4<!>
<!EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET!>@get:E4<!>
val another: Int = 42
class My {
@@ -74,18 +74,22 @@ class Derived : Base {
<!EXPERIMENTAL_ANNOTATION_ON_OVERRIDE!>@E6<!>
override val bar: Int = 42
@set:E6 @setparam:E6
@set:E6 <!EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET!>@setparam:E6<!>
override var baz: Int = 13
@E6
override fun foo() {}
override fun @receiver:E6 String.withReceiver() {}
override fun <!EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET!>@receiver:E6<!> String.withReceiver() {}
}
abstract class Another : Base {
@delegate:E6
abstract class Another(<!EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET!>@param:E6<!> val x: String) : Base {
<!EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET!>@delegate:E6<!>
override val bar: Int by lazy { 42 }
fun baz(<!EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET!>@E6<!> param: Int) {
<!EXPERIMENTAL_ANNOTATION_ON_WRONG_TARGET!>@E6<!> val x = param
}
}
interface A {
@@ -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