diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java index 9b2bb98e002..8a2bb9ee0ac 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java @@ -18,7 +18,6 @@ package org.jetbrains.kotlin.codegen; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.*; @@ -27,6 +26,7 @@ import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.resolve.AnnotationChecker; import org.jetbrains.kotlin.resolve.constants.*; import org.jetbrains.kotlin.resolve.constants.StringValue; +import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage; import org.jetbrains.kotlin.types.Flexibility; import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.TypeUtils; @@ -407,20 +407,9 @@ public abstract class AnnotationCodegen { @NotNull private RetentionPolicy getRetentionPolicy(@NotNull Annotated descriptor) { - AnnotationDescriptor kotlinAnnotation = descriptor.getAnnotations().findAnnotation(KotlinBuiltIns.FQ_NAMES.annotation); - if (kotlinAnnotation != null) { - for (Map.Entry> argument : kotlinAnnotation.getAllValueArguments().entrySet()) { - if ("retention".equals(argument.getKey().getName().asString()) && argument.getValue() instanceof EnumValue) { - ClassDescriptor enumEntry = ((EnumValue) argument.getValue()).getValue(); - JetType classObjectType = getClassObjectType(enumEntry); - if (classObjectType != null) { - if ("kotlin/annotation/AnnotationRetention".equals(typeMapper.mapType(classObjectType).getInternalName())) { - KotlinRetention retention = KotlinRetention.valueOf(enumEntry.getName().asString()); - return annotationRetentionMap.get(retention); - } - } - } - } + KotlinRetention retention = DescriptorUtilPackage.getAnnotationRetention(descriptor); + if (retention != null) { + return annotationRetentionMap.get(retention); } AnnotationDescriptor retentionAnnotation = descriptor.getAnnotations().findAnnotation(new FqName(Retention.class.getName())); if (retentionAnnotation != null) { 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 0d6b71ad984..f17607a5745 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 @@ -58,6 +58,7 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension { MAP.put(ErrorsJvm.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION, "Only named arguments are available for Java annotations"); MAP.put(ErrorsJvm.DEPRECATED_ANNOTATION_METHOD_CALL, "Annotation methods are deprecated. Use property instead"); MAP.put(ErrorsJvm.DEPRECATED_JAVA_ANNOTATION, "This annotation is deprecated in Kotlin. Use ''{0}'' instead", Renderers.TO_STRING); + MAP.put(ErrorsJvm.NON_SOURCE_REPEATED_ANNOTATION, "Only annotations with SOURCE retention can be repeated on JVM platform"); MAP.put(ErrorsJvm.NO_REFLECTION_IN_CLASS_PATH, "Call uses reflection API which is not found in compilation classpath. " + "Make sure you have kotlin-reflect.jar in the classpath"); 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 b115719a5de..657653fa365 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 @@ -56,6 +56,7 @@ public interface ErrorsJvm { DiagnosticFactory0 POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 DEPRECATED_ANNOTATION_METHOD_CALL = DiagnosticFactory0.create(WARNING); DiagnosticFactory1 DEPRECATED_JAVA_ANNOTATION = DiagnosticFactory1.create(WARNING); + DiagnosticFactory0 NON_SOURCE_REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 TRAIT_CANT_CALL_DEFAULT_METHOD_VIA_SUPER = DiagnosticFactory0.create(ERROR); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt index 4805ee105ec..0750e6b2a45 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt @@ -20,6 +20,8 @@ import org.jetbrains.kotlin.cfg.WhenChecker import org.jetbrains.kotlin.container.StorageComponentContainer import org.jetbrains.kotlin.container.useImpl import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention +import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.jvm.RuntimeAssertionsTypeChecker @@ -43,6 +45,8 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability +import org.jetbrains.kotlin.resolve.descriptorUtil.getAnnotationRetention +import org.jetbrains.kotlin.resolve.descriptorUtil.isRepeatableAnnotation import org.jetbrains.kotlin.resolve.jvm.calls.checkers.NeedSyntheticChecker import org.jetbrains.kotlin.resolve.jvm.calls.checkers.ReflectionAPICallChecker import org.jetbrains.kotlin.resolve.jvm.calls.checkers.TraitDefaultMethodCallChecker @@ -75,7 +79,10 @@ public object JvmPlatformConfigurator : PlatformConfigurator( JavaNullabilityWarningsChecker(), RuntimeAssertionsTypeChecker ), - additionalSymbolUsageValidators = listOf() + + additionalSymbolUsageValidators = listOf(), + + additionalAnnotationChecker = RepeatableAnnotationChecker ) { override fun configure(container: StorageComponentContainer) { @@ -85,6 +92,21 @@ public object JvmPlatformConfigurator : PlatformConfigurator( } } +public object RepeatableAnnotationChecker: AdditionalAnnotationChecker { + override fun checkEntries(entries: List, actualTargets: List, trace: BindingTrace) { + val entryTypes: MutableSet = hashSetOf() + for (entry in entries) { + val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue + val classDescriptor = TypeUtils.getClassDescriptor(descriptor.type) ?: continue + if (!entryTypes.add(descriptor.type) + && classDescriptor.isRepeatableAnnotation() + && classDescriptor.getAnnotationRetention() != KotlinRetention.SOURCE) { + trace.report(ErrorsJvm.NON_SOURCE_REPEATED_ANNOTATION.on(entry)); + } + } + } +} + public class LocalFunInlineChecker : DeclarationChecker { override fun check( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt index 3ebbbec7715..77da1680d57 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt @@ -27,10 +27,12 @@ import org.jetbrains.kotlin.resolve.constants.EnumValue import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget -import org.jetbrains.kotlin.resolve.constants.BooleanValue +import org.jetbrains.kotlin.resolve.descriptorUtil.isRepeatableAnnotation public object AnnotationChecker { + public var additionalChecker: AdditionalAnnotationChecker? = null + public fun check(annotated: JetAnnotated, trace: BindingTrace, descriptor: ClassDescriptor? = null) { if (annotated is JetTypeParameter) return // TODO: support type parameter annotations val actualTargets = getActualTargetList(annotated, descriptor) @@ -64,24 +66,17 @@ public object AnnotationChecker { } } - private fun isRepeatable(classDescriptor: ClassDescriptor): Boolean { - val annotationEntryDescriptor = classDescriptor.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.annotation) ?: return false - val repeatableArgumentValue = annotationEntryDescriptor.allValueArguments.entrySet().firstOrNull { - "repeatable" == it.key.name.asString() - }?.getValue() as? BooleanValue ?: return false - return repeatableArgumentValue.value - } - private fun checkEntries(entries: List, actualTargets: List, trace: BindingTrace) { val entryTypes: MutableSet = hashSetOf() 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) && !isRepeatable(classDescriptor)) { + if (!entryTypes.add(descriptor.type) && !classDescriptor.isRepeatableAnnotation()) { trace.report(Errors.REPEATED_ANNOTATION.on(entry)); } } + additionalChecker?.checkEntries(entries, actualTargets, trace) } public fun possibleTargetSet(classDescriptor: ClassDescriptor): Set? { @@ -135,4 +130,8 @@ public object AnnotationChecker { if (annotated is JetTypeParameter) return listOf(KotlinTarget.TYPE_PARAMETER) return listOf() } +} + +public interface AdditionalAnnotationChecker { + public fun checkEntries(entries: List, actualTargets: List, trace: BindingTrace) } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index 28e92beca8b..5f648f6604d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -48,7 +48,8 @@ public open class PlatformConfigurator( additionalDeclarationCheckers: List, additionalCallCheckers: List, additionalTypeCheckers: List, - additionalSymbolUsageValidators: List + additionalSymbolUsageValidators: List, + private val additionalAnnotationChecker: AdditionalAnnotationChecker? = null ) { private val declarationCheckers: List = DEFAULT_DECLARATION_CHECKERS + additionalDeclarationCheckers @@ -64,5 +65,6 @@ public open class PlatformConfigurator( typeCheckers.forEach { useInstance(it) } useInstance(symbolUsageValidator) } + AnnotationChecker.additionalChecker = additionalAnnotationChecker } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/annotations/annotationsOnLambdaAsCallArgument.kt b/compiler/testData/diagnostics/tests/annotations/annotationsOnLambdaAsCallArgument.kt index 11ff6202e1c..97a73fa058d 100644 --- a/compiler/testData/diagnostics/tests/annotations/annotationsOnLambdaAsCallArgument.kt +++ b/compiler/testData/diagnostics/tests/annotations/annotationsOnLambdaAsCallArgument.kt @@ -1,5 +1,5 @@ target(AnnotationTarget.EXPRESSION) -annotation(repeatable = true) class Ann(val x: Int = 1) +annotation(repeatable = true, retention = AnnotationRetention.SOURCE) class Ann(val x: Int = 1) inline fun bar(block: () -> Int): Int = block() diff --git a/compiler/testData/diagnostics/tests/annotations/annotationsOnLambdaAsCallArgument.txt b/compiler/testData/diagnostics/tests/annotations/annotationsOnLambdaAsCallArgument.txt index 98a9c0f6da4..11d1f4a3584 100644 --- a/compiler/testData/diagnostics/tests/annotations/annotationsOnLambdaAsCallArgument.txt +++ b/compiler/testData/diagnostics/tests/annotations/annotationsOnLambdaAsCallArgument.txt @@ -3,7 +3,7 @@ package kotlin.inline() internal fun bar(/*0*/ block: () -> kotlin.Int): kotlin.Int internal fun foo(): kotlin.Unit -kotlin.annotation.target(allowedTargets = {AnnotationTarget.EXPRESSION}) kotlin.annotation.annotation(repeatable = true) internal final class Ann : kotlin.Annotation { +kotlin.annotation.target(allowedTargets = {AnnotationTarget.EXPRESSION}) kotlin.annotation.annotation(repeatable = true, retention = AnnotationRetention.SOURCE) internal final class Ann : kotlin.Annotation { public constructor Ann(/*0*/ x: kotlin.Int = ...) internal final val x: kotlin.Int public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean diff --git a/compiler/testData/diagnostics/tests/annotations/atAnnotationResolve.kt b/compiler/testData/diagnostics/tests/annotations/atAnnotationResolve.kt index 2443d32f32a..05d5e8e06bd 100644 --- a/compiler/testData/diagnostics/tests/annotations/atAnnotationResolve.kt +++ b/compiler/testData/diagnostics/tests/annotations/atAnnotationResolve.kt @@ -2,7 +2,7 @@ target(AnnotationTarget.TYPE, AnnotationTarget.CLASSIFIER, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION, AnnotationTarget.EXPRESSION, AnnotationTarget.PROPERTY) -annotation(repeatable = true) class Ann(val x: Int = 6) +annotation(repeatable = true, retention = AnnotationRetention.SOURCE) class Ann(val x: Int = 6) @Ann(1) @Ann(2) @Ann(3) @private class A @Ann constructor() { @Ann(x = 5) fun foo() { diff --git a/compiler/testData/diagnostics/tests/annotations/atAnnotationResolve.txt b/compiler/testData/diagnostics/tests/annotations/atAnnotationResolve.txt index 8304ffac487..6f36da78368 100644 --- a/compiler/testData/diagnostics/tests/annotations/atAnnotationResolve.txt +++ b/compiler/testData/diagnostics/tests/annotations/atAnnotationResolve.txt @@ -10,7 +10,7 @@ Ann(x = 1) Ann(x = 2) Ann(x = 3) private final class A { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } -kotlin.annotation.target(allowedTargets = {AnnotationTarget.TYPE, AnnotationTarget.CLASSIFIER, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION, AnnotationTarget.EXPRESSION, AnnotationTarget.PROPERTY}) kotlin.annotation.annotation(repeatable = true) internal final class Ann : kotlin.Annotation { +kotlin.annotation.target(allowedTargets = {AnnotationTarget.TYPE, AnnotationTarget.CLASSIFIER, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION, AnnotationTarget.EXPRESSION, AnnotationTarget.PROPERTY}) kotlin.annotation.annotation(repeatable = true, retention = AnnotationRetention.SOURCE) internal final class Ann : kotlin.Annotation { public constructor Ann(/*0*/ x: kotlin.Int = ...) internal final val x: kotlin.Int public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean diff --git a/compiler/testData/diagnostics/tests/annotations/options/repeatable.kt b/compiler/testData/diagnostics/tests/annotations/options/repeatable.kt index 2c327f3dbcd..2a810fa49f5 100644 --- a/compiler/testData/diagnostics/tests/annotations/options/repeatable.kt +++ b/compiler/testData/diagnostics/tests/annotations/options/repeatable.kt @@ -4,14 +4,18 @@ annotation(retention = AnnotationRetention.SOURCE, repeatable = true) class repa annotation(repeatable = true, retention = AnnotationRetention.SOURCE) class repann2(val f: Boolean) +annotation(repeatable = true, retention = AnnotationRetention.BINARY) class binrepann + target(AnnotationTarget.EXPRESSION) annotation(repeatable = true) class repexpr -repann repann class DoubleAnnotated +repann repann class DoubleAnnotated repann1(1) repann1(2) repann1(3) class TripleAnnotated repann2(true) repann2(false) repann2(false) repann2(true) class FourTimesAnnotated -@repann @repann fun foo(@repann @repann x: Int): Int { - @repexpr @repexpr return x +binrepann binrepann class BinaryAnnotated + +@repann @repann fun foo(@repann @repann x: Int): Int { + @repexpr @repexpr return x } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/annotations/options/repeatable.txt b/compiler/testData/diagnostics/tests/annotations/options/repeatable.txt index 55fbbdfa675..99133ef03b1 100644 --- a/compiler/testData/diagnostics/tests/annotations/options/repeatable.txt +++ b/compiler/testData/diagnostics/tests/annotations/options/repeatable.txt @@ -2,6 +2,13 @@ package repann() repann() internal fun foo(/*0*/ repann() repann() x: kotlin.Int): kotlin.Int +binrepann() binrepann() internal final class BinaryAnnotated { + public constructor BinaryAnnotated() + 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 +} + repann() repann() internal final class DoubleAnnotated { public constructor DoubleAnnotated() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean @@ -23,6 +30,13 @@ repann1(x = 1) repann1(x = 2) repann1(x = 3) internal final class TripleAnnotate public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } +kotlin.annotation.annotation(repeatable = true, retention = AnnotationRetention.BINARY) internal final class binrepann : kotlin.Annotation { + public constructor binrepann() + 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 repann : kotlin.Annotation { public constructor repann() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean diff --git a/compiler/testData/diagnostics/tests/resolve/resolveAnnotatedLambdaArgument.kt b/compiler/testData/diagnostics/tests/resolve/resolveAnnotatedLambdaArgument.kt index 78a2967dd2d..ffe432f687d 100644 --- a/compiler/testData/diagnostics/tests/resolve/resolveAnnotatedLambdaArgument.kt +++ b/compiler/testData/diagnostics/tests/resolve/resolveAnnotatedLambdaArgument.kt @@ -1,6 +1,6 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER target(AnnotationTarget.EXPRESSION) -annotation(repeatable = true) class Ann +annotation(repeatable = true, retention = AnnotationRetention.SOURCE) class Ann fun bar(block: (T) -> Int) {} diff --git a/compiler/testData/diagnostics/tests/resolve/resolveAnnotatedLambdaArgument.txt b/compiler/testData/diagnostics/tests/resolve/resolveAnnotatedLambdaArgument.txt index ee455a37a64..1f6f151de58 100644 --- a/compiler/testData/diagnostics/tests/resolve/resolveAnnotatedLambdaArgument.txt +++ b/compiler/testData/diagnostics/tests/resolve/resolveAnnotatedLambdaArgument.txt @@ -3,7 +3,7 @@ package internal fun bar(/*0*/ block: (T) -> kotlin.Int): kotlin.Unit internal fun foo(): kotlin.Unit -kotlin.annotation.target(allowedTargets = {AnnotationTarget.EXPRESSION}) kotlin.annotation.annotation(repeatable = true) internal final class Ann : kotlin.Annotation { +kotlin.annotation.target(allowedTargets = {AnnotationTarget.EXPRESSION}) kotlin.annotation.annotation(repeatable = true, retention = AnnotationRetention.SOURCE) 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 diff --git a/compiler/testData/diagnostics/testsWithJava8/annotations/javaRepeatable.kt b/compiler/testData/diagnostics/testsWithJava8/annotations/javaRepeatable.kt index c04418c4718..582afe16827 100644 --- a/compiler/testData/diagnostics/testsWithJava8/annotations/javaRepeatable.kt +++ b/compiler/testData/diagnostics/testsWithJava8/annotations/javaRepeatable.kt @@ -15,5 +15,6 @@ public @interface RepeatableAnnotations { // FILE: RepeatableUse.kt -RepeatableAnnotation RepeatableAnnotation class My +// Error should be gone when Java 8 Target will be available +RepeatableAnnotation RepeatableAnnotation class My diff --git a/compiler/testData/diagnostics/testsWithJava8/annotations/javaRepeatableRetention.kt b/compiler/testData/diagnostics/testsWithJava8/annotations/javaRepeatableRetention.kt index 7659bc7a112..ea372b00ced 100644 --- a/compiler/testData/diagnostics/testsWithJava8/annotations/javaRepeatableRetention.kt +++ b/compiler/testData/diagnostics/testsWithJava8/annotations/javaRepeatableRetention.kt @@ -16,6 +16,7 @@ public @interface RepeatableAnnotations { // FILE: RepeatableUse.kt -RepeatableAnnotation RepeatableAnnotation class My +// Error should be gone when Java 8 Target will be available +RepeatableAnnotation RepeatableAnnotation class My diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/array.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/array.kt index 8706a9da0dd..93de3014354 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/array.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/array.kt @@ -1,4 +1,4 @@ -annotation(repeatable = true) class Ann(val i: IntArray) +annotation(repeatable = true, retention = AnnotationRetention.SOURCE) class Ann(val i: IntArray) Ann(intArrayOf(i)) Ann(intArrayOf(i2)) @@ -13,7 +13,7 @@ val i3 = foo() fun foo(): Int = 1 -annotation(repeatable = true) class AnnAnn(val i: Array) +annotation(repeatable = true, retention = AnnotationRetention.SOURCE) class AnnAnn(val i: Array) AnnAnn(arrayOf(Ann(intArrayOf(1)))) AnnAnn(arrayOf(iAnn)) class TestAnn diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/array.txt b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/array.txt index b45cf14aca8..4350a8870fa 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/array.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/array.txt @@ -6,7 +6,7 @@ internal val i3: kotlin.Int internal val iAnn: Ann internal fun foo(): kotlin.Int -kotlin.annotation.annotation(repeatable = true) internal final class Ann : kotlin.Annotation { +kotlin.annotation.annotation(repeatable = true, retention = AnnotationRetention.SOURCE) internal final class Ann : kotlin.Annotation { public constructor Ann(/*0*/ i: kotlin.IntArray) internal final val i: kotlin.IntArray public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean @@ -14,7 +14,7 @@ kotlin.annotation.annotation(repeatable = true) internal final class Ann : kotli public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } -kotlin.annotation.annotation(repeatable = true) internal final class AnnAnn : kotlin.Annotation { +kotlin.annotation.annotation(repeatable = true, retention = AnnotationRetention.SOURCE) internal final class AnnAnn : kotlin.Annotation { public constructor AnnAnn(/*0*/ i: kotlin.Array) internal final val i: kotlin.Array public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/simple.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/simple.kt index f2ebffa977c..3f76190ce7a 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/simple.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/simple.kt @@ -1,4 +1,4 @@ -annotation(repeatable = true) class Ann(val i: Int) +annotation(repeatable = true, retention = AnnotationRetention.SOURCE) class Ann(val i: Int) annotation class AnnIA(val ia: IntArray) annotation class AnnSA(val sa: Array) diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/simple.txt b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/simple.txt index 70682abd8df..c5ba3c47812 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/simple.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/simple.txt @@ -6,7 +6,7 @@ internal val ia: kotlin.IntArray internal val sa: kotlin.Array internal fun foo(): kotlin.Int -kotlin.annotation.annotation(repeatable = true) internal final class Ann : kotlin.Annotation { +kotlin.annotation.annotation(repeatable = true, retention = AnnotationRetention.SOURCE) internal final class Ann : kotlin.Annotation { public constructor Ann(/*0*/ i: kotlin.Int) internal final val i: kotlin.Int public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/vararg.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/vararg.kt index c7b7d2f9185..1c1510307b2 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/vararg.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/vararg.kt @@ -1,4 +1,4 @@ -annotation(repeatable = true) class Ann(vararg val i: Int) +annotation(repeatable = true, retention = AnnotationRetention.SOURCE) class Ann(vararg val i: Int) Ann(i) Ann(i2) @@ -16,7 +16,7 @@ val i3 = foo() fun foo(): Int = 1 -annotation(repeatable = true) class AnnAnn(vararg val i: Ann) +annotation(repeatable = true, retention = AnnotationRetention.SOURCE) class AnnAnn(vararg val i: Ann) AnnAnn(*arrayOf(Ann(1))) AnnAnn(*arrayOf(iAnn)) class TestAnn diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/vararg.txt b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/vararg.txt index 128bec460d6..71e4bd9f2f0 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/vararg.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/vararg.txt @@ -6,7 +6,7 @@ internal val i3: kotlin.Int internal val iAnn: Ann internal fun foo(): kotlin.Int -kotlin.annotation.annotation(repeatable = true) internal final class Ann : kotlin.Annotation { +kotlin.annotation.annotation(repeatable = true, retention = AnnotationRetention.SOURCE) internal final class Ann : kotlin.Annotation { public constructor Ann(/*0*/ vararg i: kotlin.Int /*kotlin.IntArray*/) internal final val i: kotlin.IntArray public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean @@ -14,7 +14,7 @@ kotlin.annotation.annotation(repeatable = true) internal final class Ann : kotli public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } -kotlin.annotation.annotation(repeatable = true) internal final class AnnAnn : kotlin.Annotation { +kotlin.annotation.annotation(repeatable = true, retention = AnnotationRetention.SOURCE) internal final class AnnAnn : kotlin.Annotation { public constructor AnnAnn(/*0*/ vararg i: Ann /*kotlin.Array*/) internal final val i: kotlin.Array public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt index 16b0ea4d432..1de7299c12f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt @@ -21,10 +21,14 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.ClassKind.ENUM_CLASS import org.jetbrains.kotlin.descriptors.ClassKind.ENUM_ENTRY import org.jetbrains.kotlin.descriptors.ClassKind.OBJECT +import org.jetbrains.kotlin.descriptors.annotations.Annotated +import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.constants.BooleanValue +import org.jetbrains.kotlin.resolve.constants.EnumValue import org.jetbrains.kotlin.types.JetType public fun ClassDescriptor.getClassObjectReferenceTarget(): ClassDescriptor = getCompanionObjectDescriptor() ?: this @@ -140,3 +144,19 @@ public fun CallableDescriptor.getOwnerForEffectiveDispatchReceiverParameter(): D } return getDispatchReceiverParameter()?.getContainingDeclaration() } + +public fun Annotated.isRepeatableAnnotation(): Boolean { + val annotationEntryDescriptor = annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.annotation) ?: return false + val repeatableArgumentValue = annotationEntryDescriptor.allValueArguments.entrySet().firstOrNull { + "repeatable" == it.key.name.asString() + }?.getValue() as? BooleanValue ?: return false // not repeatable by default + return repeatableArgumentValue.value +} + +public fun Annotated.getAnnotationRetention(): KotlinRetention? { + val annotationEntryDescriptor = annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.annotation) ?: return null + val retentionArgumentValue = annotationEntryDescriptor.allValueArguments.entrySet().firstOrNull { + "retention" == it.key.name.asString() + }?.getValue() as? EnumValue ?: return null + return KotlinRetention.valueOf(retentionArgumentValue.value.name.asString()) +} diff --git a/idea/testData/checker/AnnotationOnFile.kt b/idea/testData/checker/AnnotationOnFile.kt index 3aa74e65ad2..8e852772ad1 100644 --- a/idea/testData/checker/AnnotationOnFile.kt +++ b/idea/testData/checker/AnnotationOnFile.kt @@ -20,4 +20,4 @@ val BAZ = "baz" val N = 0 target(AnnotationTarget.FILE) -annotation(repeatable = true) class myAnnotation(val i: Int, val s: String) +annotation(repeatable = true, retention = AnnotationRetention.SOURCE) class myAnnotation(val i: Int, val s: String) diff --git a/idea/testData/decompiler/stubBuilder/Annotations/Annotations.kt b/idea/testData/decompiler/stubBuilder/Annotations/Annotations.kt index b351531a8da..d1043f32080 100644 --- a/idea/testData/decompiler/stubBuilder/Annotations/Annotations.kt +++ b/idea/testData/decompiler/stubBuilder/Annotations/Annotations.kt @@ -32,6 +32,6 @@ annotation class a target(AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.CLASSIFIER, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.TYPE) -annotation(repeatable = true) class b(val e: E) +annotation(repeatable = true, retention = AnnotationRetention.SOURCE) class b(val e: E) enum class E { E1 E2 } \ No newline at end of file diff --git a/idea/testData/decompiler/stubBuilder/Annotations/Annotations.txt b/idea/testData/decompiler/stubBuilder/Annotations/Annotations.txt index 6b4276b48be..fe3bec4fbe2 100644 --- a/idea/testData/decompiler/stubBuilder/Annotations/Annotations.txt +++ b/idea/testData/decompiler/stubBuilder/Annotations/Annotations.txt @@ -44,19 +44,9 @@ PsiJetFileStubImpl[package=] CLASS_BODY: OBJECT_DECLARATION:[fqName=Annotations.Companion, isCompanion=true, isLocal=false, isObjectLiteral=false, isTopLevel=false, name=Companion, superNames=[]] MODIFIER_LIST:[private companion] - ANNOTATION_ENTRY:[hasValueArguments=false, shortName=b] - CONSTRUCTOR_CALLEE: - TYPE_REFERENCE: - USER_TYPE:[isAbsoluteInRootPackage=false] - REFERENCE_EXPRESSION:[referencedName=b] CLASS_BODY: PROPERTY:[fqName=Annotations.c, hasDelegate=false, hasDelegateExpression=false, hasInitializer=false, hasReturnTypeRef=true, isExtension=false, isTopLevel=false, isVar=false, name=c] MODIFIER_LIST:[private final] - ANNOTATION_ENTRY:[hasValueArguments=false, shortName=b] - CONSTRUCTOR_CALLEE: - TYPE_REFERENCE: - USER_TYPE:[isAbsoluteInRootPackage=false] - REFERENCE_EXPRESSION:[referencedName=b] TYPE_REFERENCE: USER_TYPE:[isAbsoluteInRootPackage=false] USER_TYPE:[isAbsoluteInRootPackage=false] @@ -133,11 +123,6 @@ PsiJetFileStubImpl[package=] TYPE_REFERENCE: USER_TYPE:[isAbsoluteInRootPackage=false] REFERENCE_EXPRESSION:[referencedName=a] - ANNOTATION_ENTRY:[hasValueArguments=false, shortName=b] - CONSTRUCTOR_CALLEE: - TYPE_REFERENCE: - USER_TYPE:[isAbsoluteInRootPackage=false] - REFERENCE_EXPRESSION:[referencedName=b] VALUE_PARAMETER_LIST: VALUE_PARAMETER:[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=p1] MODIFIER_LIST:[] @@ -200,15 +185,5 @@ PsiJetFileStubImpl[package=] TYPE_REFERENCE: USER_TYPE:[isAbsoluteInRootPackage=false] REFERENCE_EXPRESSION:[referencedName=a] - ANNOTATION_ENTRY:[hasValueArguments=false, shortName=b] - CONSTRUCTOR_CALLEE: - TYPE_REFERENCE: - USER_TYPE:[isAbsoluteInRootPackage=false] - REFERENCE_EXPRESSION:[referencedName=b] - ANNOTATION_ENTRY:[hasValueArguments=false, shortName=b] - CONSTRUCTOR_CALLEE: - TYPE_REFERENCE: - USER_TYPE:[isAbsoluteInRootPackage=false] - REFERENCE_EXPRESSION:[referencedName=b] VALUE_PARAMETER_LIST: CLASS_BODY: