diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 1fa1b252d5e..8a7a5816d2d 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -2474,6 +2474,16 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY) { firDiagnostic -> + AbstractMemberNotImplementedByEnumEntryImpl( + firSymbolBuilder.buildSymbol(firDiagnostic.a), + firDiagnostic.b.map { firCallableSymbol -> + firSymbolBuilder.callableBuilder.buildCallableSymbol(firCallableSymbol) + }, + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED) { firDiagnostic -> AbstractClassMemberNotImplementedImpl( firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a), diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index 5bb244e650f..057526ccc62 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -1758,6 +1758,12 @@ sealed interface KtFirDiagnostic : KtDiagnosticWithPsi { val missingDeclaration: KtCallableSymbol } + interface AbstractMemberNotImplementedByEnumEntry : KtFirDiagnostic { + override val diagnosticClass get() = AbstractMemberNotImplementedByEnumEntry::class + val enumEntry: KtSymbol + val missingDeclarations: List + } + interface AbstractClassMemberNotImplemented : KtFirDiagnostic { override val diagnosticClass get() = AbstractClassMemberNotImplemented::class val classOrObject: KtClassLikeSymbol diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 98e9b0b1404..fc9a4a69e38 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -2110,6 +2110,13 @@ internal class AbstractMemberNotImplementedImpl( token: KtLifetimeToken, ) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.AbstractMemberNotImplemented +internal class AbstractMemberNotImplementedByEnumEntryImpl( + override val enumEntry: KtSymbol, + override val missingDeclarations: List, + firDiagnostic: KtPsiDiagnostic, + token: KtLifetimeToken, +) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.AbstractMemberNotImplementedByEnumEntry + internal class AbstractClassMemberNotImplementedImpl( override val classOrObject: KtClassLikeSymbol, override val missingDeclaration: KtCallableSymbol, 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 b7266b7f716..ef094fd83fc 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 @@ -861,6 +861,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { parameter>("classOrObject") parameter>("missingDeclaration") } + val ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY by error(PositioningStrategy.DECLARATION_NAME) { + parameter("enumEntry") + parameter>>("missingDeclarations") + } val ABSTRACT_CLASS_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 7c22b7e0f58..fa0aca7e5df 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 @@ -471,6 +471,7 @@ object FirErrors { val VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION by error2, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME) val CONFLICTING_INHERITED_MEMBERS by error2, List>>(SourceElementPositioningStrategies.DECLARATION_NAME) val ABSTRACT_MEMBER_NOT_IMPLEMENTED by error2, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME) + val ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY by error2>>(SourceElementPositioningStrategies.DECLARATION_NAME) val ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED by error2, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME) val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER by deprecationError2, FirCallableSymbol<*>>(ProhibitInvisibleAbstractMethodsInSuperclasses, SourceElementPositioningStrategies.DECLARATION_NAME) val AMBIGUOUS_ANONYMOUS_TYPE_INFERRED by error1>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt index 9d55889320e..40b9da1cdfc 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt @@ -92,6 +92,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { get() = setOf( FirOverrideChecker, FirNotImplementedOverrideChecker, + FirNotImplementedOverrideSimpleEnumEntryChecker, FirThrowableSubclassChecker, FirOpenMemberChecker, FirClassVarianceChecker, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideSimpleEnumEntryChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideSimpleEnumEntryChecker.kt new file mode 100644 index 00000000000..ae1335fb503 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideSimpleEnumEntryChecker.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2023 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.checkers.declaration + +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY +import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.FirEnumEntry +import org.jetbrains.kotlin.fir.declarations.utils.isAbstract +import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass +import org.jetbrains.kotlin.fir.scopes.processAllCallables +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol + +object FirNotImplementedOverrideSimpleEnumEntryChecker : FirClassChecker() { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isEnumClass) return + + // Enum entries with an initializer are handled by FirNotImplementedOverrideChecker since they contain an AnonymousObject. + val enumEntries = declaration.declarations.filterIsInstance().filter { it.initializer == null && it.source != null } + if (enumEntries.isEmpty()) return + + val enumScope = declaration.unsubstitutedScope(context) + + val notImplemented = mutableListOf>() + enumScope.processAllCallables { symbol -> + if (symbol.isAbstract) { + notImplemented.add(symbol) + } + } + + if (notImplemented.isEmpty()) return + + for (enumEntry in enumEntries) { + reporter.reportOn(enumEntry.source, ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY, enumEntry.symbol, notImplemented, context) + } + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index ac8e6460946..61cae6c7bde 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -40,6 +40,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_DELEGATE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_FUNCTION_WITH_BODY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_PROPERTY_WITH_GETTER @@ -1419,6 +1420,12 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { RENDER_CLASS_OR_OBJECT, DECLARATION_NAME ) + map.put( + ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY, + "''{0}'' does not implement abstract members: {1}.", + SYMBOL, + SYMBOLS, + ) map.put( ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, "{0} is not abstract and does not implement abstract base class member {1}", diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirContainingNamesAwareScope.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirContainingNamesAwareScope.kt index 2dd52cf8325..33f0ec41dd1 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirContainingNamesAwareScope.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirContainingNamesAwareScope.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.scopes +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.name.Name @@ -27,6 +28,13 @@ fun FirContainingNamesAwareScope.processAllProperties(processor: (FirVariableSym } } +fun FirContainingNamesAwareScope.processAllCallables(processor: (FirCallableSymbol<*>) -> Unit) { + for (name in getCallableNames()) { + processFunctionsByName(name, processor) + processPropertiesByName(name, processor) + } +} + fun FirContainingNamesAwareScope.collectAllProperties(): Collection> { return mutableListOf>().apply { processAllProperties(this::add) diff --git a/compiler/testData/diagnostics/tests/enum/AbstractInEnum.fir.kt b/compiler/testData/diagnostics/tests/enum/AbstractInEnum.fir.kt index 732b4eec884..16ca7eab842 100644 --- a/compiler/testData/diagnostics/tests/enum/AbstractInEnum.fir.kt +++ b/compiler/testData/diagnostics/tests/enum/AbstractInEnum.fir.kt @@ -2,7 +2,7 @@ package abstract enum class MyEnum() { - INSTANCE; + INSTANCE; //properties val a: Int val a1: Int = 1 diff --git a/compiler/testData/diagnostics/tests/enum/enumImplementingTrait.fir.kt b/compiler/testData/diagnostics/tests/enum/enumImplementingTrait.fir.kt index 3faa491a53d..4c2d4626b99 100644 --- a/compiler/testData/diagnostics/tests/enum/enumImplementingTrait.fir.kt +++ b/compiler/testData/diagnostics/tests/enum/enumImplementingTrait.fir.kt @@ -6,7 +6,7 @@ enum class EnumImplementingTraitWithFun: T1 { E1 { override fun foo() {} }, - E2 + E2 } interface T2 { @@ -17,5 +17,5 @@ enum class EnumImplementingTraitWithVal: T2 { E1 { override val bar = 1 }, - E2 -} \ No newline at end of file + E2 +}