More accurate check of repeated use-site annotations #KT-13859 Fixed
This commit is contained in:
@@ -41,7 +41,7 @@ class AnnotationChecker(private val additionalCheckers: Iterable<AdditionalAnnot
|
||||
|
||||
fun check(annotated: KtAnnotated, trace: BindingTrace, descriptor: DeclarationDescriptor? = null) {
|
||||
val actualTargets = getActualTargetList(annotated, descriptor, trace)
|
||||
checkEntries(annotated.annotationEntries, actualTargets, trace)
|
||||
checkEntries(annotated.annotationEntries, actualTargets, trace, annotated)
|
||||
if (annotated is KtCallableDeclaration) {
|
||||
annotated.typeReference?.let { check(it, trace) }
|
||||
annotated.receiverTypeReference?.let { check(it, trace) }
|
||||
@@ -78,7 +78,28 @@ class AnnotationChecker(private val additionalCheckers: Iterable<AdditionalAnnot
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkEntries(entries: List<KtAnnotationEntry>, actualTargets: TargetList, trace: BindingTrace) {
|
||||
private fun KtAnnotated?.getImplicitUseSiteTargetList(): List<AnnotationUseSiteTarget> = 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<KtAnnotationEntry>,
|
||||
actualTargets: TargetList,
|
||||
trace: BindingTrace,
|
||||
annotated: KtAnnotated? = null
|
||||
) {
|
||||
val entryTypesWithAnnotations = hashMapOf<KotlinType, MutableList<AnnotationUseSiteTarget?>>()
|
||||
|
||||
for (entry in entries) {
|
||||
@@ -86,7 +107,7 @@ class AnnotationChecker(private val additionalCheckers: Iterable<AdditionalAnnot
|
||||
val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue
|
||||
val classDescriptor = TypeUtils.getClassDescriptor(descriptor.type) ?: continue
|
||||
|
||||
val useSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget()
|
||||
val useSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget() ?: annotated.getDefaultUseSiteTarget(descriptor)
|
||||
val existingTargetsForAnnotation = entryTypesWithAnnotations.getOrPut(descriptor.type) { arrayListOf() }
|
||||
val duplicateAnnotation = useSiteTarget in existingTargetsForAnnotation
|
||||
|| (existingTargetsForAnnotation.any { (it == null) != (useSiteTarget == null) })
|
||||
@@ -332,6 +353,15 @@ class AnnotationChecker(private val additionalCheckers: Iterable<AdditionalAnnot
|
||||
val defaultTargets: List<KotlinTarget>,
|
||||
val canBeSubstituted: List<KotlinTarget> = emptyList(),
|
||||
val onlyWithUseSiteTarget: List<KotlinTarget> = emptyList())
|
||||
|
||||
private object UseSiteTargetsList {
|
||||
val T_CONSTRUCTOR_PARAMETER = listOf(AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER,
|
||||
AnnotationUseSiteTarget.PROPERTY,
|
||||
AnnotationUseSiteTarget.FIELD)
|
||||
|
||||
val T_PROPERTY = listOf(AnnotationUseSiteTarget.PROPERTY,
|
||||
AnnotationUseSiteTarget.FIELD)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,4 +10,12 @@ annotation class ann(val y: Int)
|
||||
|
||||
@ann(0) <!REPEATED_ANNOTATION!>@ann(1)<!> fun foo(@ann(7) <!REPEATED_ANNOTATION!>@ann(2)<!> x: Int): Int {
|
||||
@annexpr <!REPEATED_ANNOTATION!>@annexpr<!> return x
|
||||
}
|
||||
}
|
||||
|
||||
@unrepann(0)
|
||||
@get:unrepann(1)
|
||||
var annotated = 1 // No errors should be here
|
||||
|
||||
@unrepann(0)
|
||||
<!REPEATED_ANNOTATION!>@property:unrepann(1)<!>
|
||||
var annotated2 = 2
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+22
-5
@@ -14,7 +14,7 @@ public class A(@param:Ann <!REPEATED_ANNOTATION!>@Ann<!> val x: Int, @param: Rep
|
||||
@field:Ann @property:Ann @RepeatableAnn @property:RepeatableAnn
|
||||
val a: Int = 0
|
||||
|
||||
@Ann <!REPEATED_ANNOTATION!>@field:Ann<!> <!REPEATED_ANNOTATION!>@property:Ann<!>
|
||||
@Ann @field:Ann <!REPEATED_ANNOTATION!>@property:Ann<!>
|
||||
val b: Int = 0
|
||||
|
||||
@field:RepeatableAnn @field:RepeatableAnn
|
||||
@@ -29,14 +29,31 @@ public class A(@param:Ann <!REPEATED_ANNOTATION!>@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 <!REPEATED_ANNOTATION!>@delegate:Ann<!>
|
||||
@Ann @delegate:Ann
|
||||
val g: String by CustomDelegate()
|
||||
|
||||
@Ann <!REPEATED_ANNOTATION!>@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(<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@param:fieldOrPropAnn<!> @fieldOrPropAnn val x: Int,
|
||||
@property:fieldOrPropAnn <!REPEATED_ANNOTATION!>@fieldOrPropAnn<!> val y: Int) {
|
||||
@fieldOrPropAnn @field:fieldOrPropAnn
|
||||
val z: Int = 42
|
||||
|
||||
<!WRONG_ANNOTATION_TARGET!>@getSetAndParamAnn<!>
|
||||
<!REPEATED_ANNOTATION!>@setparam:getSetAndParamAnn<!>
|
||||
var w: Int
|
||||
@getSetAndParamAnn <!REPEATED_ANNOTATION!>@get:getSetAndParamAnn<!> get() = 0
|
||||
// See KT-15470: fake INAPPLICABLE_TARGET_ON_PROPERTY
|
||||
@getSetAndParamAnn <!INAPPLICABLE_TARGET_ON_PROPERTY, REPEATED_ANNOTATION!>@set:getSetAndParamAnn<!> set(arg) {}
|
||||
}
|
||||
+25
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user