Allow multiple non-repeatable annotations with different targets
This commit is contained in:
+12
-2
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.container.StorageComponentContainer
|
||||
import org.jetbrains.kotlin.container.useImpl
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
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.DiagnosticSink
|
||||
@@ -97,15 +98,24 @@ public object JvmPlatformConfigurator : PlatformConfigurator(
|
||||
|
||||
public object RepeatableAnnotationChecker: AdditionalAnnotationChecker {
|
||||
override fun checkEntries(entries: List<JetAnnotationEntry>, actualTargets: List<KotlinTarget>, trace: BindingTrace) {
|
||||
val entryTypes: MutableSet<JetType> = hashSetOf()
|
||||
val entryTypesWithAnnotations = hashMapOf<JetType, MutableList<AnnotationUseSiteTarget?>>()
|
||||
|
||||
for (entry in entries) {
|
||||
val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue
|
||||
val classDescriptor = TypeUtils.getClassDescriptor(descriptor.type) ?: continue
|
||||
if (!entryTypes.add(descriptor.type)
|
||||
|
||||
val useSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget()
|
||||
val existingTargetsForAnnotation = entryTypesWithAnnotations.getOrPut(descriptor.type) { arrayListOf() }
|
||||
val duplicateAnnotation = useSiteTarget in existingTargetsForAnnotation
|
||||
|| (existingTargetsForAnnotation.any { (it == null) != (useSiteTarget == null) })
|
||||
|
||||
if (duplicateAnnotation
|
||||
&& classDescriptor.isRepeatableAnnotation()
|
||||
&& classDescriptor.getAnnotationRetention() != KotlinRetention.SOURCE) {
|
||||
trace.report(ErrorsJvm.NON_SOURCE_REPEATED_ANNOTATION.on(entry));
|
||||
}
|
||||
|
||||
existingTargetsForAnnotation.add(useSiteTarget)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getAnnotationEntries
|
||||
@@ -61,14 +63,23 @@ public class AnnotationChecker(private val additionalCheckers: Iterable<Addition
|
||||
}
|
||||
|
||||
private fun checkEntries(entries: List<JetAnnotationEntry>, actualTargets: TargetList, trace: BindingTrace) {
|
||||
val entryTypes: MutableSet<JetType> = hashSetOf()
|
||||
val entryTypesWithAnnotations = hashMapOf<JetType, MutableList<AnnotationUseSiteTarget?>>()
|
||||
|
||||
for (entry in entries) {
|
||||
checkAnnotationEntry(entry, actualTargets, trace)
|
||||
val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue
|
||||
val classDescriptor = TypeUtils.getClassDescriptor(descriptor.type) ?: continue
|
||||
if (!entryTypes.add(descriptor.type) && !classDescriptor.isRepeatableAnnotation()) {
|
||||
|
||||
val useSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget()
|
||||
val existingTargetsForAnnotation = entryTypesWithAnnotations.getOrPut(descriptor.type) { arrayListOf() }
|
||||
val duplicateAnnotation = useSiteTarget in existingTargetsForAnnotation
|
||||
|| (existingTargetsForAnnotation.any { (it == null) != (useSiteTarget == null) })
|
||||
|
||||
if (duplicateAnnotation && !classDescriptor.isRepeatableAnnotation()) {
|
||||
trace.report(Errors.REPEATED_ANNOTATION.on(entry));
|
||||
}
|
||||
|
||||
existingTargetsForAnnotation.add(useSiteTarget)
|
||||
}
|
||||
additionalCheckers.forEach { it.checkEntries(entries, actualTargets.declarationSite, trace) }
|
||||
}
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
annotation(repeatable = true) class RepeatableAnn
|
||||
annotation class Ann
|
||||
|
||||
public class A(@param:Ann <!REPEATED_ANNOTATION!>@Ann<!> val x: Int, @param: RepeatableAnn @Ann val y: Int) {
|
||||
|
||||
@field:Ann @property:Ann @RepeatableAnn @property:RepeatableAnn
|
||||
val a: Int = 0
|
||||
|
||||
@Ann <!REPEATED_ANNOTATION!>@field:Ann<!> <!REPEATED_ANNOTATION!>@property:Ann<!>
|
||||
val b: Int = 0
|
||||
|
||||
@field:RepeatableAnn @field:RepeatableAnn
|
||||
val c: Int = 0
|
||||
|
||||
@property:RepeatableAnn @RepeatableAnn
|
||||
val d: Int = 0
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package
|
||||
|
||||
public final class A {
|
||||
public constructor A(/*0*/ Ann() Ann() x: kotlin.Int, /*1*/ RepeatableAnn() Ann() y: kotlin.Int)
|
||||
Ann() RepeatableAnn() Ann() RepeatableAnn() internal final val a: kotlin.Int = 0
|
||||
Ann() Ann() Ann() internal final val b: kotlin.Int = 0
|
||||
RepeatableAnn() RepeatableAnn() internal final val c: kotlin.Int = 0
|
||||
RepeatableAnn() RepeatableAnn() internal final val d: kotlin.Int = 0
|
||||
internal final val x: kotlin.Int
|
||||
internal final val y: kotlin.Int
|
||||
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.annotation() internal final class Ann : kotlin.Annotation {
|
||||
public constructor Ann()
|
||||
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.annotation(repeatable = true) internal final class RepeatableAnn : kotlin.Annotation {
|
||||
public constructor RepeatableAnn()
|
||||
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
|
||||
}
|
||||
@@ -1232,6 +1232,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("repeatable.kt")
|
||||
public void testRepeatable() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/repeatable.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SetterAnnotations.kt")
|
||||
public void testSetterAnnotations() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/SetterAnnotations.kt");
|
||||
|
||||
Reference in New Issue
Block a user