[FIR] Create checker for simple enum entries with missing overrides
Complex enum entries (those with bodies) with missing overrides are covered by an existing checker that checks all types of classes. But simple enum entries (those without bodies) were not covered and require a separate checker for missing overrides. #KT-58637 Fixed
This commit is contained in:
+10
@@ -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),
|
||||
|
||||
+6
@@ -1758,6 +1758,12 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
val missingDeclaration: KtCallableSymbol
|
||||
}
|
||||
|
||||
interface AbstractMemberNotImplementedByEnumEntry : KtFirDiagnostic<KtEnumEntry> {
|
||||
override val diagnosticClass get() = AbstractMemberNotImplementedByEnumEntry::class
|
||||
val enumEntry: KtSymbol
|
||||
val missingDeclarations: List<KtCallableSymbol>
|
||||
}
|
||||
|
||||
interface AbstractClassMemberNotImplemented : KtFirDiagnostic<KtClassOrObject> {
|
||||
override val diagnosticClass get() = AbstractClassMemberNotImplemented::class
|
||||
val classOrObject: KtClassLikeSymbol
|
||||
|
||||
+7
@@ -2110,6 +2110,13 @@ internal class AbstractMemberNotImplementedImpl(
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<KtClassOrObject>(firDiagnostic, token), KtFirDiagnostic.AbstractMemberNotImplemented
|
||||
|
||||
internal class AbstractMemberNotImplementedByEnumEntryImpl(
|
||||
override val enumEntry: KtSymbol,
|
||||
override val missingDeclarations: List<KtCallableSymbol>,
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<KtEnumEntry>(firDiagnostic, token), KtFirDiagnostic.AbstractMemberNotImplementedByEnumEntry
|
||||
|
||||
internal class AbstractClassMemberNotImplementedImpl(
|
||||
override val classOrObject: KtClassLikeSymbol,
|
||||
override val missingDeclaration: KtCallableSymbol,
|
||||
|
||||
+4
@@ -861,6 +861,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<FirClassSymbol<*>>("classOrObject")
|
||||
parameter<FirCallableSymbol<*>>("missingDeclaration")
|
||||
}
|
||||
val ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY by error<KtEnumEntry>(PositioningStrategy.DECLARATION_NAME) {
|
||||
parameter<FirEnumEntrySymbol>("enumEntry")
|
||||
parameter<List<FirCallableSymbol<*>>>("missingDeclarations")
|
||||
}
|
||||
val ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED by error<KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
|
||||
parameter<FirClassSymbol<*>>("classOrObject")
|
||||
parameter<FirCallableSymbol<*>>("missingDeclaration")
|
||||
|
||||
@@ -471,6 +471,7 @@ object FirErrors {
|
||||
val VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION by error2<KtClassOrObject, FirCallableSymbol<*>, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val CONFLICTING_INHERITED_MEMBERS by error2<KtClassOrObject, FirClassSymbol<*>, List<FirCallableSymbol<*>>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val ABSTRACT_MEMBER_NOT_IMPLEMENTED by error2<KtClassOrObject, FirClassSymbol<*>, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY by error2<KtEnumEntry, FirEnumEntrySymbol, List<FirCallableSymbol<*>>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED by error2<KtClassOrObject, FirClassSymbol<*>, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER by deprecationError2<KtClassOrObject, FirClassSymbol<*>, FirCallableSymbol<*>>(ProhibitInvisibleAbstractMethodsInSuperclasses, SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val AMBIGUOUS_ANONYMOUS_TYPE_INFERRED by error1<KtDeclaration, Collection<ConeKotlinType>>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
|
||||
+1
@@ -92,6 +92,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
get() = setOf(
|
||||
FirOverrideChecker,
|
||||
FirNotImplementedOverrideChecker,
|
||||
FirNotImplementedOverrideSimpleEnumEntryChecker,
|
||||
FirThrowableSubclassChecker,
|
||||
FirOpenMemberChecker,
|
||||
FirClassVarianceChecker,
|
||||
|
||||
+43
@@ -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<FirEnumEntry>().filter { it.initializer == null && it.source != null }
|
||||
if (enumEntries.isEmpty()) return
|
||||
|
||||
val enumScope = declaration.unsubstitutedScope(context)
|
||||
|
||||
val notImplemented = mutableListOf<FirCallableSymbol<*>>()
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
@@ -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}",
|
||||
|
||||
@@ -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<FirVariableSymbol<*>> {
|
||||
return mutableListOf<FirVariableSymbol<*>>().apply {
|
||||
processAllProperties(this::add)
|
||||
|
||||
@@ -2,7 +2,7 @@ package abstract
|
||||
|
||||
|
||||
enum class MyEnum() {
|
||||
INSTANCE;
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY!>INSTANCE<!>;
|
||||
//properties
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>val a: Int<!>
|
||||
val a1: Int = 1
|
||||
|
||||
@@ -6,7 +6,7 @@ enum class EnumImplementingTraitWithFun: T1 {
|
||||
E1 {
|
||||
override fun foo() {}
|
||||
},
|
||||
E2
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY!>E2<!>
|
||||
}
|
||||
|
||||
interface T2 {
|
||||
@@ -17,5 +17,5 @@ enum class EnumImplementingTraitWithVal: T2 {
|
||||
E1 {
|
||||
override val bar = 1
|
||||
},
|
||||
E2
|
||||
}
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY!>E2<!>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user