diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt index d1cfa3bb00a..54ada1c3878 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt @@ -7,15 +7,16 @@ package org.jetbrains.kotlin.fir.checkers.generator.diagnostics import com.intellij.psi.PsiElement import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.descriptors.Named import org.jetbrains.kotlin.fir.PrivateForInline -import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList -import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.* +import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtAnnotationEntry import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtExpression @Suppress("UNUSED_VARIABLE", "LocalVariableName", "ClassName", "unused") @OptIn(PrivateForInline::class) @@ -111,6 +112,15 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") { val EXTERNAL_DECLARATION_CANNOT_BE_INLINED by error(PositioningStrategy.DECLARATION_SIGNATURE) } + val REPEATABLE by object : DiagnosticGroup("Repeatable Annotations") { + val NON_SOURCE_REPEATED_ANNOTATION by error() + val REPEATED_ANNOTATION_TARGET6 by error() + val REPEATED_ANNOTATION_WITH_CONTAINER by error { + parameter("name") + parameter("explicitContainerName") + } + } + val MISC by object : DiagnosticGroup("Misc") { val INAPPLICABLE_JVM_FIELD by error { parameter("message") diff --git a/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt b/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt index eac86852e34..b410ed2c92e 100644 --- a/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt +++ b/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt @@ -89,6 +89,11 @@ object FirJvmErrors { val EXTERNAL_DECLARATION_IN_INTERFACE by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) val EXTERNAL_DECLARATION_CANNOT_BE_INLINED by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) + // Repeatable Annotations + val NON_SOURCE_REPEATED_ANNOTATION by error0() + val REPEATED_ANNOTATION_TARGET6 by error0() + val REPEATED_ANNOTATION_WITH_CONTAINER by error2() + // Misc val INAPPLICABLE_JVM_FIELD by error1() val INAPPLICABLE_JVM_FIELD_WARNING by warning1() diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt index 8a635cdc590..1341f54964a 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt @@ -19,6 +19,7 @@ object JvmDeclarationCheckers : DeclarationCheckers() { override val annotatedDeclarationCheckers: Set get() = setOf( FirJvmStaticChecker, + FirRepeatableAnnotationChecker ) override val classCheckers: Set diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirRepeatableAnnotationChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirRepeatableAnnotationChecker.kt new file mode 100644 index 00000000000..cb1decd727d --- /dev/null +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirRepeatableAnnotationChecker.kt @@ -0,0 +1,106 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration + +import org.jetbrains.kotlin.builtins.StandardNames +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirAnnotatedDeclarationChecker +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.languageVersionSettings +import org.jetbrains.kotlin.fir.moduleData +import org.jetbrains.kotlin.fir.resolve.fqName +import org.jetbrains.kotlin.fir.resolve.symbolProvider +import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirEnumEntrySymbol +import org.jetbrains.kotlin.fir.types.ConeClassLikeType +import org.jetbrains.kotlin.fir.types.coneType +import org.jetbrains.kotlin.fir.types.lowerBoundIfFlexible +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name + +object FirRepeatableAnnotationChecker : FirAnnotatedDeclarationChecker() { + private val RETENTION_PARAMETER_NAME = Name.identifier("value") + private val REPEATABLE_PARAMETER_NAME = Name.identifier("value") + private val JAVA_REPEATABLE_ANNOTATION = FqName("java.lang.annotation.Repeatable") + + override fun check(declaration: FirAnnotatedDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + val annotationsSet = hashSetOf() + + val session = context.session + val annotations = declaration.annotations + for (annotation in annotations) { + val classId = annotation.classId ?: continue + val annotationClassId = annotation.toAnnotationClassId() ?: continue + if (annotationClassId.isLocal) continue + val annotationClass = session.symbolProvider.getClassLikeSymbolByFqName(annotationClassId) ?: continue + + // TODO: consider REPEATED_ANNOTATION ? + if (fqName in annotationsSet && + annotationClass.isRepeatableAnnotation(session) && + annotationClass.getAnnotationRetention() != AnnotationRetention.SOURCE + ) { + if (session.moduleData.platform.componentPlatforms.any { it.targetName == "1.6" }) { + reporter.reportOn(annotation.source, FirJvmErrors.REPEATED_ANNOTATION_TARGET6, context) + } else if (session.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 = annotationClass.resolveContainerAnnotation() + if (explicitContainer != null && annotations.any { it.fqName(session) == explicitContainer }) { + reporter.reportOn( + annotation.source, + FirJvmErrors.REPEATED_ANNOTATION_WITH_CONTAINER, + fqName, + explicitContainer, + context + ) + } + } else { + reporter.reportOn(annotation.source, FirJvmErrors.NON_SOURCE_REPEATED_ANNOTATION, context) + } + } + + annotationsSet.add(fqName) + } + } + + private fun FirClassLikeSymbol<*>.isRepeatableAnnotation(session: FirSession): Boolean { + if (getAnnotationByFqName(StandardNames.FqNames.repeatable) != null) return true + if (getAnnotationByFqName(JAVA_REPEATABLE_ANNOTATION) == null) return false + + return session.languageVersionSettings.supportsFeature(LanguageFeature.RepeatableAnnotations) || + getAnnotationRetention() == AnnotationRetention.SOURCE + } + + private fun FirClassLikeSymbol<*>.getAnnotationRetention(): AnnotationRetention? { + val repeatableAnnotation = getAnnotationByFqName(StandardNames.FqNames.retention) ?: return null + val retentionValue = repeatableAnnotation.findArgumentByName(RETENTION_PARAMETER_NAME) ?: return null + val resolvedSymbol = retentionValue.toResolvedCallableSymbol() as? FirEnumEntrySymbol ?: return null + val name = resolvedSymbol.name.asString() + + return AnnotationRetention.values().firstOrNull { it.name == name } + } + + private fun FirClassLikeSymbol<*>.resolveContainerAnnotation(): FqName? { + val repeatableAnnotation = + getAnnotationByFqName(StandardNames.FqNames.repeatable) ?: getAnnotationByFqName(JAVA_REPEATABLE_ANNOTATION) ?: return null + val value = repeatableAnnotation.findArgumentByName(REPEATABLE_PARAMETER_NAME) ?: return null + val classCallArgument = (value as? FirGetClassCall)?.argument ?: return null + if (classCallArgument is FirResolvedQualifier) { + return classCallArgument.relativeClassFqName + } else if (classCallArgument is FirClassReferenceExpression) { + val type = classCallArgument.classTypeRef.coneType.lowerBoundIfFlexible() as? ConeClassLikeType ?: return null + return type.lookupTag.classId.asSingleFqName() + } + return null + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/diagnostics/FirJvmDefaultErrorMessages.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/diagnostics/FirJvmDefaultErrorMessages.kt index a76d10d33c4..7920cd72c7f 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/diagnostics/FirJvmDefaultErrorMessages.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/diagnostics/FirJvmDefaultErrorMessages.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.analysis.jvm.diagnostics +import org.jetbrains.kotlin.diagnostics.rendering.Renderers.NAME import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.STRING import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDefaultErrorMessages import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE @@ -47,6 +48,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.LOCAL_JVM_ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.NON_DATA_CLASS_JVM_RECORD import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.NON_FINAL_JVM_RECORD import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.NON_JVM_DEFAULT_OVERRIDES_JAVA_DEFAULT +import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.NON_SOURCE_REPEATED_ANNOTATION import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_ABSTRACT import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_INTERFACE @@ -54,6 +56,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_PRIVATE import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERRIDE_CANNOT_BE_STATIC +import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATED_ANNOTATION_TARGET6 +import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATED_ANNOTATION_WITH_CONTAINER import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.STRICTFP_ON_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SUPER_CALL_WITH_DEFAULT_PARAMETERS import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZED_IN_INTERFACE @@ -172,6 +176,34 @@ object FirJvmDefaultErrorMessages { map.put(INAPPLICABLE_JVM_FIELD_WARNING, "{0}. This warning will become an error in further releases", STRING) map.put(JVM_SYNTHETIC_ON_DELEGATE, "'@JvmSynthetic' annotation cannot be used on delegated properties") + + 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( + DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET, + "Super calls to Java default methods are prohibited in JVM target 1.6. Recompile with '-jvm-target 1.8'" + ) + map.put( + INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET, + "Calls to static methods in Java interfaces are prohibited in JVM target 1.6. Recompile with '-jvm-target 1.8'" + ) + map.put( + INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER, + "Interfaces can call default methods via super only within @JvmDefault members. Please annotate the containing interface member with @JvmDefault" + ) } } } \ No newline at end of file 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 index 23cbb75ceb2..5af4685e48d 100644 --- a/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_5.fir.kt @@ -50,12 +50,12 @@ fun jr1() {} @JR @JR.Container() -@JR +@JR fun jr2() {} @JR @JR.Container(JR()) -@JR +@JR fun jr3() {} @JR 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 deleted file mode 100644 index 4b9baffadcb..00000000000 --- a/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.fir.kt +++ /dev/null @@ -1,142 +0,0 @@ -// !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 index b06e8ecc584..ee40fdc58ac 100644 --- a/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.kt +++ b/compiler/testData/diagnostics/tests/annotations/repeatable/containerAndAnnotationAreBothApplied_1_6.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +RepeatableAnnotations // FULL_JDK // FILE: JR.java diff --git a/compiler/testData/diagnostics/tests/annotations/repeatable/javaRepeatableJvmTarget6.fir.kt b/compiler/testData/diagnostics/tests/annotations/repeatable/javaRepeatableJvmTarget6.fir.kt deleted file mode 100644 index 0a58e2974dd..00000000000 --- a/compiler/testData/diagnostics/tests/annotations/repeatable/javaRepeatableJvmTarget6.fir.kt +++ /dev/null @@ -1,49 +0,0 @@ -// !LANGUAGE: +RepeatableAnnotations -// !JVM_TARGET: 1.6 -// FULL_JDK -// FILE: Runtime.java - -import java.lang.annotation.*; - -@Repeatable(Runtime.Container.class) -@Retention(RetentionPolicy.RUNTIME) -public @interface Runtime { - public @interface Container { - Runtime[] value(); - } -} - -// FILE: Clazz.java - -import java.lang.annotation.*; - -@Repeatable(Clazz.Container.class) -@Retention(RetentionPolicy.CLASS) -public @interface Clazz { - public @interface Container { - Clazz[] value(); - } -} - -// FILE: Source.java - -import java.lang.annotation.*; - -@Repeatable(Source.Container.class) -@Retention(RetentionPolicy.SOURCE) -public @interface Source { - public @interface Container { - Source[] value(); - } -} - -// FILE: usage.kt - -@Runtime @Runtime -class UseRuntime - -@Clazz @Clazz -class UseClazz - -@Source @Source -class UseSource diff --git a/compiler/testData/diagnostics/tests/annotations/repeatable/javaRepeatableJvmTarget6.kt b/compiler/testData/diagnostics/tests/annotations/repeatable/javaRepeatableJvmTarget6.kt index 205dfbefab2..458fd261893 100644 --- a/compiler/testData/diagnostics/tests/annotations/repeatable/javaRepeatableJvmTarget6.kt +++ b/compiler/testData/diagnostics/tests/annotations/repeatable/javaRepeatableJvmTarget6.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +RepeatableAnnotations // !JVM_TARGET: 1.6 // FULL_JDK diff --git a/compiler/testData/diagnostics/tests/annotations/repeatable/javaRepeatable_1_5.fir.kt b/compiler/testData/diagnostics/tests/annotations/repeatable/javaRepeatable_1_5.fir.kt index ca1795663b3..78125ecfa94 100644 --- a/compiler/testData/diagnostics/tests/annotations/repeatable/javaRepeatable_1_5.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/repeatable/javaRepeatable_1_5.fir.kt @@ -38,10 +38,10 @@ public @interface Source { // FILE: usage.kt -@Runtime @Runtime +@Runtime @Runtime class UseRuntime -@Clazz @Clazz +@Clazz @Clazz class UseClazz @Source @Source diff --git a/compiler/testData/diagnostics/tests/annotations/repeatable/kotlinRepeatable_1_5.fir.kt b/compiler/testData/diagnostics/tests/annotations/repeatable/kotlinRepeatable_1_5.fir.kt deleted file mode 100644 index b5179ac8654..00000000000 --- a/compiler/testData/diagnostics/tests/annotations/repeatable/kotlinRepeatable_1_5.fir.kt +++ /dev/null @@ -1,33 +0,0 @@ -// !LANGUAGE: -RepeatableAnnotations - -@Repeatable -annotation class repann - -@Retention(AnnotationRetention.SOURCE) -@Repeatable -annotation class repann1(val x: Int) - -@Retention(AnnotationRetention.SOURCE) -@Repeatable -annotation class repann2(val f: Boolean) - -@Retention(AnnotationRetention.BINARY) -@Repeatable -annotation class binrepann - -@Target(AnnotationTarget.EXPRESSION) -@Retention(AnnotationRetention.SOURCE) -@Repeatable -annotation class repexpr - -@repann @repann class DoubleAnnotated - -@repann1(1) @repann1(2) @repann1(3) class TripleAnnotated - -@repann2(true) @repann2(false) @repann2(false) @repann2(true) class FourTimesAnnotated - -@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/repeatable/kotlinRepeatable_1_5.kt b/compiler/testData/diagnostics/tests/annotations/repeatable/kotlinRepeatable_1_5.kt index 68de8188765..ecdfc011758 100644 --- a/compiler/testData/diagnostics/tests/annotations/repeatable/kotlinRepeatable_1_5.kt +++ b/compiler/testData/diagnostics/tests/annotations/repeatable/kotlinRepeatable_1_5.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: -RepeatableAnnotations @Repeatable diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index 59229392fa1..354742d35a0 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -2520,7 +2520,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert firDiagnostic.b, firDiagnostic.c.mapKeys { (incompatible, _) -> incompatible - }.mapValues { (_, collection) -> + }.mapValues { (_, collection) -> collection.map { firBasedSymbol -> firSymbolBuilder.buildSymbol(firBasedSymbol.fir) } @@ -2534,7 +2534,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert firSymbolBuilder.buildSymbol(firDiagnostic.a.fir), firDiagnostic.b.mapKeys { (incompatible, _) -> incompatible - }.mapValues { (_, collection) -> + }.mapValues { (_, collection) -> collection.map { firBasedSymbol -> firSymbolBuilder.buildSymbol(firBasedSymbol.fir) } @@ -2569,7 +2569,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert firDiagnostic.b.map { pair -> firSymbolBuilder.buildSymbol(pair.first.fir) to pair.second.mapKeys { (incompatible, _) -> incompatible - }.mapValues { (_, collection) -> + }.mapValues { (_, collection) -> collection.map { firBasedSymbol -> firSymbolBuilder.buildSymbol(firBasedSymbol.fir) } @@ -3780,6 +3780,26 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirJvmErrors.NON_SOURCE_REPEATED_ANNOTATION) { firDiagnostic -> + NonSourceRepeatedAnnotationImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirJvmErrors.REPEATED_ANNOTATION_TARGET6) { firDiagnostic -> + RepeatedAnnotationTarget6Impl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirJvmErrors.REPEATED_ANNOTATION_WITH_CONTAINER) { firDiagnostic -> + RepeatedAnnotationWithContainerImpl( + firDiagnostic.a, + firDiagnostic.b, + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirJvmErrors.INAPPLICABLE_JVM_FIELD) { firDiagnostic -> InapplicableJvmFieldImpl( firDiagnostic.a, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index 150c040b516..d1f9dcf3837 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -2628,6 +2628,20 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = ExternalDeclarationCannotBeInlined::class } + abstract class NonSourceRepeatedAnnotation : KtFirDiagnostic() { + override val diagnosticClass get() = NonSourceRepeatedAnnotation::class + } + + abstract class RepeatedAnnotationTarget6 : KtFirDiagnostic() { + override val diagnosticClass get() = RepeatedAnnotationTarget6::class + } + + abstract class RepeatedAnnotationWithContainer : KtFirDiagnostic() { + override val diagnosticClass get() = RepeatedAnnotationWithContainer::class + abstract val name: FqName + abstract val explicitContainerName: FqName + } + abstract class InapplicableJvmField : KtFirDiagnostic() { override val diagnosticClass get() = InapplicableJvmField::class abstract val message: String diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index ea3b78decf6..059824efd8c 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -4273,6 +4273,29 @@ internal class ExternalDeclarationCannotBeInlinedImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class NonSourceRepeatedAnnotationImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.NonSourceRepeatedAnnotation(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class RepeatedAnnotationTarget6Impl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.RepeatedAnnotationTarget6(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class RepeatedAnnotationWithContainerImpl( + override val name: FqName, + override val explicitContainerName: FqName, + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.RepeatedAnnotationWithContainer(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class InapplicableJvmFieldImpl( override val message: String, firDiagnostic: FirPsiDiagnostic,