From 5f3c1dfc4194b8b0c40c66f6b0af223afb70243f Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Thu, 22 Dec 2016 20:04:57 +0300 Subject: [PATCH] More accurate check of repeated use-site annotations #KT-13859 Fixed --- .../kotlin/resolve/AnnotationChecker.kt | 36 +++++++++++++++++-- .../tests/annotations/options/unrepeatable.kt | 10 +++++- .../annotations/options/unrepeatable.txt | 2 ++ .../withUseSiteTarget/repeatable.kt | 27 +++++++++++--- .../withUseSiteTarget/repeatable.txt | 25 +++++++++++++ 5 files changed, 91 insertions(+), 9 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt index e1bc8ebc911..5e839c68e06 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt @@ -41,7 +41,7 @@ class AnnotationChecker(private val additionalCheckers: Iterable, actualTargets: TargetList, trace: BindingTrace) { + private fun KtAnnotated?.getImplicitUseSiteTargetList(): List = when (this) { + is KtParameter -> + if (ownerFunction is KtPrimaryConstructor) UseSiteTargetsList.T_CONSTRUCTOR_PARAMETER else emptyList() + is KtProperty -> + if (!isLocal) UseSiteTargetsList.T_PROPERTY else emptyList() + is KtPropertyAccessor -> + if (isGetter) listOf(AnnotationUseSiteTarget.PROPERTY_GETTER) else listOf(AnnotationUseSiteTarget.PROPERTY_SETTER) + else -> + emptyList() + } + + private fun KtAnnotated?.getDefaultUseSiteTarget(descriptor: AnnotationDescriptor) = + getImplicitUseSiteTargetList().firstOrNull { + KotlinTarget.USE_SITE_MAPPING[it] in AnnotationChecker.applicableTargetSet(descriptor) + } + + private fun checkEntries( + entries: List, + actualTargets: TargetList, + trace: BindingTrace, + annotated: KtAnnotated? = null + ) { val entryTypesWithAnnotations = hashMapOf>() for (entry in entries) { @@ -86,7 +107,7 @@ class AnnotationChecker(private val additionalCheckers: Iterable, val canBeSubstituted: List = emptyList(), val onlyWithUseSiteTarget: List = emptyList()) + + private object UseSiteTargetsList { + val T_CONSTRUCTOR_PARAMETER = listOf(AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER, + AnnotationUseSiteTarget.PROPERTY, + AnnotationUseSiteTarget.FIELD) + + val T_PROPERTY = listOf(AnnotationUseSiteTarget.PROPERTY, + AnnotationUseSiteTarget.FIELD) + } } } diff --git a/compiler/testData/diagnostics/tests/annotations/options/unrepeatable.kt b/compiler/testData/diagnostics/tests/annotations/options/unrepeatable.kt index 56318cf3d12..9ba2e58edc7 100644 --- a/compiler/testData/diagnostics/tests/annotations/options/unrepeatable.kt +++ b/compiler/testData/diagnostics/tests/annotations/options/unrepeatable.kt @@ -10,4 +10,12 @@ annotation class ann(val y: Int) @ann(0) @ann(1) fun foo(@ann(7) @ann(2) x: Int): Int { @annexpr @annexpr return x -} \ No newline at end of file +} + +@unrepann(0) +@get:unrepann(1) +var annotated = 1 // No errors should be here + +@unrepann(0) +@property:unrepann(1) +var annotated2 = 2 diff --git a/compiler/testData/diagnostics/tests/annotations/options/unrepeatable.txt b/compiler/testData/diagnostics/tests/annotations/options/unrepeatable.txt index 0e90958fe26..43fcf6c2be0 100644 --- a/compiler/testData/diagnostics/tests/annotations/options/unrepeatable.txt +++ b/compiler/testData/diagnostics/tests/annotations/options/unrepeatable.txt @@ -1,5 +1,7 @@ package +@unrepann(x = 0) public var annotated: kotlin.Int +@unrepann(x = 0) @property:unrepann(x = 1) public var annotated2: kotlin.Int @ann(y = 0) @ann(y = 1) public fun foo(/*0*/ @ann(y = 7) @ann(y = 2) x: kotlin.Int): kotlin.Int @unrepann(x = 1) @unrepann(x = 2) public final class DoubleAnnotated { diff --git a/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/repeatable.kt b/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/repeatable.kt index 309e4341e1c..ec5d48ca946 100644 --- a/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/repeatable.kt +++ b/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/repeatable.kt @@ -14,7 +14,7 @@ public class A(@param:Ann @Ann val x: Int, @param: Rep @field:Ann @property:Ann @RepeatableAnn @property:RepeatableAnn val a: Int = 0 - @Ann @field:Ann @property:Ann + @Ann @field:Ann @property:Ann val b: Int = 0 @field:RepeatableAnn @field:RepeatableAnn @@ -29,14 +29,31 @@ public class A(@param:Ann @Ann val x: Int, @param: Rep @property:Ann @delegate:Ann val f: String by CustomDelegate() - // Ideally we should not have repeated anotation here and below - // (because @Ann should go to the property and the second annotation to its related field) - @Ann @delegate:Ann + @Ann @delegate:Ann val g: String by CustomDelegate() - @Ann @field:Ann + @Ann @field:Ann val h: String = "" @property:Ann @field:Ann val i: String = "" +} + +@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY) +annotation class fieldOrPropAnn + +@Target(AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.VALUE_PARAMETER) +annotation class getSetAndParamAnn + +public class B(@param:fieldOrPropAnn @fieldOrPropAnn val x: Int, + @property:fieldOrPropAnn @fieldOrPropAnn val y: Int) { + @fieldOrPropAnn @field:fieldOrPropAnn + val z: Int = 42 + + @getSetAndParamAnn + @setparam:getSetAndParamAnn + var w: Int + @getSetAndParamAnn @get:getSetAndParamAnn get() = 0 + // See KT-15470: fake INAPPLICABLE_TARGET_ON_PROPERTY + @getSetAndParamAnn @set:getSetAndParamAnn set(arg) {} } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/repeatable.txt b/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/repeatable.txt index 20dddf85af8..349d818575b 100644 --- a/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/repeatable.txt +++ b/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/repeatable.txt @@ -25,6 +25,17 @@ public final annotation class Ann : kotlin.Annotation { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } +public final class B { + public constructor B(/*0*/ @param:fieldOrPropAnn x: kotlin.Int, /*1*/ y: kotlin.Int) + @getSetAndParamAnn @setparam:getSetAndParamAnn public final var w: kotlin.Int + @fieldOrPropAnn public final val x: kotlin.Int + @property:fieldOrPropAnn @fieldOrPropAnn public final val y: kotlin.Int + @fieldOrPropAnn @field:fieldOrPropAnn public final val z: kotlin.Int = 42 + 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 +} + public final class CustomDelegate { public constructor CustomDelegate() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean @@ -39,3 +50,17 @@ public final class CustomDelegate { public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } + +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.FIELD, AnnotationTarget.PROPERTY}) public final annotation class fieldOrPropAnn : kotlin.Annotation { + public constructor fieldOrPropAnn() + 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.annotation.Target(allowedTargets = {AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.VALUE_PARAMETER}) public final annotation class getSetAndParamAnn : kotlin.Annotation { + public constructor getSetAndParamAnn() + 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 +}