FIR: Rework FirNotImplementedOverrideChecker around delegated members reporting

This commit is contained in:
Denis.Zharkov
2021-06-29 18:10:28 +03:00
committed by TeamCityServer
parent a213ee0e01
commit a77cbb8f63
13 changed files with 132 additions and 97 deletions
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.firClassLike
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.impl.multipleDelegatesWithTheSameSignature
import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
import org.jetbrains.kotlin.fir.symbols.impl.*
@@ -438,6 +439,11 @@ fun FirCallableMemberDeclaration.isVisibleInClass(parentClass: FirClass): Boolea
fun FirCallableMemberDeclaration.getImplementationStatus(sessionHolder: SessionHolder, parentClass: FirClass): ImplementationStatus {
val containingClass = getContainingClass(sessionHolder)
val symbol = this.symbol
if (this.multipleDelegatesWithTheSameSignature == true && containingClass == parentClass) {
return ImplementationStatus.AMBIGUOUSLY_INHERITED
}
if (symbol is FirIntersectionCallableSymbol) {
if (containingClass === parentClass && symbol.subjectToManyNotImplemented(sessionHolder)) {
return ImplementationStatus.AMBIGUOUSLY_INHERITED
@@ -12,23 +12,26 @@ import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
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.*
import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenMembers
import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData
import org.jetbrains.kotlin.fir.scopes.impl.multipleDelegatesWithTheSameSignature
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionCallableSymbol
import org.jetbrains.kotlin.fir.unwrapFakeOverrides
@@ -50,10 +53,39 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
val notImplementedSymbols = mutableListOf<FirCallableSymbol<*>>()
val notImplementedIntersectionSymbols = mutableListOf<FirCallableSymbol<*>>()
val manyImplementationsDelegationSymbols = mutableListOf<FirCallableSymbol<*>>()
val delegationOverrideOfFinal = mutableListOf<Pair<FirCallableSymbol<*>, FirCallableSymbol<*>>>()
val delegationOverrideOfOpen = mutableListOf<Pair<FirCallableSymbol<*>, FirCallableSymbol<*>>>()
val invisibleSymbols = mutableListOf<FirCallableSymbol<*>>()
fun collectSymbol(symbol: FirCallableSymbol<*>) {
val fir = symbol.fir as? FirCallableMemberDeclaration ?: return
if (fir.delegatedWrapperData != null) {
val directOverriddenMembers = classScope.getDirectOverriddenMembers(
symbol,
unwrapIntersectionAndSubstitutionOverride = true
)
val delegatedTo = fir.delegatedWrapperData!!.wrapped.unwrapFakeOverrides()
if (symbol.fir.multipleDelegatesWithTheSameSignature == true) {
manyImplementationsDelegationSymbols.add(symbol)
}
val firstFinal = directOverriddenMembers.firstOrNull { it.fir.isFinal }
val firstOpen = directOverriddenMembers.firstOrNull { it.fir.isOpen && delegatedTo != it.unwrapFakeOverrides().fir }
when {
firstFinal != null ->
delegationOverrideOfFinal.add(symbol to firstFinal)
firstOpen != null ->
delegationOverrideOfOpen.add(symbol to firstOpen)
}
return
}
when (fir.getImplementationStatus(context.sessionHolder, declaration)) {
ImplementationStatus.AMBIGUOUSLY_INHERITED -> notImplementedIntersectionSymbols.add(symbol)
ImplementationStatus.NOT_IMPLEMENTED -> when {
@@ -87,59 +119,48 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
reporter.reportOn(source, INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING, declaration, invisible, context)
}
}
if (notImplementedIntersectionSymbols.isNotEmpty()) {
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
manyImplementationsDelegationSymbols.firstOrNull()?.let {
reporter.reportOn(source, MANY_IMPL_MEMBER_NOT_IMPLEMENTED, declaration, it.fir, context)
}
delegationOverrideOfFinal.firstOrNull()?.let { (delegated, final) ->
reporter.reportOn(
source,
OVERRIDING_FINAL_MEMBER_BY_DELEGATION,
delegated.fir,
final.fir,
context
)
}
delegationOverrideOfOpen.firstOrNull()?.let { (delegated, open) ->
reporter.reportOn(
source,
DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE,
delegated.fir,
open.fir,
context
)
}
if (manyImplementationsDelegationSymbols.isEmpty() && 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
}
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
) {
reporter.reportOn(source, MANY_IMPL_MEMBER_NOT_IMPLEMENTED, declaration, notImplementedIntersection, context)
} else {
reporter.reportOn(
source,
FirErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED,
declaration,
notImplementedIntersection,
context
)
}
}
}
@@ -5,8 +5,11 @@
package org.jetbrains.kotlin.fir.scopes
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
import org.jetbrains.kotlin.fir.isIntersectionOverride
import org.jetbrains.kotlin.fir.originalForSubstitutionOverride
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.name.Name
@@ -140,24 +143,56 @@ inline fun FirTypeScope.processDirectlyOverriddenProperties(
processor(overridden)
}
fun FirTypeScope.getDirectOverriddenFunctions(function: FirNamedFunctionSymbol): List<FirNamedFunctionSymbol> {
fun FirTypeScope.getDirectOverriddenMembers(
member: FirCallableSymbol<*>,
unwrapIntersectionAndSubstitutionOverride: Boolean = false,
): List<FirCallableSymbol<out FirCallableMemberDeclaration>> =
when (member) {
is FirNamedFunctionSymbol -> getDirectOverriddenFunctions(member, unwrapIntersectionAndSubstitutionOverride)
is FirPropertySymbol -> getDirectOverriddenProperties(member, unwrapIntersectionAndSubstitutionOverride)
else -> emptyList()
}
fun FirTypeScope.getDirectOverriddenFunctions(
function: FirNamedFunctionSymbol,
unwrapIntersectionAndSubstitutionOverride: Boolean = false,
): List<FirNamedFunctionSymbol> {
val overriddenFunctions = mutableSetOf<FirNamedFunctionSymbol>()
processDirectlyOverriddenFunctions(function) {
overriddenFunctions.add(it)
overriddenFunctions.addOverridden(it, unwrapIntersectionAndSubstitutionOverride)
ProcessorAction.NEXT
}
return overriddenFunctions.toList()
}
fun FirTypeScope.getDirectOverriddenProperties(property: FirPropertySymbol): List<FirPropertySymbol> {
fun FirTypeScope.getDirectOverriddenProperties(
property: FirPropertySymbol,
unwrapIntersectionAndSubstitutionOverride: Boolean = false,
): List<FirPropertySymbol> {
val overriddenProperties = mutableSetOf<FirPropertySymbol>()
processDirectlyOverriddenProperties(property) {
overriddenProperties.add(it)
overriddenProperties.addOverridden(it, unwrapIntersectionAndSubstitutionOverride)
ProcessorAction.NEXT
}
return overriddenProperties.toList()
}
private inline fun <reified D : FirCallableSymbol<*>> MutableCollection<D>.addOverridden(
symbol: D,
unwrapIntersectionAndSubstitutionOverride: Boolean
) {
if (unwrapIntersectionAndSubstitutionOverride) {
if (symbol is FirIntersectionCallableSymbol) {
@Suppress("UNCHECKED_CAST")
addAll(symbol.intersections as Collection<D>)
} else {
add(symbol.originalForSubstitutionOverride ?: symbol)
}
} else {
add(symbol)
}
}
@@ -51,7 +51,7 @@ abstract class Test8 : IGeneric<String> by CGeneric<String>(), IInt
abstract <!MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>class Test10<!> : IInt by CInt(), IStr by CStr(), IAny by CAny()
abstract <!DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE!>class Test11<!> : IInt, IStr by CStr(), IAny by CAny()
abstract <!MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>class Test11<!> : IInt, IStr by CStr(), IAny by CAny()
abstract class Test12 : IInt, IStr, IAny by CAny()
@@ -53,7 +53,7 @@ abstract class Test8 : IGeneric<String> by CGeneric<String>(), IInt
abstract <!MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>class Test10<!> : IInt by CInt(), IStr by CStr(), IAny by CAny()
abstract <!DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE!>class Test11<!> : IInt, IStr by CStr(), IAny by CAny()
abstract <!MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>class Test11<!> : IInt, IStr by CStr(), IAny by CAny()
abstract class Test12 : IInt, IStr, IAny by CAny()
@@ -13,5 +13,5 @@ object AImpl : IA {
open class C : IA by AImpl, IB
class D : C() {
override fun foo(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>Double<!> = 3.14
override fun foo(): Double = 3.14
}
@@ -35,7 +35,7 @@ fun box(): String {
}
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>object<!> : Base2 by Impl2(), Base3 by Impl3(), Base by Impl() {
<!DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE, MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>object<!> : Base2 by Impl2(), Base3 by Impl3(), Base by Impl() {
}
@@ -1,16 +0,0 @@
public interface Base {
fun test() = "Base"
}
class Delegate : Base {
override fun test() = "Base"
}
public open class MyClass : Base by Delegate()
fun box(): String {
<!MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>object<!> : MyClass(), Base by Delegate() {
}
return "OK"
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
public interface Base {
fun test() = "Base"
}
@@ -14,7 +14,7 @@ class Delegate : Derived {
public open class MyClass : Base by Delegate()
fun box(): String {
<!MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>object<!> : MyClass(), Derived by Delegate() {
<!DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE!>object<!> : MyClass(), Derived by Delegate() {
}
return "OK"
}
@@ -22,6 +22,6 @@ public abstract class MyClass : Base1, Base2 {
}
}
<!DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE!>class A<!> : MyClass(), Base1 by Delegate1(), <!SUPERTYPE_APPEARS_TWICE!>Base1<!> by <!TYPE_MISMATCH!>Delegate2()<!> {
<!DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE, MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>class A<!> : MyClass(), Base1 by Delegate1(), <!SUPERTYPE_APPEARS_TWICE!>Base1<!> by <!TYPE_MISMATCH!>Delegate2()<!> {
}
@@ -1,13 +0,0 @@
interface D {
fun foo()
}
interface E {
fun foo() {}
}
object Impl : D, E {
override fun foo() {}
}
val obj: D = <!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>object<!> : D by Impl, E by Impl {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
interface D {
fun foo()
}