FirNotImplementedOverrideChecker: check also anonymous objects / enums

This commit is contained in:
Mikhail Glukhikh
2021-03-24 11:23:59 +03:00
parent 82b8cc333e
commit 449a79151a
19 changed files with 44 additions and 64 deletions
+2 -2
View File
@@ -26,11 +26,11 @@ enum class EnumClass {
override val bar: String = "a"
},
E2 {
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>E2<!> {
},
E3();
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>E3<!>();
abstract fun foo(): Int
abstract val bar: String
@@ -28,16 +28,13 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
object FirNotImplementedOverrideChecker : FirClassChecker() {
override fun check(declaration: FirClass<*>, context: CheckerContext, reporter: DiagnosticReporter) {
// TODO: kt4763Property: reporting on `object` literal causes invalid error in test...FirDiagnosticHandler
if (declaration !is FirRegularClass) return
val source = declaration.source ?: return
if (source.kind is FirFakeSourceElementKind) return
val sourceKind = source.kind
if (sourceKind is FirFakeSourceElementKind && sourceKind != FirFakeSourceElementKind.EnumInitializer) return
val modality = declaration.modality()
if (modality == Modality.ABSTRACT || modality == Modality.SEALED) return
if (declaration.isExpect) return
if (declaration is FirRegularClass && declaration.isExpect) return
val classKind = declaration.classKind
// TODO: we should check enum entries (probably as anonymous objects, see above)
if (classKind == ClassKind.ANNOTATION_CLASS || classKind == ClassKind.ENUM_CLASS) return
val classScope = declaration.unsubstitutedScope(
@@ -70,7 +67,9 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
classScope.processFunctionsByName(name) { namedFunctionSymbol ->
val simpleFunction = namedFunctionSymbol.fir
if (!simpleFunction.shouldBeImplemented()) return@processFunctionsByName
if (declaration.isData && simpleFunction.matchesDataClassSyntheticMemberSignatures) return@processFunctionsByName
if (declaration is FirRegularClass && 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
@@ -94,7 +93,7 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
if (notImplementedSymbols.isNotEmpty()) {
val notImplemented = notImplementedSymbols.first().fir
if (notImplemented.isFromInterface(context)) {
if (notImplemented.isFromInterfaceOrEnum(context)) {
reporter.reportOn(source, FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)
} else {
reporter.reportOn(source, FirErrors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)
@@ -110,8 +109,8 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
}
}
private fun FirCallableDeclaration<*>.isFromInterface(context: CheckerContext): Boolean =
(getContainingClass(context) as? FirRegularClass)?.isInterface == true
private fun FirCallableDeclaration<*>.isFromInterfaceOrEnum(context: CheckerContext): Boolean =
(getContainingClass(context) as? FirRegularClass)?.let { it.isInterface || it.isEnumClass } == true
private val FirSimpleFunction.matchesDataClassSyntheticMemberSignatures: Boolean
get() = (this.name == OperatorNameConventions.EQUALS && matchesEqualsSignature) ||
@@ -532,7 +532,8 @@ class DeclarationsConverter(
fun convertObjectLiteral(objectLiteral: LighterASTNode): FirElement {
return withChildClassName(ANONYMOUS_OBJECT_NAME) {
buildAnonymousObject {
source = objectLiteral.toFirSourceElement()
val objectDeclaration = objectLiteral.getChildNodesByType(OBJECT_DECLARATION).first()
source = objectDeclaration.toFirSourceElement()
origin = FirDeclarationOrigin.Source
session = baseSession
classKind = ClassKind.OBJECT
@@ -551,7 +552,7 @@ class DeclarationsConverter(
var delegatedConstructorSource: FirLightSourceElement? = null
var delegateFields: List<FirField>? = null
objectLiteral.getChildNodesByType(OBJECT_DECLARATION).first().forEachChildren {
objectDeclaration.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
PRIMARY_CONSTRUCTOR -> primaryConstructor = it
@@ -636,7 +637,7 @@ class DeclarationsConverter(
annotations += modifiers.annotations
initializer = withChildClassName(enumEntryName) {
buildAnonymousObject {
source = this@buildEnumEntry.source
source = enumEntry.toFirSourceElement(FirFakeSourceElementKind.EnumInitializer)
session = baseSession
origin = FirDeclarationOrigin.Source
classKind = ClassKind.ENUM_ENTRY
@@ -894,7 +894,7 @@ open class RawFirBuilder(
val objectDeclaration = expression.objectDeclaration
return withChildClassName(ANONYMOUS_OBJECT_NAME) {
buildAnonymousObject {
source = expression.toFirSourceElement()
source = objectDeclaration.toFirSourceElement()
session = baseSession
origin = FirDeclarationOrigin.Source
classKind = ClassKind.OBJECT
@@ -258,6 +258,7 @@ class RawFirBuilderTotalKotlinTestCase : AbstractRawFirBuilderTestCase() {
it is KtAnnotatedExpression ||
it is KtWhenConditionWithExpression ||
it is KtFinallySection ||
it is KtObjectLiteralExpression ||
// TODO: KT-24089 (support of dynamic)
it is KtDynamicType ||
// NB: KtAnnotation is processed via its KtAnnotationEntries