From 67128c022aede383a13ab5c5bbb68ba8cbea7a39 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Sat, 24 Jul 2021 00:47:35 +0200 Subject: [PATCH] Report error if both repeatable annotation and its container are used #KT-12794 --- ...irOldFrontendDiagnosticsTestGenerated.java | 12 ++ ...DiagnosticsWithLightTreeTestGenerated.java | 12 ++ .../checkers/RepeatableAnnotationChecker.kt | 61 ++++++-- .../diagnostics/DefaultErrorMessagesJvm.java | 1 + .../resolve/jvm/diagnostics/ErrorsJvm.java | 1 + ...inerAndAnnotationAreBothApplied_1_5.fir.kt | 142 ++++++++++++++++++ ...ontainerAndAnnotationAreBothApplied_1_5.kt | 142 ++++++++++++++++++ ...ntainerAndAnnotationAreBothApplied_1_5.txt | 83 ++++++++++ ...inerAndAnnotationAreBothApplied_1_6.fir.kt | 142 ++++++++++++++++++ ...ontainerAndAnnotationAreBothApplied_1_6.kt | 142 ++++++++++++++++++ ...ntainerAndAnnotationAreBothApplied_1_6.txt | 83 ++++++++++ .../test/runners/DiagnosticTestGenerated.java | 12 ++ ...CompilerTestFE10TestdataTestGenerated.java | 12 ++ 13 files changed, 833 insertions(+), 12 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.fir.kt create mode 100644 compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.kt create mode 100644 compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.txt create mode 100644 compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.fir.kt create mode 100644 compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.kt create mode 100644 compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.txt diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index bb185908039..a9dbfb74bad 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -2094,6 +2094,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/annotations/repeatable"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @Test + @TestMetadata("containerAndAnnotationAreBothApplied_1_5.kt") + public void testContainerAndAnnotationAreBothApplied_1_5() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.kt"); + } + + @Test + @TestMetadata("containerAndAnnotationAreBothApplied_1_6.kt") + public void testContainerAndAnnotationAreBothApplied_1_6() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.kt"); + } + @Test @TestMetadata("javaRepeatableJvmTarget6.kt") public void testJavaRepeatableJvmTarget6() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index 74f2d8cab24..843711b224b 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -2094,6 +2094,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/annotations/repeatable"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @Test + @TestMetadata("containerAndAnnotationAreBothApplied_1_5.kt") + public void testContainerAndAnnotationAreBothApplied_1_5() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.kt"); + } + + @Test + @TestMetadata("containerAndAnnotationAreBothApplied_1_6.kt") + public void testContainerAndAnnotationAreBothApplied_1_6() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.kt"); + } + @Test @TestMetadata("javaRepeatableJvmTarget6.kt") public void testJavaRepeatableJvmTarget6() throws Exception { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/RepeatableAnnotationChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/RepeatableAnnotationChecker.kt index db2366244b4..2987f61c586 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/RepeatableAnnotationChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/RepeatableAnnotationChecker.kt @@ -9,14 +9,18 @@ import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.ClassDescriptor +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.load.java.JvmAnnotationNames import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtAnnotationEntry import org.jetbrains.kotlin.resolve.AdditionalAnnotationChecker import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.constants.KClassValue import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.descriptorUtil.getAnnotationRetention import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotatedWithKotlinRepeatable @@ -28,8 +32,6 @@ class RepeatableAnnotationChecker( private val jvmTarget: JvmTarget, private val platformAnnotationFeaturesSupport: JvmPlatformAnnotationFeaturesSupport, ) : AdditionalAnnotationChecker { - private val nonSourceDisallowed = !languageVersionSettings.supportsFeature(LanguageFeature.RepeatableAnnotations) - override fun checkEntries( entries: List, actualTargets: List, @@ -38,14 +40,24 @@ class RepeatableAnnotationChecker( ) { if (entries.isEmpty()) return + val annotations = entries.mapNotNull { entry -> + val descriptor = trace.get(BindingContext.ANNOTATION, entry) + val useSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget() + if (descriptor != null) { + ResolvedAnnotation(entry, descriptor, useSiteTarget) + } else null + } + + checkRepeatedEntries(annotations, trace) + } + + private fun checkRepeatedEntries(annotations: List, trace: BindingTrace) { val entryTypesWithAnnotations = hashMapOf>() - for (entry in entries) { - val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue + for ((entry, descriptor, useSiteTarget) in annotations) { val fqName = descriptor.fqName ?: continue val classDescriptor = descriptor.annotationClass ?: continue - val useSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget() val existingTargetsForAnnotation = entryTypesWithAnnotations.getOrPut(fqName) { arrayListOf() } val duplicateAnnotation = useSiteTarget in existingTargetsForAnnotation || (existingTargetsForAnnotation.any { (it == null) != (useSiteTarget == null) }) @@ -54,13 +66,21 @@ class RepeatableAnnotationChecker( && isRepeatableAnnotation(classDescriptor) && classDescriptor.getAnnotationRetention() != KotlinRetention.SOURCE ) { - val error = when { - jvmTarget == JvmTarget.JVM_1_6 -> ErrorsJvm.REPEATED_ANNOTATION_TARGET6 - nonSourceDisallowed -> ErrorsJvm.NON_SOURCE_REPEATED_ANNOTATION - else -> null - } - if (error != null) { - trace.report(error.on(entry)) + when { + jvmTarget == JvmTarget.JVM_1_6 -> { + trace.report(ErrorsJvm.REPEATED_ANNOTATION_TARGET6.on(entry)) + } + languageVersionSettings.supportsFeature(LanguageFeature.RepeatableAnnotations) -> { + // It's not allowed to have both a repeated annotation (applied more than once) and its container + // on the same element. See https://docs.oracle.com/javase/specs/jls/se16/html/jls-9.html#jls-9.7.5. + val explicitContainer = resolveContainerAnnotation(classDescriptor) + if (explicitContainer != null && annotations.any { it.descriptor.fqName == explicitContainer }) { + trace.report(ErrorsJvm.REPEATED_ANNOTATION_WITH_CONTAINER.on(entry, fqName, explicitContainer)) + } + } + else -> { + trace.report(ErrorsJvm.NON_SOURCE_REPEATED_ANNOTATION.on(entry)) + } } } @@ -70,4 +90,21 @@ class RepeatableAnnotationChecker( private fun isRepeatableAnnotation(classDescriptor: ClassDescriptor): Boolean = classDescriptor.isAnnotatedWithKotlinRepeatable() || platformAnnotationFeaturesSupport.isRepeatableAnnotationClass(classDescriptor) + + private data class ResolvedAnnotation( + val entry: KtAnnotationEntry, + val descriptor: AnnotationDescriptor, + val useSiteTarget: AnnotationUseSiteTarget?, + ) + + // For a repeatable annotation class, returns FQ name of the container annotation if it can be resolved in Kotlin. + // This only exists when the annotation class (whether declared in Java or Kotlin) is annotated with java.lang.annotation.Repeatable, + // in which case the container annotation is @j.l.a.Repeatable's only argument. + private fun resolveContainerAnnotation(annotationClass: ClassDescriptor): FqName? { + val javaRepeatable = annotationClass.annotations.findAnnotation(JvmAnnotationNames.REPEATABLE_ANNOTATION) ?: return null + val value = javaRepeatable.allValueArguments[Name.identifier("value")] as? KClassValue ?: return null + // Local annotations are supported neither in Java nor in Kotlin. + val normalClass = value.value as? KClassValue.Value.NormalClass ?: return null + return normalClass.classId.asSingleFqName() + } } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java index eac72d699a0..3d7ed0fc0e4 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java @@ -73,6 +73,7 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension { MAP.put(DEPRECATED_JAVA_ANNOTATION, "This annotation is deprecated in Kotlin. Use ''@{0}'' instead", TO_STRING); MAP.put(NON_SOURCE_REPEATED_ANNOTATION, "Repeatable annotations with non-SOURCE retention are only supported starting from Kotlin 1.6"); MAP.put(REPEATED_ANNOTATION_TARGET6, "Repeatable annotations with non-SOURCE retention are not supported with JVM target 1.6. Use -jvm-target 1.8"); + MAP.put(REPEATED_ANNOTATION_WITH_CONTAINER, "Repeated annotation ''@{0}'' cannot be used on a declaration which is annotated with its container annotation ''@{1}''", TO_STRING, TO_STRING); MAP.put(ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES, "Annotation ''@{0}'' is not applicable to the multi-file classes", TO_STRING); MAP.put(JVM_PACKAGE_NAME_CANNOT_BE_EMPTY, "''@JvmPackageName'' annotation value cannot be empty"); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java index c9966fe71ff..afddc9a9e66 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java @@ -71,6 +71,7 @@ public interface ErrorsJvm { DiagnosticFactory1 DEPRECATED_JAVA_ANNOTATION = DiagnosticFactory1.create(WARNING); DiagnosticFactory0 NON_SOURCE_REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 REPEATED_ANNOTATION_TARGET6 = DiagnosticFactory0.create(ERROR); + DiagnosticFactory2 REPEATED_ANNOTATION_WITH_CONTAINER = DiagnosticFactory2.create(ERROR); DiagnosticFactory1 ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 JVM_PACKAGE_NAME_CANNOT_BE_EMPTY = DiagnosticFactory0.create(ERROR); diff --git a/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.fir.kt b/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.fir.kt new file mode 100644 index 00000000000..23cbb75ceb2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.fir.kt @@ -0,0 +1,142 @@ +// !LANGUAGE: -RepeatableAnnotations +// FULL_JDK +// FILE: JR.java + +import java.lang.annotation.*; + +@Repeatable(JR.Container.class) +@Retention(RetentionPolicy.RUNTIME) +public @interface JR { + public @interface Container { + JR[] value(); + } +} + +// FILE: JS.java + +import java.lang.annotation.*; + +@Repeatable(JS.Container.class) +@Retention(RetentionPolicy.SOURCE) +public @interface JS { + public @interface Container { + JS[] value(); + } +} + +// FILE: KR.kt + +@java.lang.annotation.Repeatable(KR.Container::class) +@Retention(AnnotationRetention.RUNTIME) +annotation class KR { + annotation class Container(val value: Array) +} + +// FILE: KS.kt + +@java.lang.annotation.Repeatable(KS.Container::class) +@Retention(AnnotationRetention.SOURCE) +annotation class KS { + annotation class Container(val value: Array) +} + +// FILE: test.kt + +// Java runtime-retained annotation + +@JR +@JR.Container() +fun jr1() {} + +@JR +@JR.Container() +@JR +fun jr2() {} + +@JR +@JR.Container(JR()) +@JR +fun jr3() {} + +@JR +@JR.Container(JR()) +fun jr4() {} + +@JR +@JR.Container(JR(), JR()) +fun jr5() {} + + +// Java source-retained annotation + +@JS +@JS.Container() +fun js1() {} + +@JS +@JS.Container() +@JS +fun js2() {} + +@JS +@JS.Container(JS()) +@JS +fun js3() {} + +@JS +@JS.Container(JS()) +fun js4() {} + +@JS +@JS.Container(JS(), JS()) +fun js5() {} + + +// Kotlin runtime-retained annotation + +@KR.Container([]) +@KR +fun kr1() {} + +@KR.Container([]) +@KR +@KR +fun kr2() {} + +@KR +@KR +@KR.Container([KR()]) +fun kr3() {} + +@KR.Container([KR()]) +@KR +fun kr4() {} + +@KR +@KR.Container([KR(), KR()]) +fun kr5() {} + + +// Kotlin source-retained annotation + +@KS.Container([]) +@KS +fun ks1() {} + +@KS.Container([]) +@KS +@KS +fun ks2() {} + +@KS +@KS +@KS.Container([KS()]) +fun ks3() {} + +@KS.Container([KS()]) +@KS +fun ks4() {} + +@KS +@KS.Container([KS(), KS()]) +fun ks5() {} diff --git a/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.kt b/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.kt new file mode 100644 index 00000000000..5f014e769c0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.kt @@ -0,0 +1,142 @@ +// !LANGUAGE: -RepeatableAnnotations +// FULL_JDK +// FILE: JR.java + +import java.lang.annotation.*; + +@Repeatable(JR.Container.class) +@Retention(RetentionPolicy.RUNTIME) +public @interface JR { + public @interface Container { + JR[] value(); + } +} + +// FILE: JS.java + +import java.lang.annotation.*; + +@Repeatable(JS.Container.class) +@Retention(RetentionPolicy.SOURCE) +public @interface JS { + public @interface Container { + JS[] value(); + } +} + +// FILE: KR.kt + +@java.lang.annotation.Repeatable(KR.Container::class) +@Retention(AnnotationRetention.RUNTIME) +annotation class KR { + annotation class Container(val value: Array) +} + +// FILE: KS.kt + +@java.lang.annotation.Repeatable(KS.Container::class) +@Retention(AnnotationRetention.SOURCE) +annotation class KS { + annotation class Container(val value: Array) +} + +// FILE: test.kt + +// Java runtime-retained annotation + +@JR +@JR.Container() +fun jr1() {} + +@JR +@JR.Container() +@JR +fun jr2() {} + +@JR +@JR.Container(JR()) +@JR +fun jr3() {} + +@JR +@JR.Container(JR()) +fun jr4() {} + +@JR +@JR.Container(JR(), JR()) +fun jr5() {} + + +// Java source-retained annotation + +@JS +@JS.Container() +fun js1() {} + +@JS +@JS.Container() +@JS +fun js2() {} + +@JS +@JS.Container(JS()) +@JS +fun js3() {} + +@JS +@JS.Container(JS()) +fun js4() {} + +@JS +@JS.Container(JS(), JS()) +fun js5() {} + + +// Kotlin runtime-retained annotation + +@KR.Container([]) +@KR +fun kr1() {} + +@KR.Container([]) +@KR +@KR +fun kr2() {} + +@KR +@KR +@KR.Container([KR()]) +fun kr3() {} + +@KR.Container([KR()]) +@KR +fun kr4() {} + +@KR +@KR.Container([KR(), KR()]) +fun kr5() {} + + +// Kotlin source-retained annotation + +@KS.Container([]) +@KS +fun ks1() {} + +@KS.Container([]) +@KS +@KS +fun ks2() {} + +@KS +@KS +@KS.Container([KS()]) +fun ks3() {} + +@KS.Container([KS()]) +@KS +fun ks4() {} + +@KS +@KS.Container([KS(), KS()]) +fun ks5() {} diff --git a/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.txt b/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.txt new file mode 100644 index 00000000000..a74a1f3c22b --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.txt @@ -0,0 +1,83 @@ +package + +@JR @JR.Container(value = {}) public fun jr1(): kotlin.Unit +@JR @JR.Container(value = {}) @JR public fun jr2(): kotlin.Unit +@JR @JR.Container(value = {JR}) @JR public fun jr3(): kotlin.Unit +@JR @JR.Container(value = {JR}) public fun jr4(): kotlin.Unit +@JR @JR.Container(value = {JR, JR}) public fun jr5(): kotlin.Unit +@JS @JS.Container(value = {}) public fun js1(): kotlin.Unit +@JS @JS.Container(value = {}) @JS public fun js2(): kotlin.Unit +@JS @JS.Container(value = {JS}) @JS public fun js3(): kotlin.Unit +@JS @JS.Container(value = {JS}) public fun js4(): kotlin.Unit +@JS @JS.Container(value = {JS, JS}) public fun js5(): kotlin.Unit +@KR.Container(value = {}) @KR public fun kr1(): kotlin.Unit +@KR.Container(value = {}) @KR @KR public fun kr2(): kotlin.Unit +@KR @KR @KR.Container(value = {KR}) public fun kr3(): kotlin.Unit +@KR.Container(value = {KR}) @KR public fun kr4(): kotlin.Unit +@KR @KR.Container(value = {KR, KR}) public fun kr5(): kotlin.Unit +@KS.Container(value = {}) @KS public fun ks1(): kotlin.Unit +@KS.Container(value = {}) @KS @KS public fun ks2(): kotlin.Unit +@KS @KS @KS.Container(value = {KS}) public fun ks3(): kotlin.Unit +@KS.Container(value = {KS}) @KS public fun ks4(): kotlin.Unit +@KS @KS.Container(value = {KS, KS}) public fun ks5(): kotlin.Unit + +@java.lang.annotation.Repeatable(value = JR.Container::class) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class JR : kotlin.Annotation { + public constructor JR() + 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 annotation class Container : kotlin.Annotation { + public constructor Container(/*0*/ vararg value: JR /*kotlin.Array*/) + public final val value: kotlin.Array + 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 + } +} + +@java.lang.annotation.Repeatable(value = JS.Container::class) @kotlin.annotation.Retention(value = AnnotationRetention.SOURCE) public final annotation class JS : kotlin.Annotation { + public constructor JS() + 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 annotation class Container : kotlin.Annotation { + public constructor Container(/*0*/ vararg value: JS /*kotlin.Array*/) + public final val value: kotlin.Array + 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 + } +} + +@java.lang.annotation.Repeatable(value = KR.Container::class) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class KR : kotlin.Annotation { + public constructor KR() + 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 annotation class Container : kotlin.Annotation { + public constructor Container(/*0*/ value: kotlin.Array) + public final val value: kotlin.Array + 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 + } +} + +@java.lang.annotation.Repeatable(value = KS.Container::class) @kotlin.annotation.Retention(value = AnnotationRetention.SOURCE) public final annotation class KS : kotlin.Annotation { + public constructor KS() + 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 annotation class Container : kotlin.Annotation { + public constructor Container(/*0*/ value: kotlin.Array) + public final val value: kotlin.Array + 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 + } +} + diff --git a/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.fir.kt b/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.fir.kt new file mode 100644 index 00000000000..4b9baffadcb --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.fir.kt @@ -0,0 +1,142 @@ +// !LANGUAGE: +RepeatableAnnotations +// FULL_JDK +// FILE: JR.java + +import java.lang.annotation.*; + +@Repeatable(JR.Container.class) +@Retention(RetentionPolicy.RUNTIME) +public @interface JR { + public @interface Container { + JR[] value(); + } +} + +// FILE: JS.java + +import java.lang.annotation.*; + +@Repeatable(JS.Container.class) +@Retention(RetentionPolicy.SOURCE) +public @interface JS { + public @interface Container { + JS[] value(); + } +} + +// FILE: KR.kt + +@java.lang.annotation.Repeatable(KR.Container::class) +@Retention(AnnotationRetention.RUNTIME) +annotation class KR { + annotation class Container(val value: Array) +} + +// FILE: KS.kt + +@java.lang.annotation.Repeatable(KS.Container::class) +@Retention(AnnotationRetention.SOURCE) +annotation class KS { + annotation class Container(val value: Array) +} + +// FILE: test.kt + +// Java runtime-retained annotation + +@JR +@JR.Container() +fun jr1() {} + +@JR +@JR.Container() +@JR +fun jr2() {} + +@JR +@JR.Container(JR()) +@JR +fun jr3() {} + +@JR +@JR.Container(JR()) +fun jr4() {} + +@JR +@JR.Container(JR(), JR()) +fun jr5() {} + + +// Java source-retained annotation + +@JS +@JS.Container() +fun js1() {} + +@JS +@JS.Container() +@JS +fun js2() {} + +@JS +@JS.Container(JS()) +@JS +fun js3() {} + +@JS +@JS.Container(JS()) +fun js4() {} + +@JS +@JS.Container(JS(), JS()) +fun js5() {} + + +// Kotlin runtime-retained annotation + +@KR.Container([]) +@KR +fun kr1() {} + +@KR.Container([]) +@KR +@KR +fun kr2() {} + +@KR +@KR +@KR.Container([KR()]) +fun kr3() {} + +@KR.Container([KR()]) +@KR +fun kr4() {} + +@KR +@KR.Container([KR(), KR()]) +fun kr5() {} + + +// Kotlin source-retained annotation + +@KS.Container([]) +@KS +fun ks1() {} + +@KS.Container([]) +@KS +@KS +fun ks2() {} + +@KS +@KS +@KS.Container([KS()]) +fun ks3() {} + +@KS.Container([KS()]) +@KS +fun ks4() {} + +@KS +@KS.Container([KS(), KS()]) +fun ks5() {} diff --git a/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.kt b/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.kt new file mode 100644 index 00000000000..b06e8ecc584 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.kt @@ -0,0 +1,142 @@ +// !LANGUAGE: +RepeatableAnnotations +// FULL_JDK +// FILE: JR.java + +import java.lang.annotation.*; + +@Repeatable(JR.Container.class) +@Retention(RetentionPolicy.RUNTIME) +public @interface JR { + public @interface Container { + JR[] value(); + } +} + +// FILE: JS.java + +import java.lang.annotation.*; + +@Repeatable(JS.Container.class) +@Retention(RetentionPolicy.SOURCE) +public @interface JS { + public @interface Container { + JS[] value(); + } +} + +// FILE: KR.kt + +@java.lang.annotation.Repeatable(KR.Container::class) +@Retention(AnnotationRetention.RUNTIME) +annotation class KR { + annotation class Container(val value: Array) +} + +// FILE: KS.kt + +@java.lang.annotation.Repeatable(KS.Container::class) +@Retention(AnnotationRetention.SOURCE) +annotation class KS { + annotation class Container(val value: Array) +} + +// FILE: test.kt + +// Java runtime-retained annotation + +@JR +@JR.Container() +fun jr1() {} + +@JR +@JR.Container() +@JR +fun jr2() {} + +@JR +@JR.Container(JR()) +@JR +fun jr3() {} + +@JR +@JR.Container(JR()) +fun jr4() {} + +@JR +@JR.Container(JR(), JR()) +fun jr5() {} + + +// Java source-retained annotation + +@JS +@JS.Container() +fun js1() {} + +@JS +@JS.Container() +@JS +fun js2() {} + +@JS +@JS.Container(JS()) +@JS +fun js3() {} + +@JS +@JS.Container(JS()) +fun js4() {} + +@JS +@JS.Container(JS(), JS()) +fun js5() {} + + +// Kotlin runtime-retained annotation + +@KR.Container([]) +@KR +fun kr1() {} + +@KR.Container([]) +@KR +@KR +fun kr2() {} + +@KR +@KR +@KR.Container([KR()]) +fun kr3() {} + +@KR.Container([KR()]) +@KR +fun kr4() {} + +@KR +@KR.Container([KR(), KR()]) +fun kr5() {} + + +// Kotlin source-retained annotation + +@KS.Container([]) +@KS +fun ks1() {} + +@KS.Container([]) +@KS +@KS +fun ks2() {} + +@KS +@KS +@KS.Container([KS()]) +fun ks3() {} + +@KS.Container([KS()]) +@KS +fun ks4() {} + +@KS +@KS.Container([KS(), KS()]) +fun ks5() {} diff --git a/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.txt b/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.txt new file mode 100644 index 00000000000..a74a1f3c22b --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.txt @@ -0,0 +1,83 @@ +package + +@JR @JR.Container(value = {}) public fun jr1(): kotlin.Unit +@JR @JR.Container(value = {}) @JR public fun jr2(): kotlin.Unit +@JR @JR.Container(value = {JR}) @JR public fun jr3(): kotlin.Unit +@JR @JR.Container(value = {JR}) public fun jr4(): kotlin.Unit +@JR @JR.Container(value = {JR, JR}) public fun jr5(): kotlin.Unit +@JS @JS.Container(value = {}) public fun js1(): kotlin.Unit +@JS @JS.Container(value = {}) @JS public fun js2(): kotlin.Unit +@JS @JS.Container(value = {JS}) @JS public fun js3(): kotlin.Unit +@JS @JS.Container(value = {JS}) public fun js4(): kotlin.Unit +@JS @JS.Container(value = {JS, JS}) public fun js5(): kotlin.Unit +@KR.Container(value = {}) @KR public fun kr1(): kotlin.Unit +@KR.Container(value = {}) @KR @KR public fun kr2(): kotlin.Unit +@KR @KR @KR.Container(value = {KR}) public fun kr3(): kotlin.Unit +@KR.Container(value = {KR}) @KR public fun kr4(): kotlin.Unit +@KR @KR.Container(value = {KR, KR}) public fun kr5(): kotlin.Unit +@KS.Container(value = {}) @KS public fun ks1(): kotlin.Unit +@KS.Container(value = {}) @KS @KS public fun ks2(): kotlin.Unit +@KS @KS @KS.Container(value = {KS}) public fun ks3(): kotlin.Unit +@KS.Container(value = {KS}) @KS public fun ks4(): kotlin.Unit +@KS @KS.Container(value = {KS, KS}) public fun ks5(): kotlin.Unit + +@java.lang.annotation.Repeatable(value = JR.Container::class) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class JR : kotlin.Annotation { + public constructor JR() + 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 annotation class Container : kotlin.Annotation { + public constructor Container(/*0*/ vararg value: JR /*kotlin.Array*/) + public final val value: kotlin.Array + 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 + } +} + +@java.lang.annotation.Repeatable(value = JS.Container::class) @kotlin.annotation.Retention(value = AnnotationRetention.SOURCE) public final annotation class JS : kotlin.Annotation { + public constructor JS() + 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 annotation class Container : kotlin.Annotation { + public constructor Container(/*0*/ vararg value: JS /*kotlin.Array*/) + public final val value: kotlin.Array + 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 + } +} + +@java.lang.annotation.Repeatable(value = KR.Container::class) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class KR : kotlin.Annotation { + public constructor KR() + 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 annotation class Container : kotlin.Annotation { + public constructor Container(/*0*/ value: kotlin.Array) + public final val value: kotlin.Array + 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 + } +} + +@java.lang.annotation.Repeatable(value = KS.Container::class) @kotlin.annotation.Retention(value = AnnotationRetention.SOURCE) public final annotation class KS : kotlin.Annotation { + public constructor KS() + 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 annotation class Container : kotlin.Annotation { + public constructor Container(/*0*/ value: kotlin.Array) + public final val value: kotlin.Array + 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 + } +} + diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 499f0d433e4..272556ec631 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -2100,6 +2100,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/annotations/repeatable"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @Test + @TestMetadata("containerAndAnnotationAreBothApplied_1_5.kt") + public void testContainerAndAnnotationAreBothApplied_1_5() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.kt"); + } + + @Test + @TestMetadata("containerAndAnnotationAreBothApplied_1_6.kt") + public void testContainerAndAnnotationAreBothApplied_1_6() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.kt"); + } + @Test @TestMetadata("javaRepeatableJvmTarget6.kt") public void testJavaRepeatableJvmTarget6() throws Exception { diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index d89cbcbccdf..926f098500f 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -2094,6 +2094,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/annotations/repeatable"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @Test + @TestMetadata("containerAndAnnotationAreBothApplied_1_5.kt") + public void testContainerAndAnnotationAreBothApplied_1_5() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.kt"); + } + + @Test + @TestMetadata("containerAndAnnotationAreBothApplied_1_6.kt") + public void testContainerAndAnnotationAreBothApplied_1_6() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.kt"); + } + @Test @TestMetadata("javaRepeatableJvmTarget6.kt") public void testJavaRepeatableJvmTarget6() throws Exception {