diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/incompatibleModifiers.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/incompatibleModifiers.kt index 930e025ca9c..8ac05486eaf 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/incompatibleModifiers.kt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/incompatibleModifiers.kt @@ -22,7 +22,7 @@ abstract class K { private abstract val i2: Int } -private open class L : K() +private open class L : K() private abstract class M : K() class X { diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index a2a88b9995a..3f1efa1539d 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -299,6 +299,14 @@ object DIAGNOSTICS_LIST : DiagnosticList() { parameter>("classOrObject") parameter>("missingDeclaration") } + val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER by error(PositioningStrategy.DECLARATION_NAME) { + parameter>("classOrObject") + parameter>("invisibleDeclaration") + } + val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING by warning(PositioningStrategy.DECLARATION_NAME) { + parameter>("classOrObject") + parameter>("invisibleDeclaration") + } val MANY_IMPL_MEMBER_NOT_IMPLEMENTED by error(PositioningStrategy.DECLARATION_NAME) { parameter>("classOrObject") parameter>("missingDeclaration") diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 4d81dcb5e31..d9fd8e5f420 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -210,6 +210,8 @@ object FirErrors { val OVERRIDING_FINAL_MEMBER by error2, Name>(SourceElementPositioningStrategies.OVERRIDE_MODIFIER) val ABSTRACT_MEMBER_NOT_IMPLEMENTED by error2, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME) val ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED by error2, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME) + val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER by error2, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME) + val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING by warning2, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME) val MANY_IMPL_MEMBER_NOT_IMPLEMENTED by error2, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME) val MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED by error2, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME) val RETURN_TYPE_MISMATCH_ON_OVERRIDE by error2(SourceElementPositioningStrategies.DECLARATION_RETURN_TYPE) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt index b466658a104..0eded547fc8 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities @@ -17,6 +18,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.types.coneType @@ -43,6 +45,7 @@ object FirNotImplementedOverrideChecker : FirClassChecker() { ) val notImplementedSymbols = mutableListOf>() + val invisibleSymbols = mutableListOf>() val classPackage = declaration.symbol.classId.packageFqName fun FirCallableMemberDeclaration<*>.isInvisible(): Boolean { @@ -67,22 +70,25 @@ object FirNotImplementedOverrideChecker : FirClassChecker() { classScope.processFunctionsByName(name) { namedFunctionSymbol -> val simpleFunction = namedFunctionSymbol.fir if (!simpleFunction.shouldBeImplemented()) return@processFunctionsByName - // TODO: private & package-private functions / properties require another diagnostic - // (INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER) - if (simpleFunction.isInvisible()) return@processFunctionsByName - if (declaration.isData && simpleFunction.matchesDataClassSyntheticMemberSignatures) return@processFunctionsByName // TODO: suspend function overridden by a Java class in the middle is not properly regarded as an override if (simpleFunction.isSuspend) return@processFunctionsByName - notImplementedSymbols += namedFunctionSymbol + if (simpleFunction.isInvisible()) { + invisibleSymbols += namedFunctionSymbol + } else { + notImplementedSymbols += namedFunctionSymbol + } } classScope.processPropertiesByName(name) { propertySymbol -> val property = propertySymbol.fir as? FirProperty ?: return@processPropertiesByName if (!property.shouldBeImplemented()) return@processPropertiesByName - if (property.isInvisible()) return@processPropertiesByName - notImplementedSymbols += propertySymbol + if (property.isInvisible()) { + invisibleSymbols += propertySymbol + } else { + notImplementedSymbols += propertySymbol + } } } @@ -94,6 +100,14 @@ object FirNotImplementedOverrideChecker : FirClassChecker() { reporter.reportOn(source, FirErrors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context) } } + if (invisibleSymbols.isNotEmpty()) { + val invisible = invisibleSymbols.first().fir + if (context.session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitInvisibleAbstractMethodsInSuperclasses)) { + reporter.reportOn(source, FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER, declaration, invisible, context) + } else { + reporter.reportOn(source, FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING, declaration, invisible, context) + } + } } private fun FirCallableDeclaration<*>.isFromInterface(context: CheckerContext): Boolean = diff --git a/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromJava.fir.kt b/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromJava.fir.kt deleted file mode 100644 index 3185bec9eaa..00000000000 --- a/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromJava.fir.kt +++ /dev/null @@ -1,21 +0,0 @@ -// !LANGUAGE: +ProhibitInvisibleAbstractMethodsInSuperclasses -// FILE: base/Base.java -package base; - -public abstract class Base { - public void foo() { - packagePrivateFoo(); - } - - /* package-private */ abstract void packagePrivateFoo(); -} - -// FILE: Impl.kt -package impl -import base.* - -class Impl : Base() - -fun foo() { - Impl().foo() -} diff --git a/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromJava.kt b/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromJava.kt index 1ea47cc08cc..8a65b451a41 100644 --- a/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromJava.kt +++ b/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromJava.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +ProhibitInvisibleAbstractMethodsInSuperclasses // FILE: base/Base.java package base; diff --git a/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromKotlin.fir.kt b/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromKotlin.fir.kt index 2c7d6dd65db..2314d5d9cb5 100644 --- a/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromKotlin.fir.kt +++ b/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromKotlin.fir.kt @@ -27,9 +27,9 @@ package impl import base.* import intermediate.* -class ImplDirectFromBase : Base() +class ImplDirectFromBase : Base() -object ImplObjDirectFromBase : Base() +object ImplObjDirectFromBase : Base() class ImplDirectFromBaseWithOverride : BaseWithOverride() @@ -37,7 +37,7 @@ class ImplDirectFromBaseWithOverrid : Base() { override fun internalFoo(): String = "" } -class ImplViaIntermediate : Intermediate() +class ImplViaIntermediate : Intermediate() fun foo() { ImplDirectFromBase().foo() diff --git a/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromKotlinWarning.fir.kt b/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromKotlinWarning.fir.kt deleted file mode 100644 index 8a09feb8a6f..00000000000 --- a/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromKotlinWarning.fir.kt +++ /dev/null @@ -1,22 +0,0 @@ -// !LANGUAGE: -ProhibitInvisibleAbstractMethodsInSuperclasses -// MODULE: base -// FILE: Base.kt -package base - -abstract class Base { - fun foo(): String { - return internalFoo() - } - internal abstract fun internalFoo(): String -} - -// MODULE: impl(base) -// FILE: Impl.kt -package impl -import base.* - -class Impl : Base() - -fun foo() { - Impl().foo() -} diff --git a/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromKotlinWarning.kt b/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromKotlinWarning.kt index 5e781c0a17f..2ebd51d8cbd 100644 --- a/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromKotlinWarning.kt +++ b/compiler/testData/diagnostics/tests/visibility/abstractInvisibleMemberFromKotlinWarning.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: -ProhibitInvisibleAbstractMethodsInSuperclasses // MODULE: base // FILE: Base.kt diff --git a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.5.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.5.fir.kt index d863115e225..d89e08f802f 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.5.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.5.fir.kt @@ -26,7 +26,7 @@ import base.* // TESTCASE NUMBER: 1 -class Case1 : BaseJava() {} +class Case1 : BaseJava() {} fun case1() { val v = Case1() @@ -38,7 +38,7 @@ fun case1() { */ abstract class AbstractClassCase2 : BaseJava() {} -class Case2 : AbstractClassCase2() {} +class Case2 : AbstractClassCase2() {} fun case2() { val v = Case2() diff --git a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.6.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.6.fir.kt index 6daab747dd9..2b711accb1c 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.6.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.6.fir.kt @@ -51,7 +51,7 @@ fun case2() { // TESTCASE NUMBER: 3 -class Case3 : BaseJava() {} +class Case3 : BaseJava() {} fun case3() { val v = Case3() @@ -63,7 +63,7 @@ fun case3() { */ abstract class AbstractClassCase4 : BaseJava() {} -class Case4 : AbstractClassCase4() {} +class Case4 : AbstractClassCase4() {} fun case4() { val v = Case4() diff --git a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.7.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.7.fir.kt index 499fc322cda..b8265bf23f0 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.7.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.7.fir.kt @@ -59,7 +59,7 @@ fun case2() { // TESTCASE NUMBER: 3 -class Case3 : BaseKotlin() {} +class Case3 : BaseKotlin() {} fun case3() { val v = Case3() @@ -73,7 +73,7 @@ fun case3() { */ abstract class AbstractClassCase4 : BaseKotlin() {} -class Case4 : AbstractClassCase4() {} +class Case4 : AbstractClassCase4() {} fun case4() { val v = Case4() diff --git a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.8.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.8.fir.kt index 42a1256a292..311ae0b1873 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.8.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.8.fir.kt @@ -20,7 +20,7 @@ abstract class AbstractClassCase1() { public abstract val pub1: String } -class Case1 : AbstractClassCase1(){ +class Case1 : AbstractClassCase1(){ override fun prot() {} override fun int() { 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 2b60ef07674..7a83a6ead3d 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 @@ -896,6 +896,22 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER) { firDiagnostic -> + InvisibleAbstractMemberFromSuperImpl( + firSymbolBuilder.buildClassLikeSymbol(firDiagnostic.a), + firSymbolBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration), + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } + add(FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING) { firDiagnostic -> + InvisibleAbstractMemberFromSuperWarningImpl( + firSymbolBuilder.buildClassLikeSymbol(firDiagnostic.a), + firSymbolBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration), + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } add(FirErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED) { firDiagnostic -> ManyImplMemberNotImplementedImpl( firSymbolBuilder.buildClassLikeSymbol(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 3f0406144fe..830c4a3463e 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 @@ -637,6 +637,18 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val missingDeclaration: KtCallableSymbol } + abstract class InvisibleAbstractMemberFromSuper : KtFirDiagnostic() { + override val diagnosticClass get() = InvisibleAbstractMemberFromSuper::class + abstract val classOrObject: KtClassLikeSymbol + abstract val invisibleDeclaration: KtCallableSymbol + } + + abstract class InvisibleAbstractMemberFromSuperWarning : KtFirDiagnostic() { + override val diagnosticClass get() = InvisibleAbstractMemberFromSuperWarning::class + abstract val classOrObject: KtClassLikeSymbol + abstract val invisibleDeclaration: KtCallableSymbol + } + abstract class ManyImplMemberNotImplemented : KtFirDiagnostic() { override val diagnosticClass get() = ManyImplMemberNotImplemented::class abstract val classOrObject: KtClassLikeSymbol 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 58d4f95e38d..e6d720e6cf4 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 @@ -1025,6 +1025,24 @@ internal class AbstractClassMemberNotImplementedImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } +internal class InvisibleAbstractMemberFromSuperImpl( + override val classOrObject: KtClassLikeSymbol, + override val invisibleDeclaration: KtCallableSymbol, + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.InvisibleAbstractMemberFromSuper(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + +internal class InvisibleAbstractMemberFromSuperWarningImpl( + override val classOrObject: KtClassLikeSymbol, + override val invisibleDeclaration: KtCallableSymbol, + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.InvisibleAbstractMemberFromSuperWarning(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class ManyImplMemberNotImplementedImpl( override val classOrObject: KtClassLikeSymbol, override val missingDeclaration: KtCallableSymbol,