[FIR] Report ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY on enum entries with initializer

#KT-59577 Fixed
This commit is contained in:
Kirill Rakhman
2023-09-22 13:10:45 +02:00
committed by Space Team
parent ef78d4b95a
commit 44a4498ee5
5 changed files with 46 additions and 4 deletions
@@ -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].
+3 -2
View File
@@ -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"
},
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>E2<!> {
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY!>E2<!> {
},
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>E3<!>();
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY!>E3<!>();
abstract fun foo(): Int
abstract val bar: String
@@ -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
}
@@ -0,0 +1,13 @@
enum class EnumClass {
E1 {
override fun foo() = 1
override val bar: String = "a"
},
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY!>E2<!> {
};
abstract fun foo(): Int
abstract val bar: String
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
enum class EnumClass {
E1 {
override fun foo() = 1