diff --git a/compiler/fir/analysis-tests/testData/resolve/arguments/argumentsOfJavaAnnotation.kt b/compiler/fir/analysis-tests/testData/resolve/arguments/argumentsOfJavaAnnotation.kt index 4e128d99842..5330a9d0cc4 100644 --- a/compiler/fir/analysis-tests/testData/resolve/arguments/argumentsOfJavaAnnotation.kt +++ b/compiler/fir/analysis-tests/testData/resolve/arguments/argumentsOfJavaAnnotation.kt @@ -9,7 +9,7 @@ public @interface Ann { // FILE: main.kt @Ann(x = 10, s = "") -@Ann(10, "") +@Ann(10, "") @Ann(x = 10, s = "", y = 10) class A diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/AnnotationWithEnum.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/AnnotationWithEnum.kt index 9f6e402a052..9e21f561939 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/AnnotationWithEnum.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/AnnotationWithEnum.kt @@ -11,7 +11,7 @@ public @interface Nls { import some.Nls.Capitalization.* import some.Nls -@Nls(Title) +@Nls(Title) fun f() { -} \ No newline at end of file +} 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 bd80e30de01..26115ceeec8 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 @@ -69,6 +69,8 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") { val JVM_PACKAGE_NAME_CANNOT_BE_EMPTY by error() val JVM_PACKAGE_NAME_MUST_BE_VALID_NAME by error() val JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES by error() + + val POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION by error() } val SUPER by object : DiagnosticGroup("Super") { 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 19736366c46..30fa5b9be37 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 @@ -60,6 +60,7 @@ object FirJvmErrors { val JVM_PACKAGE_NAME_CANNOT_BE_EMPTY by error0() val JVM_PACKAGE_NAME_MUST_BE_VALID_NAME by error0() val JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES by error0() + val POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION by error0() // Super val SUPER_CALL_WITH_DEFAULT_PARAMETERS by error1() diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmExpressionCheckers.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmExpressionCheckers.kt index a3c6c277efd..e62aa638d83 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmExpressionCheckers.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmExpressionCheckers.kt @@ -27,7 +27,7 @@ object JvmExpressionCheckers : ExpressionCheckers() { override val annotationCheckers: Set get() = setOf( - FirDeprecatedJavaAnnotationsChecker, + FirJavaAnnotationsChecker, FirJvmPackageNameAnnotationsChecker, ) } diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirDeprecatedJavaAnnotationsChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJavaAnnotationsChecker.kt similarity index 63% rename from compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirDeprecatedJavaAnnotationsChecker.kt rename to compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJavaAnnotationsChecker.kt index b7a68825b39..03c07bb5311 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirDeprecatedJavaAnnotationsChecker.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJavaAnnotationsChecker.kt @@ -9,17 +9,23 @@ import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.fir.FirRealSourceElementKind import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationChecker +import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol 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.FirDeclarationOrigin import org.jetbrains.kotlin.fir.expressions.FirAnnotation +import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall +import org.jetbrains.kotlin.fir.expressions.FirWrappedArgumentExpression +import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.coneTypeSafe import org.jetbrains.kotlin.load.java.JvmAnnotationNames +import org.jetbrains.kotlin.load.java.JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName -object FirDeprecatedJavaAnnotationsChecker : FirAnnotationChecker() { +object FirJavaAnnotationsChecker : FirAnnotationChecker() { private val javaToKotlinNameMap: Map = mapOf( @@ -31,10 +37,23 @@ object FirDeprecatedJavaAnnotationsChecker : FirAnnotationChecker() { override fun check(expression: FirAnnotation, context: CheckerContext, reporter: DiagnosticReporter) { if (context.containingDeclarations.lastOrNull()?.source?.kind != FirRealSourceElementKind) return + val callableSymbol = expression.annotationTypeRef.toRegularClassSymbol(context.session) + if (callableSymbol?.origin != FirDeclarationOrigin.Java) return val lookupTag = expression.annotationTypeRef.coneTypeSafe()?.lookupTag ?: return javaToKotlinNameMap[lookupTag.classId]?.let { betterName -> reporter.reportOn(expression.source, FirJvmErrors.DEPRECATED_JAVA_ANNOTATION, betterName, context) } + + if (expression is FirAnnotationCall) { + val argumentList = expression.argumentList + if (argumentList is FirResolvedArgumentList) { + for ((key, value) in argumentList.mapping) { + if (value.name != DEFAULT_ANNOTATION_MEMBER_NAME && key !is FirWrappedArgumentExpression) { + reporter.reportOn(key.source, FirJvmErrors.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION, context) + } + } + } + } } } 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 b2f9467a2fe..b749e604a9c 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 @@ -59,6 +59,7 @@ 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.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_CONTAINER_HAS_NON_DEFAULT_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_CONTAINER_HAS_SHORTER_RETENTION @@ -98,6 +99,7 @@ object FirJvmDefaultErrorMessages { "'@JvmOverloads' annotation cannot be used on constructors of annotation classes" ) map.put(DEPRECATED_JAVA_ANNOTATION, "This annotation is deprecated in Kotlin. Use ''@{0}'' instead", TO_STRING) + map.put(POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION, "Only named arguments are available for Java annotations") map.put(JVM_PACKAGE_NAME_CANNOT_BE_EMPTY, "''@JvmPackageName'' annotation value cannot be empty") map.put( JVM_PACKAGE_NAME_MUST_BE_VALID_NAME, diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameters/valueArrayAndOtherDefault.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameters/valueArrayAndOtherDefault.fir.kt index 967766a3da7..3861b12954d 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameters/valueArrayAndOtherDefault.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameters/valueArrayAndOtherDefault.fir.kt @@ -25,5 +25,5 @@ public @interface A { @A fun test8() {} @A(x = Any::class, *arrayOf("5", "6"), "7", y = 3) fun test9() {} -@A(x = Any::class, value = ["5", "6"], "7", y = 3) fun test10() {} +@A(x = Any::class, value = ["5", "6"], "7", y = 3) fun test10() {} @A(x = Any::class, value = ["5", "6", "7"], y = 3) fun test11() {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/tooManyArgs.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/tooManyArgs.fir.kt index ab8d76fde53..91d7187dd78 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/tooManyArgs.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/tooManyArgs.fir.kt @@ -6,6 +6,6 @@ public @interface A { } // FILE: b.kt -@A(false, -1.0, -false, 1, 2) fun foo1() {} +@A(false, +1.0, +false, 1, 2) fun foo1() {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/typeMismatch.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/typeMismatch.fir.kt index f8055aefa28..f3cfb575a7d 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/typeMismatch.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/typeMismatch.fir.kt @@ -6,8 +6,8 @@ public @interface A { } // FILE: b.kt -@A(false, -1.0, -false) fun foo1() {} +@A(false, +1.0, +false) fun foo1() {} -@A(2.0, x = true, b = 2.0) fun foo2() {} +@A(2.0, x = true, b = 2.0) fun foo2() {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/withValue.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/withValue.fir.kt deleted file mode 100644 index d2766ff2519..00000000000 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/withValue.fir.kt +++ /dev/null @@ -1,17 +0,0 @@ -// FILE: A.java -public @interface A { - int a(); - double b(); - String value(); - boolean x(); -} - -// FILE: b.kt -@A("v1", 1, -1.0, -false) fun foo1() {} - -@A("v2", 2, x = true, b = 2.0) fun foo2() {} - -@A("v2", x = true, b = 3.0, a = 4) fun foo3() {} -@A(value = "v2", x = true, b = 3.0, a = 4) fun foo4() {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/withValue.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/withValue.kt index 3ab7061f744..71edd4a93fc 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/withValue.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/withValue.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // FILE: A.java public @interface A { int a(); diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/withoutValue.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/withoutValue.fir.kt deleted file mode 100644 index b0c8cf02472..00000000000 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/withoutValue.fir.kt +++ /dev/null @@ -1,17 +0,0 @@ -// FILE: A.java -public @interface A { - int a(); - double b(); - boolean x(); -} - -// FILE: b.kt -@A(1, -1.0, -false) fun foo1() {} - -@A(2, x = true, b = 2.0) fun foo2() {} - -@A(x = true, b = 3.0, a = 4) fun foo3() {} - - diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/withoutValue.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/withoutValue.kt index 3660b7f2647..71f4715972d 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/withoutValue.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/prohibitPositionedArgument/withoutValue.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // FILE: A.java public @interface A { int a(); 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 1102ecb1fb3..5fe85791d42 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 @@ -3743,6 +3743,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirJvmErrors.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION) { firDiagnostic -> + PositionedValueArgumentForJavaAnnotationImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirJvmErrors.LOCAL_JVM_RECORD) { firDiagnostic -> LocalJvmRecordImpl( firDiagnostic as FirPsiDiagnostic, 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 70d5bad34ec..3c4773ef29e 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 @@ -2604,6 +2604,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = JvmPackageNameNotSupportedInFilesWithClasses::class } + abstract class PositionedValueArgumentForJavaAnnotation : KtFirDiagnostic() { + override val diagnosticClass get() = PositionedValueArgumentForJavaAnnotation::class + } + abstract class LocalJvmRecord : KtFirDiagnostic() { override val diagnosticClass get() = LocalJvmRecord::class } 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 337502f08cc..9b280f95928 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 @@ -4231,6 +4231,13 @@ internal class JvmPackageNameNotSupportedInFilesWithClassesImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class PositionedValueArgumentForJavaAnnotationImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.PositionedValueArgumentForJavaAnnotation(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class LocalJvmRecordImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken,