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
}
}
}
@@ -39,18 +39,18 @@ class CBarT<T> : IBarT<T> {
override val bar: T get() = null!!
}
class Test1 : Final(), IFoo by CFoo()
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION!>class Test1<!> : Final(), IFoo by CFoo()
class Test2 : Final(), IBar by CBar()
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION!>class Test2<!> : Final(), IBar by CBar()
class Test3 : Final(), IQux by CQux()
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION!>class Test3<!> : Final(), IQux by CQux()
class Test4 : Derived(), IFoo by CFoo()
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION!>class Test4<!> : Derived(), IFoo by CFoo()
class Test5 : Derived(), IBar by CBar()
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION!>class Test5<!> : Derived(), IBar by CBar()
class Test6 : Derived(), IQux by CQux()
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION!>class Test6<!> : Derived(), IQux by CQux()
class Test7 : Final(), IBarT<Int> by CBarT<Int>()
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION!>class Test7<!> : Final(), IBarT<Int> by CBarT<Int>()
class Test8 : Final(), IBarT<Int> by CBar()
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION!>class Test8<!> : Final(), IBarT<Int> by CBar()
@@ -6,7 +6,7 @@ open class IDerived1 : IBase1 {
override fun foo(): String = "1"
}
class Broken1(val b: IBase1) : IBase1 by b, IDerived1()
<!DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE!>class Broken1<!>(val b: IBase1) : IBase1 by b, IDerived1()
interface IBase2 {
val foo: Any
@@ -16,4 +16,4 @@ open class IDerived2 : IBase2 {
override val foo: String = "2"
}
class Broken2(val b: IBase2) : IBase2 by b, IDerived2()
<!DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE!>class Broken2<!>(val b: IBase2) : IBase2 by b, IDerived2()
@@ -1,19 +0,0 @@
public interface Base {
fun test() = "OK"
}
public interface Base2 : Base {
override fun test() = "OK2"
}
class Delegate : Base2
fun box(): String {
object : Base, Base2 by Delegate() {
}
object : Base2, Base by Delegate() {
}
return "OK"
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
public interface Base {
fun test() = "OK"
}
@@ -1,26 +0,0 @@
public interface Base {
var test: String
get() = "OK"
set(s: String) {
}
}
public interface Base2 : Base {
override var test: String
get() = "OK2"
set(value) {}
}
class Delegate : Base2 {
}
fun box(): String {
object : Base, Base2 by Delegate() {
}
object : Base2, Base by Delegate() {
}
return "OK"
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
public interface Base {
var test: String
get() = "OK"
@@ -23,19 +23,19 @@ class ImplAll : Base, Base2, Base3 {
}
fun box(): String {
object : Base2, Base3, Base by Impl() {
<!DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE!>object<!> : Base2, Base3, Base by Impl() {
}
object : Base2 by Impl2(), Base3, Base {
<!DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE!>object<!> : Base2 by Impl2(), Base3, Base {
}
object : Base2, Base3 by Impl3(), Base {
<!DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE!>object<!> : Base2, Base3 by Impl3(), Base {
}
object : Base2 by Impl2(), Base3 by Impl3(), Base by Impl() {
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>object<!> : Base2 by Impl2(), Base3 by Impl3(), Base by Impl() {
}
@@ -1,13 +0,0 @@
interface Base {
fun test() = "Base"
}
class Delegate : Base
abstract class Middle : Base {
override fun test() = "MyClass"
}
abstract class MyClass : Middle()
class A : MyClass(), Base by Delegate()
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
interface Base {
fun test() = "Base"
}
@@ -14,7 +14,7 @@ class Delegate : Derived {
public open class MyClass : Base by Delegate()
fun box(): String {
object : MyClass(), Derived by Delegate() {
<!MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>object<!> : MyClass(), Derived by Delegate() {
}
return "OK"
}
@@ -23,6 +23,6 @@ public abstract class MyClass : Base1, Base2 {
}
}
class A : MyClass(), Base1 by Delegate1(), Base1 by Delegate2() {
<!DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE!>class A<!> : MyClass(), Base1 by Delegate1(), Base1 by Delegate2() {
}
@@ -1,19 +0,0 @@
public interface Base {
fun getValue(): String
fun test() = getValue()
}
class Delegate : Base {
override fun getValue() = "Delegate"
}
public abstract class MyClass : Base {
override fun test(): String {
return "Class"
}
}
class A : MyClass(), Base by Delegate() {
override fun getValue() = "Delegate"
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
public interface Base {
fun getValue(): String
@@ -1,17 +0,0 @@
public interface Base {
val test: String
get() = "OK"
}
open class Delegate : Base {
override val test: String
get() = "OK"
}
fun box(): String {
object : Delegate(), Base by Delegate() {
}
return "OK"
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
public interface Base {
val test: String
get() = "OK"
@@ -10,4 +10,4 @@ interface B {
class C(f: A<String>): A<String> by f, B
class D(f: A<Int>): A<Int> by f, B
<!DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE!>class D<!>(f: A<Int>): A<Int> by f, B
@@ -965,6 +965,22 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.OVERRIDING_FINAL_MEMBER_BY_DELEGATION) { firDiagnostic ->
OverridingFinalMemberByDelegationImpl(
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a as FirCallableDeclaration),
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE) { firDiagnostic ->
DelegatedMemberHidesSupertypeOverrideImpl(
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a as FirCallableDeclaration),
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.b as FirCallableDeclaration),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.RETURN_TYPE_MISMATCH_ON_OVERRIDE) { firDiagnostic ->
ReturnTypeMismatchOnOverrideImpl(
firSymbolBuilder.buildSymbol(firDiagnostic.a as FirDeclaration),
@@ -690,6 +690,18 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val missingDeclaration: KtCallableSymbol
}
abstract class OverridingFinalMemberByDelegation : KtFirDiagnostic<KtClassOrObject>() {
override val diagnosticClass get() = OverridingFinalMemberByDelegation::class
abstract val delegatedDeclaration: KtCallableSymbol
abstract val overriddenDeclaration: KtCallableSymbol
}
abstract class DelegatedMemberHidesSupertypeOverride : KtFirDiagnostic<KtClassOrObject>() {
override val diagnosticClass get() = DelegatedMemberHidesSupertypeOverride::class
abstract val delegatedDeclaration: KtCallableSymbol
abstract val overriddenDeclaration: KtCallableSymbol
}
abstract class ReturnTypeMismatchOnOverride : KtFirDiagnostic<KtNamedDeclaration>() {
override val diagnosticClass get() = ReturnTypeMismatchOnOverride::class
abstract val function: KtSymbol
@@ -1105,6 +1105,24 @@ internal class ManyInterfacesMemberNotImplementedImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class OverridingFinalMemberByDelegationImpl(
override val delegatedDeclaration: KtCallableSymbol,
override val overriddenDeclaration: KtCallableSymbol,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.OverridingFinalMemberByDelegation(), KtAbstractFirDiagnostic<KtClassOrObject> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class DelegatedMemberHidesSupertypeOverrideImpl(
override val delegatedDeclaration: KtCallableSymbol,
override val overriddenDeclaration: KtCallableSymbol,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.DelegatedMemberHidesSupertypeOverride(), KtAbstractFirDiagnostic<KtClassOrObject> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class ReturnTypeMismatchOnOverrideImpl(
override val function: KtSymbol,
override val superFunction: KtSymbol,