diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByPsiForLibraryTestGenerated.java b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByPsiForLibraryTestGenerated.java index 49cc6e0778f..aad7a02f025 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByPsiForLibraryTestGenerated.java +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByPsiForLibraryTestGenerated.java @@ -24,6 +24,12 @@ public class SymbolLightClassesByPsiForLibraryTestGenerated extends AbstractSymb KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/asJava/lightClasses/lightClassByPsi"), Pattern.compile("^(.+)\\.(kt|kts)$"), null, true); } + @Test + @TestMetadata("allowedTargets.kt") + public void testAllowedTargets() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.kt"); + } + @Test @TestMetadata("annotationWithSetParamPropertyModifier.kt") public void testAnnotationWithSetParamPropertyModifier() throws Exception { diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesEqualityByPsiForLibraryTestGenerated.java b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesEqualityByPsiForLibraryTestGenerated.java index c645a349339..7e93c4c740c 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesEqualityByPsiForLibraryTestGenerated.java +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesEqualityByPsiForLibraryTestGenerated.java @@ -24,6 +24,12 @@ public class SymbolLightClassesEqualityByPsiForLibraryTestGenerated extends Abst KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/asJava/lightClasses/lightClassByPsi"), Pattern.compile("^(.+)\\.(kt|kts)$"), null, true); } + @Test + @TestMetadata("allowedTargets.kt") + public void testAllowedTargets() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.kt"); + } + @Test @TestMetadata("annotationWithSetParamPropertyModifier.kt") public void testAnnotationWithSetParamPropertyModifier() throws Exception { diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesParentingByPsiForLibraryTestGenerated.java b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesParentingByPsiForLibraryTestGenerated.java index ec257250a19..5b567ed4bf1 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesParentingByPsiForLibraryTestGenerated.java +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesParentingByPsiForLibraryTestGenerated.java @@ -24,6 +24,12 @@ public class SymbolLightClassesParentingByPsiForLibraryTestGenerated extends Abs KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/asJava/lightClasses/lightClassByPsi"), Pattern.compile("^(.+)\\.(kt|kts)$"), null, true); } + @Test + @TestMetadata("allowedTargets.kt") + public void testAllowedTargets() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.kt"); + } + @Test @TestMetadata("annotationWithSetParamPropertyModifier.kt") public void testAnnotationWithSetParamPropertyModifier() throws Exception { diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByPsiForSourceTestGenerated.java b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByPsiForSourceTestGenerated.java index 72d464753da..382fac00ec5 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByPsiForSourceTestGenerated.java +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByPsiForSourceTestGenerated.java @@ -24,6 +24,12 @@ public class SymbolLightClassesByPsiForSourceTestGenerated extends AbstractSymbo KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/asJava/lightClasses/lightClassByPsi"), Pattern.compile("^(.+)\\.(kt|kts)$"), null, true); } + @Test + @TestMetadata("allowedTargets.kt") + public void testAllowedTargets() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.kt"); + } + @Test @TestMetadata("annotationWithSetParamPropertyModifier.kt") public void testAnnotationWithSetParamPropertyModifier() throws Exception { diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesEqualityByPsiForSourceTestGenerated.java b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesEqualityByPsiForSourceTestGenerated.java index e20f7f1fd42..0d1ad13a320 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesEqualityByPsiForSourceTestGenerated.java +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesEqualityByPsiForSourceTestGenerated.java @@ -24,6 +24,12 @@ public class SymbolLightClassesEqualityByPsiForSourceTestGenerated extends Abstr KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/asJava/lightClasses/lightClassByPsi"), Pattern.compile("^(.+)\\.(kt|kts)$"), null, true); } + @Test + @TestMetadata("allowedTargets.kt") + public void testAllowedTargets() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.kt"); + } + @Test @TestMetadata("annotationWithSetParamPropertyModifier.kt") public void testAnnotationWithSetParamPropertyModifier() throws Exception { diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesParentingByPsiForSourceTestGenerated.java b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesParentingByPsiForSourceTestGenerated.java index f712597bd58..7703eb2dc6b 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesParentingByPsiForSourceTestGenerated.java +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesParentingByPsiForSourceTestGenerated.java @@ -24,6 +24,12 @@ public class SymbolLightClassesParentingByPsiForSourceTestGenerated extends Abst KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/asJava/lightClasses/lightClassByPsi"), Pattern.compile("^(.+)\\.(kt|kts)$"), null, true); } + @Test + @TestMetadata("allowedTargets.kt") + public void testAllowedTargets() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.kt"); + } + @Test @TestMetadata("annotationWithSetParamPropertyModifier.kt") public void testAnnotationWithSetParamPropertyModifier() throws Exception { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AnnotationGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AnnotationGenerator.kt index 59726bb95fe..2869484ffe3 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AnnotationGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AnnotationGenerator.kt @@ -62,10 +62,12 @@ class AnnotationGenerator(private val components: Fir2IrComponents) : Fir2IrComp val irProperty = irField.correspondingPropertySymbol?.owner ?: throw AssertionError("$irField is not a property field") val applicableTargets = if (irProperty.isDelegated) delegatedPropertyTargets else propertyTargets - irField.annotations += property.annotations.filter { - val target = it.target(applicableTargets) - target == AnnotationUseSiteTarget.FIELD || target == AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD - }.toIrAnnotations() + property.backingField?.let { + irField.annotations += it.annotations.filter { + val target = it.target(applicableTargets) + target == AnnotationUseSiteTarget.FIELD || target == AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD + }.toIrAnnotations() + } } fun generate(propertyAccessor: IrFunction, property: FirProperty) { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java index fe02f6370a1..4c620660b2e 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java @@ -41,6 +41,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("allowedTargets.kt") + public void testAllowedTargets() throws Exception { + runTest("compiler/testData/codegen/box/annotations/allowedTargets.kt"); + } + @Test @TestMetadata("annotatedAnnotationParameter.kt") public void testAnnotatedAnnotationParameter() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java index b6ee312d45a..f0be808df64 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java @@ -41,6 +41,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("allowedTargets.kt") + public void testAllowedTargets() throws Exception { + runTest("compiler/testData/codegen/box/annotations/allowedTargets.kt"); + } + @Test @TestMetadata("annotatedAnnotationParameter.kt") public void testAnnotatedAnnotationParameter() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt index e79098d7a52..b659a516591 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt @@ -147,7 +147,7 @@ open class FirTypeResolveTransformer( if (result.isPrimary) { for (valueParameter in result.valueParameters) { if (valueParameter.correspondingProperty != null) { - valueParameter.removeDuplicateAnnotationsOfPrimaryConstructorElement() + valueParameter.removeIrrelevantAnnotations() } } } @@ -219,7 +219,7 @@ open class FirTypeResolveTransformer( unboundCyclesInTypeParametersSupertypes(property) if (property.source?.kind == KtFakeSourceElementKind.PropertyFromParameter) { - property.removeDuplicateAnnotationsOfPrimaryConstructorElement() + property.removeIrrelevantAnnotations() } calculateDeprecations(property) @@ -480,28 +480,37 @@ open class FirTypeResolveTransformer( } /** - * In a scenario like - * + * Filters annotations by target. + * For example, in the following snippet the annotation may apply to the constructor value parameter, the property or the underlying field: * ``` - * annotation class Ann * class Foo(@Ann val x: String) * ``` - * - * both, the primary ctor value parameter and the property `x` will be annotated with `@Ann`. This is due to the fact, that the - * annotation needs to be resolved in order to determine its annotation targets. We remove annotations from the wrong target if they - * don't explicitly specify the use-site target (in which case they shouldn't have been added to the element in the raw FIR). - * - * For value parameters, we remove the annotation if the targets don't include [AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER]. - * For properties, we remove the annotation, if the targets include [AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER]. + * This ambiguity may be resolved by specifying the use-site explicitly, i.e. `@field:Ann` or by analysing the allowed targets from + * the [kotlin.annotation.Target] meta-annotation. In latter case, the method will assign a use-site target to the corresponding + * annotation. */ - private fun FirVariable.removeDuplicateAnnotationsOfPrimaryConstructorElement() { - val isParameter = this is FirValueParameter - replaceAnnotations(annotations.filter { - it.useSiteTarget != null || - // equivalent to - // CONSTRUCTOR_PARAMETER in targets && isParameter || - // CONSTRUCTOR_PARAMETER !in targets && !isParameter - AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER in it.useSiteTargetsFromMetaAnnotation(session) == isParameter + private fun FirVariable.removeIrrelevantAnnotations() { + replaceAnnotations(annotations.filter { annotation -> + when(annotation.useSiteTarget) { + null -> { + val allowedTargets = annotation.useSiteTargetsFromMetaAnnotation(session) + when { + this is FirValueParameter -> AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER in allowedTargets + this.source?.kind == KtFakeSourceElementKind.PropertyFromParameter && AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER in allowedTargets -> false + this is FirProperty && AnnotationUseSiteTarget.FIELD in allowedTargets && AnnotationUseSiteTarget.PROPERTY !in allowedTargets && backingField != null -> { + (this as? FirProperty)?.backingField?.replaceAnnotations(backingField!!.annotations + annotation) + false + } + else -> true + } + } + AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER -> this is FirValueParameter + AnnotationUseSiteTarget.FIELD -> { + (this as? FirProperty)?.backingField?.replaceAnnotations(backingField!!.annotations + annotation) + false + } + else -> true + } }) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt index 0606ee3e9d6..3ff4a0de721 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt @@ -1135,6 +1135,7 @@ class JvmSymbols( KotlinTarget.PROPERTY_GETTER to etMethod, KotlinTarget.PROPERTY_SETTER to etMethod, KotlinTarget.FIELD to buildEnumEntry(elementTypeEnum, "FIELD"), + KotlinTarget.BACKING_FIELD to buildEnumEntry(elementTypeEnum, "FIELD"), KotlinTarget.VALUE_PARAMETER to buildEnumEntry(elementTypeEnum, "PARAMETER") ) diff --git a/compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.fir.java b/compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.fir.java new file mode 100644 index 00000000000..2f69a8ad678 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.fir.java @@ -0,0 +1,80 @@ +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +public abstract @interface AnotherUniversalAnnotation /* AnotherUniversalAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.FIELD}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.FIELD}) +public abstract @interface FieldAnnotation /* FieldAnnotation*/ { +} + +public final class MyClass /* MyClass*/ { + @AnotherUniversalAnnotation() + private final int x5; + + @FieldAnnotation() + private final int x1; + + @UniversalAnnotation() + private final int x6; + + private final int x2; + + private final int x3; + + private final int x4; + + private final int x7; + + public MyClass(@AnotherUniversalAnnotation() @ParameterAnnotation() @UniversalAnnotation() int, int, @PropertyOrParameterAnnotation() int, @ParameterOrFieldAnnotation() int, int, @AnotherUniversalAnnotation() int, @UniversalAnnotation() int);// .ctor(int, int, int, int, int, int, int) + + public final int getX1();// getX1() + + public final int getX2();// getX2() + + public final int getX3();// getX3() + + public final int getX4();// getX4() + + public final int getX5();// getX5() + + public final int getX6();// getX6() + + public final int getX7();// getX7() +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) +public abstract @interface ParameterAnnotation /* ParameterAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) +public abstract @interface ParameterOrFieldAnnotation /* ParameterOrFieldAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.PROPERTY}) +public abstract @interface PropertyAnnotation /* PropertyAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.FIELD}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.FIELD}) +public abstract @interface PropertyOrFieldAnnotation /* PropertyOrFieldAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) +public abstract @interface PropertyOrParameterAnnotation /* PropertyOrParameterAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) +public abstract @interface UniversalAnnotation /* UniversalAnnotation*/ { +} diff --git a/compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.java b/compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.java new file mode 100644 index 00000000000..95244ad9e41 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.java @@ -0,0 +1,80 @@ +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +public abstract @interface AnotherUniversalAnnotation /* AnotherUniversalAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.FIELD}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.FIELD}) +public abstract @interface FieldAnnotation /* FieldAnnotation*/ { +} + +public final class MyClass /* MyClass*/ { + @AnotherUniversalAnnotation() + private final int x5; + + @FieldAnnotation() + private final int x1; + + @UniversalAnnotation() + private final int x6; + + private final int x2; + + private final int x3; + + private final int x4; + + private final int x7; + + public MyClass(@AnotherUniversalAnnotation() @FieldAnnotation() @ParameterAnnotation() @PropertyAnnotation() @UniversalAnnotation() int, @PropertyOrFieldAnnotation() int, @PropertyOrParameterAnnotation() int, @ParameterOrFieldAnnotation() int, int, @AnotherUniversalAnnotation() int, @UniversalAnnotation() int);// .ctor(int, int, int, int, int, int, int) + + public final int getX1();// getX1() + + public final int getX2();// getX2() + + public final int getX3();// getX3() + + public final int getX4();// getX4() + + public final int getX5();// getX5() + + public final int getX6();// getX6() + + public final int getX7();// getX7() +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) +public abstract @interface ParameterAnnotation /* ParameterAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) +public abstract @interface ParameterOrFieldAnnotation /* ParameterOrFieldAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.PROPERTY}) +public abstract @interface PropertyAnnotation /* PropertyAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.FIELD}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.FIELD}) +public abstract @interface PropertyOrFieldAnnotation /* PropertyOrFieldAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) +public abstract @interface PropertyOrParameterAnnotation /* PropertyOrParameterAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) +public abstract @interface UniversalAnnotation /* UniversalAnnotation*/ { +} diff --git a/compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.kt b/compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.kt new file mode 100644 index 00000000000..9c1081a1668 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.kt @@ -0,0 +1,33 @@ +@Target(AnnotationTarget.PROPERTY) +annotation class PropertyAnnotation + +@Target(AnnotationTarget.FIELD) +annotation class FieldAnnotation + +@Target(AnnotationTarget.VALUE_PARAMETER) +annotation class ParameterAnnotation + +@Target(AnnotationTarget.PROPERTY, AnnotationTarget.FIELD) +annotation class PropertyOrFieldAnnotation + +@Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER) +annotation class PropertyOrParameterAnnotation + +@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER) +annotation class ParameterOrFieldAnnotation + +@Target(AnnotationTarget.PROPERTY, AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER) +annotation class UniversalAnnotation + +annotation class AnotherUniversalAnnotation + + +class MyClass( + @PropertyAnnotation @FieldAnnotation @ParameterAnnotation @UniversalAnnotation @AnotherUniversalAnnotation val x1: Int, + @PropertyOrFieldAnnotation val x2: Int, + @PropertyOrParameterAnnotation val x3: Int, + @ParameterOrFieldAnnotation val x4: Int, + @property:UniversalAnnotation @field:AnotherUniversalAnnotation val x5: Int, + @field:UniversalAnnotation @param:AnotherUniversalAnnotation val x6: Int, + @param:UniversalAnnotation @property:AnotherUniversalAnnotation val x7: Int +) diff --git a/compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.lib.java b/compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.lib.java new file mode 100644 index 00000000000..2f69a8ad678 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/lightClassByPsi/allowedTargets.lib.java @@ -0,0 +1,80 @@ +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +public abstract @interface AnotherUniversalAnnotation /* AnotherUniversalAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.FIELD}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.FIELD}) +public abstract @interface FieldAnnotation /* FieldAnnotation*/ { +} + +public final class MyClass /* MyClass*/ { + @AnotherUniversalAnnotation() + private final int x5; + + @FieldAnnotation() + private final int x1; + + @UniversalAnnotation() + private final int x6; + + private final int x2; + + private final int x3; + + private final int x4; + + private final int x7; + + public MyClass(@AnotherUniversalAnnotation() @ParameterAnnotation() @UniversalAnnotation() int, int, @PropertyOrParameterAnnotation() int, @ParameterOrFieldAnnotation() int, int, @AnotherUniversalAnnotation() int, @UniversalAnnotation() int);// .ctor(int, int, int, int, int, int, int) + + public final int getX1();// getX1() + + public final int getX2();// getX2() + + public final int getX3();// getX3() + + public final int getX4();// getX4() + + public final int getX5();// getX5() + + public final int getX6();// getX6() + + public final int getX7();// getX7() +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) +public abstract @interface ParameterAnnotation /* ParameterAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) +public abstract @interface ParameterOrFieldAnnotation /* ParameterOrFieldAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.PROPERTY}) +public abstract @interface PropertyAnnotation /* PropertyAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.FIELD}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.FIELD}) +public abstract @interface PropertyOrFieldAnnotation /* PropertyOrFieldAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) +public abstract @interface PropertyOrParameterAnnotation /* PropertyOrParameterAnnotation*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) +public abstract @interface UniversalAnnotation /* UniversalAnnotation*/ { +} diff --git a/compiler/testData/codegen/box/annotations/allowedTargets.kt b/compiler/testData/codegen/box/annotations/allowedTargets.kt new file mode 100644 index 00000000000..1d0f81e35d5 --- /dev/null +++ b/compiler/testData/codegen/box/annotations/allowedTargets.kt @@ -0,0 +1,73 @@ +// WITH_STDLIB +// WITH_REFLECT +// TARGET_BACKEND: JVM_IR + +import kotlin.test.assertEquals +import kotlin.reflect.* +import kotlin.reflect.jvm.javaField + +@Target(AnnotationTarget.PROPERTY) +annotation class PropertyAnnotation + +@Target(AnnotationTarget.FIELD) +annotation class FieldAnnotation + +@Target(AnnotationTarget.VALUE_PARAMETER) +annotation class ParameterAnnotation + +@Target(AnnotationTarget.PROPERTY, AnnotationTarget.FIELD) +annotation class PropertyOrFieldAnnotation + +@Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER) +annotation class PropertyOrParameterAnnotation + +@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER) +annotation class ParameterOrFieldAnnotation + +@Target(AnnotationTarget.PROPERTY, AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER) +annotation class UniversalAnnotation + +annotation class AnotherUniversalAnnotation + + +class C( + @PropertyAnnotation @FieldAnnotation @ParameterAnnotation @UniversalAnnotation @AnotherUniversalAnnotation val x1: Int, + @PropertyOrFieldAnnotation val x2: Int, + @PropertyOrParameterAnnotation val x3: Int, + @ParameterOrFieldAnnotation val x4: Int, + @property:UniversalAnnotation @field:AnotherUniversalAnnotation val x5: Int, + @field:UniversalAnnotation @param:AnotherUniversalAnnotation val x6: Int, + @param:UniversalAnnotation @property:AnotherUniversalAnnotation val x7: Int +) + +fun box(): String { + val parameterAnnotations = C::class.constructors.single().parameters.map { it.name to it.annotations.map { it.annotationClass.simpleName ?: "" }.toSet() }.toMap() + assertEquals(setOf("ParameterAnnotation", "UniversalAnnotation", "AnotherUniversalAnnotation"), parameterAnnotations["x1"]) + assertEquals(setOf(), parameterAnnotations["x2"]) + assertEquals(setOf("PropertyOrParameterAnnotation"), parameterAnnotations["x3"]) + assertEquals(setOf("ParameterOrFieldAnnotation"), parameterAnnotations["x4"]) + assertEquals(setOf(), parameterAnnotations["x5"]) + assertEquals(setOf("AnotherUniversalAnnotation"), parameterAnnotations["x6"]) + assertEquals(setOf("UniversalAnnotation"), parameterAnnotations["x7"]) + + val properties = C::class.members.filterIsInstance>() + val propertyAnnotations = properties.map { it.name to it.annotations.map { it.annotationClass.simpleName ?: "" }.toSet() }.toMap() + assertEquals(setOf("PropertyAnnotation"), propertyAnnotations["x1"]) + assertEquals(setOf("PropertyOrFieldAnnotation"), propertyAnnotations["x2"]) + assertEquals(setOf(), propertyAnnotations["x3"]) + assertEquals(setOf(), propertyAnnotations["x4"]) + assertEquals(setOf("UniversalAnnotation"), propertyAnnotations["x5"]) + assertEquals(setOf(), propertyAnnotations["x6"]) + assertEquals(setOf("AnotherUniversalAnnotation"), propertyAnnotations["x7"]) + + val fieldAnnotations = properties.map { it.javaField!! }.map { it.name to it.declaredAnnotations.map { it.annotationClass.simpleName ?: "" }.toSet() }.toMap() + assertEquals(setOf("FieldAnnotation"), fieldAnnotations["x1"]) + assertEquals(setOf(), fieldAnnotations["x2"]) + assertEquals(setOf(), fieldAnnotations["x3"]) + assertEquals(setOf(), fieldAnnotations["x4"]) + assertEquals(setOf("AnotherUniversalAnnotation"), fieldAnnotations["x5"]) + assertEquals(setOf("UniversalAnnotation"), fieldAnnotations["x6"]) + assertEquals(setOf(), fieldAnnotations["x7"]) + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 308606b9f3c..49b369b64a6 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -41,6 +41,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("allowedTargets.kt") + public void testAllowedTargets() throws Exception { + runTest("compiler/testData/codegen/box/annotations/allowedTargets.kt"); + } + @Test @TestMetadata("annotatedAnnotationParameter.kt") public void testAnnotatedAnnotationParameter() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java index 8d9debbbaaa..78b6e9bfd53 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java @@ -41,6 +41,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("allowedTargets.kt") + public void testAllowedTargets() throws Exception { + runTest("compiler/testData/codegen/box/annotations/allowedTargets.kt"); + } + @Test @TestMetadata("annotatedAnnotationParameter.kt") public void testAnnotatedAnnotationParameter() throws Exception { diff --git a/core/compiler.common/src/org/jetbrains/kotlin/resolve/AnnotationTargetLists.kt b/core/compiler.common/src/org/jetbrains/kotlin/resolve/AnnotationTargetLists.kt index 066f472c1a4..fb119c0d744 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/resolve/AnnotationTargetLists.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/resolve/AnnotationTargetLists.kt @@ -54,7 +54,9 @@ object AnnotationTargetLists { val T_PROPERTY_GETTER = targetList(PROPERTY_GETTER) val T_PROPERTY_SETTER = targetList(PROPERTY_SETTER) - val T_BACKING_FIELD = targetList(BACKING_FIELD) + val T_BACKING_FIELD = targetList(BACKING_FIELD) { + extraTargets(FIELD) + } val T_VALUE_PARAMETER_WITHOUT_VAL = targetList(VALUE_PARAMETER)