From 44a4498ee571618bf6dd09050798b2c18a85609e Mon Sep 17 00:00:00 2001 From: Kirill Rakhman Date: Fri, 22 Sep 2023 13:10:45 +0200 Subject: [PATCH] [FIR] Report ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY on enum entries with initializer #KT-59577 Fixed --- .../testData/resolve/enum.fir.diag.txt | 3 ++ .../analysis-tests/testData/resolve/enum.kt | 5 ++-- .../FirNotImplementedOverrideChecker.kt | 28 ++++++++++++++++++- .../tests/enum/enumEntryInAbstractEnum.fir.kt | 13 +++++++++ .../tests/enum/enumEntryInAbstractEnum.kt | 1 - 5 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/enum.fir.diag.txt create mode 100644 compiler/testData/diagnostics/tests/enum/enumEntryInAbstractEnum.fir.kt diff --git a/compiler/fir/analysis-tests/testData/resolve/enum.fir.diag.txt b/compiler/fir/analysis-tests/testData/resolve/enum.fir.diag.txt new file mode 100644 index 00000000000..ce766e69ef6 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/enum.fir.diag.txt @@ -0,0 +1,3 @@ +/enum.kt:(506,508): error: 'static enum entry E2: EnumClass = object : EnumClass' does not implement abstract members: [fun foo(): Int, val bar: String]. + +/enum.kt:(524,526): error: 'static enum entry E3: EnumClass = object : EnumClass' does not implement abstract members: [fun foo(): Int, val bar: String]. diff --git a/compiler/fir/analysis-tests/testData/resolve/enum.kt b/compiler/fir/analysis-tests/testData/resolve/enum.kt index 85c14edcc19..2eab0ffff8e 100644 --- a/compiler/fir/analysis-tests/testData/resolve/enum.kt +++ b/compiler/fir/analysis-tests/testData/resolve/enum.kt @@ -1,3 +1,4 @@ +// RENDER_DIAGNOSTICS_FULL_TEXT interface Some object O1 : Some @@ -26,11 +27,11 @@ enum class EnumClass { override val bar: String = "a" }, - E2 { + E2 { }, - E3(); + E3(); abstract fun foo(): Int abstract val bar: String 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 0bce296e1f3..f9916d1b572 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 @@ -18,13 +18,17 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVISIBLE_ABSTRAC import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OVERRIDING_FINAL_MEMBER_BY_DELEGATION import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_IMPLEMENTED_BY_INHERITED_VAL import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin +import org.jetbrains.kotlin.fir.declarations.FirEnumEntry import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.delegatedWrapperData +import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.scopes.MemberWithBaseScope import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenMembersWithBaseScope @@ -32,6 +36,8 @@ import org.jetbrains.kotlin.fir.scopes.impl.* import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.unwrapFakeOverrides import org.jetbrains.kotlin.util.ImplementationStatus +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract object FirNotImplementedOverrideChecker : FirClassChecker() { @@ -126,7 +132,18 @@ object FirNotImplementedOverrideChecker : FirClassChecker() { val notImplemented = (notImplementedSymbols.firstOrNull { !it.isFromInterfaceOrEnum(context) } ?: notImplementedSymbols.first()) .unwrapFakeOverrides() if (notImplemented.isFromInterfaceOrEnum(context)) { - reporter.reportOn(source, ABSTRACT_MEMBER_NOT_IMPLEMENTED, classSymbol, notImplemented, context) + val containingDeclaration = context.containingDeclarations.lastOrNull() + if (declaration.isInitializerOfEnumEntry(containingDeclaration)) { + reporter.reportOn( + source, + ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY, + containingDeclaration.symbol, + notImplementedSymbols, + context + ) + } else { + reporter.reportOn(source, ABSTRACT_MEMBER_NOT_IMPLEMENTED, classSymbol, notImplemented, context) + } } else { reporter.reportOn(source, ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, classSymbol, notImplemented, context) } @@ -183,6 +200,15 @@ object FirNotImplementedOverrideChecker : FirClassChecker() { } } + @OptIn(ExperimentalContracts::class) + private fun FirClass.isInitializerOfEnumEntry(containingDeclaration: FirDeclaration?): Boolean { + contract { + returns(true) implies (containingDeclaration is FirEnumEntry) + } + return containingDeclaration is FirEnumEntry && + containingDeclaration.initializer.let { it is FirAnonymousObjectExpression && it.anonymousObject == this } + } + private fun FirCallableSymbol<*>.isFromInterfaceOrEnum(context: CheckerContext): Boolean = (getContainingClassSymbol(context.session) as? FirRegularClassSymbol)?.let { it.isInterface || it.isEnumClass } == true } diff --git a/compiler/testData/diagnostics/tests/enum/enumEntryInAbstractEnum.fir.kt b/compiler/testData/diagnostics/tests/enum/enumEntryInAbstractEnum.fir.kt new file mode 100644 index 00000000000..316e4b77074 --- /dev/null +++ b/compiler/testData/diagnostics/tests/enum/enumEntryInAbstractEnum.fir.kt @@ -0,0 +1,13 @@ +enum class EnumClass { + E1 { + override fun foo() = 1 + override val bar: String = "a" + }, + + E2 { + + }; + + abstract fun foo(): Int + abstract val bar: String +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/enum/enumEntryInAbstractEnum.kt b/compiler/testData/diagnostics/tests/enum/enumEntryInAbstractEnum.kt index 7981535c30f..b72a2d5f69b 100644 --- a/compiler/testData/diagnostics/tests/enum/enumEntryInAbstractEnum.kt +++ b/compiler/testData/diagnostics/tests/enum/enumEntryInAbstractEnum.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL enum class EnumClass { E1 { override fun foo() = 1