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 223e2557a3e..790bb4ea130 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 @@ -21,6 +21,8 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") { val DECLARATIONS by object : DiagnosticGroup("Declarations") { val CONFLICTING_JVM_DECLARATIONS by error() + val OVERRIDE_CANNOT_BE_STATIC by error() + val INAPPLICABLE_JVM_NAME by error() val ILLEGAL_JVM_NAME by error() } 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 b918472719d..3a3e61e0063 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 @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.psi.KtExpression object FirJvmErrors { // Declarations val CONFLICTING_JVM_DECLARATIONS by error0() + val OVERRIDE_CANNOT_BE_STATIC by error0() val INAPPLICABLE_JVM_NAME by error0() val ILLEGAL_JVM_NAME by error0() 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 0c07ca8a160..b25d2cbe0d2 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 @@ -13,6 +13,7 @@ object JvmDeclarationCheckers : DeclarationCheckers() { get() = setOf( FirJvmExternalDeclarationChecker, FirJvmNameChecker, + FirJvmStaticChecker, ) override val classCheckers: Set diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmStaticChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmStaticChecker.kt new file mode 100644 index 00000000000..a864d50d3ba --- /dev/null +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmStaticChecker.kt @@ -0,0 +1,68 @@ +/* + * 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.descriptors.ClassKind +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker +import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol +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.declarations.utils.* +import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall +import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference +import org.jetbrains.kotlin.fir.symbols.SymbolInternals +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +object FirJvmStaticChecker : FirBasicDeclarationChecker() { + override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration !is FirCallableDeclaration) { + return + } + + if (!declaration.isOverride || !declaration.isContainerNotCompanionObject(context)) { + return + } + + if (declaration is FirProperty) { + declaration.getter?.let { + reportIfHasJvmStatic(it, context, reporter) + } + declaration.setter?.let { + reportIfHasJvmStatic(it, context, reporter) + } + } + + reportIfHasJvmStatic(declaration, context, reporter) + } + + private fun reportIfHasJvmStatic(declaration: FirAnnotatedDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.hasJvmStaticAnnotation()) { + reporter.reportOn(declaration.source, FirJvmErrors.OVERRIDE_CANNOT_BE_STATIC, context) + } + } + + private fun FirDeclaration.isContainerNotCompanionObject(context: CheckerContext): Boolean { + val containingClassSymbol = this.getContainingClassSymbol(context.session) ?: return false + + @OptIn(SymbolInternals::class) + val containingClass = containingClassSymbol.fir.safeAs() ?: return false + + return containingClass.classKind == ClassKind.OBJECT && !containingClass.isCompanion + } + + private fun FirAnnotatedDeclaration.hasJvmStaticAnnotation(): Boolean { + return findJvmStaticAnnotation() != null + } + + private fun FirAnnotatedDeclaration.findJvmStaticAnnotation(): FirAnnotationCall? { + return annotations.firstOrNull { + it.calleeReference.safeAs()?.name?.toString() == "JvmStatic" + } + } +} 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 f4963bea858..f75c45b245c 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 @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_LOCAL 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.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 @@ -96,6 +97,8 @@ object FirJvmDefaultErrorMessages { map.put(NON_DATA_CLASS_JVM_RECORD, "Only data classes are allowed to be marked as @JvmRecord") map.put(ILLEGAL_JAVA_LANG_RECORD_SUPERTYPE, "Classes cannot have explicit 'java.lang.Record' supertype") + map.put(OVERRIDE_CANNOT_BE_STATIC, "Override member cannot be '@JvmStatic' in object") + map.put(INAPPLICABLE_JVM_NAME, "'@JvmName' annotation is not applicable to this declaration") map.put(ILLEGAL_JVM_NAME, "Illegal JVM name") } diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/finalAndAbstract.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/finalAndAbstract.fir.kt index 2f4126ab0a3..d4d2b9f8ee9 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/finalAndAbstract.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/finalAndAbstract.fir.kt @@ -10,11 +10,11 @@ abstract class A { object B: A() { - @JvmStatic override fun a() {} + @JvmStatic override fun a() {} - @JvmStatic override fun b() {} + @JvmStatic override fun b() {} - @JvmStatic final override fun c() {} + @JvmStatic final override fun c() {} @JvmStatic open fun d() {} } diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/property.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/property.fir.kt index 30203bc6838..e7fe53e0582 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/property.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/property.fir.kt @@ -28,12 +28,12 @@ class A { @JvmStatic val z = 1; - @JvmStatic override val base1: Int = 0 + @JvmStatic override val base1: Int = 0 @JvmStatic open fun f() {} override val base2: Int = 0 - @JvmStatic get + @JvmStatic get } var p:Int = 1 diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/property_LL13.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/property_LL13.fir.kt index d4e2e84617d..4d91f405565 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/property_LL13.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/property_LL13.fir.kt @@ -28,12 +28,12 @@ class A { @JvmStatic val z = 1; - @JvmStatic override val base1: Int = 0 + @JvmStatic override val base1: Int = 0 @JvmStatic open fun f() {} override val base2: Int = 0 - @JvmStatic get + @JvmStatic get } var p:Int = 1 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 808fd5b9dd2..d7029e30beb 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 @@ -3664,6 +3664,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirJvmErrors.OVERRIDE_CANNOT_BE_STATIC) { firDiagnostic -> + OverrideCannotBeStaticImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirJvmErrors.INAPPLICABLE_JVM_NAME) { firDiagnostic -> InapplicableJvmNameImpl( 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 871d32c1fc1..8ff6c095094 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 @@ -2550,6 +2550,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = IllegalJavaLangRecordSupertype::class } + abstract class OverrideCannotBeStatic : KtFirDiagnostic() { + override val diagnosticClass get() = OverrideCannotBeStatic::class + } + abstract class InapplicableJvmName : KtFirDiagnostic() { override val diagnosticClass get() = InapplicableJvmName::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 0ce887ccb48..65f9be90629 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 @@ -4138,6 +4138,13 @@ internal class IllegalJavaLangRecordSupertypeImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class OverrideCannotBeStaticImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.OverrideCannotBeStatic(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class InapplicableJvmNameImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken,