FIR: introduce delegated & overridden conflict checks

This commit is contained in:
Mikhail Glukhikh
2021-03-23 15:13:30 +03:00
parent 566dc434cc
commit 42d53dd954
22 changed files with 131 additions and 120 deletions
@@ -336,6 +336,14 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
parameter<FirClass<*>>("classOrObject")
parameter<FirCallableDeclaration<*>>("missingDeclaration")
}
val OVERRIDING_FINAL_MEMBER_BY_DELEGATION by error<FirSourceElement, KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
parameter<FirCallableDeclaration<*>>("delegatedDeclaration")
parameter<FirCallableDeclaration<*>>("overriddenDeclaration")
}
val DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE by warning<FirSourceElement, KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
parameter<FirCallableDeclaration<*>>("delegatedDeclaration")
parameter<FirCallableDeclaration<*>>("overriddenDeclaration")
}
val RETURN_TYPE_MISMATCH_ON_OVERRIDE by error<FirSourceElement, KtNamedDeclaration>(PositioningStrategy.DECLARATION_RETURN_TYPE) {
parameter<FirMemberDeclaration>("function")
@@ -225,6 +225,8 @@ object FirErrors {
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING by warning2<FirSourceElement, KtClassOrObject, FirClass<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
val MANY_IMPL_MEMBER_NOT_IMPLEMENTED by error2<FirSourceElement, KtClassOrObject, FirClass<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
val MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED by error2<FirSourceElement, KtClassOrObject, FirClass<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
val OVERRIDING_FINAL_MEMBER_BY_DELEGATION by error2<FirSourceElement, KtClassOrObject, FirCallableDeclaration<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
val DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE by warning2<FirSourceElement, KtClassOrObject, FirCallableDeclaration<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
val RETURN_TYPE_MISMATCH_ON_OVERRIDE by error2<FirSourceElement, KtNamedDeclaration, FirMemberDeclaration, FirMemberDeclaration>(SourceElementPositioningStrategies.DECLARATION_RETURN_TYPE)
val PROPERTY_TYPE_MISMATCH_ON_OVERRIDE by error2<FirSourceElement, KtNamedDeclaration, FirMemberDeclaration, FirMemberDeclaration>(SourceElementPositioningStrategies.DECLARATION_RETURN_TYPE)
val VAR_TYPE_MISMATCH_ON_OVERRIDE by error2<FirSourceElement, KtNamedDeclaration, FirMemberDeclaration, FirMemberDeclaration>(SourceElementPositioningStrategies.DECLARATION_RETURN_TYPE)
@@ -18,10 +18,12 @@ import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OVERRIDING_FINAL_MEMBER_BY_DELEGATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.*
@@ -135,16 +137,58 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
}
}
if (notImplementedIntersectionSymbols.isNotEmpty()) {
val notImplementedIntersectionSymbol = notImplementedIntersectionSymbols.first()
val notImplementedIntersection = notImplementedIntersectionSymbol.fir
val intersections = (notImplementedIntersectionSymbol as FirIntersectionCallableSymbol).intersections
if (intersections.any {
(it.containingClass()?.toSymbol(context.session)?.fir as? FirRegularClass)?.classKind == ClassKind.CLASS
var overridingFinalByDelegationReported = false
var manyMemberNotImplementedReported = false
var delegatedHidesSupertypeReported = false
for (notImplementedIntersectionSymbol in notImplementedIntersectionSymbols) {
val notImplementedIntersection = notImplementedIntersectionSymbol.fir
val intersections = (notImplementedIntersectionSymbol as FirIntersectionCallableSymbol).intersections
val delegatedIntersected = intersections.find {
val fir = it.fir as FirCallableMemberDeclaration
fir.origin == FirDeclarationOrigin.Delegated
}
) {
reporter.reportOn(source, MANY_IMPL_MEMBER_NOT_IMPLEMENTED, declaration, notImplementedIntersection, context)
} else {
reporter.reportOn(source, MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED, declaration, notImplementedIntersection, context)
if (delegatedIntersected != null) {
val finalIntersected = intersections.find { (it.fir as FirCallableMemberDeclaration).modality == Modality.FINAL }
if (finalIntersected != null) {
if (!overridingFinalByDelegationReported) {
reporter.reportOn(
source,
OVERRIDING_FINAL_MEMBER_BY_DELEGATION,
delegatedIntersected.fir,
finalIntersected.fir,
context
)
overridingFinalByDelegationReported = true
}
continue
}
val notDelegatedIntersected = intersections.firstOrNull {
(it.fir as FirCallableMemberDeclaration).origin != FirDeclarationOrigin.Delegated
}
if (notDelegatedIntersected != null) {
if (!delegatedHidesSupertypeReported) {
reporter.reportOn(
source,
DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE,
delegatedIntersected.fir,
notDelegatedIntersected.fir,
context
)
delegatedHidesSupertypeReported = true
}
continue
}
}
if (manyMemberNotImplementedReported) continue
if (intersections.any {
(it.containingClass()?.toSymbol(context.session)?.fir as? FirRegularClass)?.classKind == ClassKind.CLASS
}
) {
reporter.reportOn(source, MANY_IMPL_MEMBER_NOT_IMPLEMENTED, declaration, notImplementedIntersection, context)
} else {
reporter.reportOn(source, MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED, declaration, notImplementedIntersection, context)
}
manyMemberNotImplementedReported = true
}
}
}