FIR: introduce delegated & overridden conflict checks
This commit is contained in:
+8
@@ -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)
|
||||
|
||||
+53
-9
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -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()
|
||||
|
||||
+2
-2
@@ -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()
|
||||
|
||||
-19
@@ -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
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
public interface Base {
|
||||
fun test() = "OK"
|
||||
}
|
||||
|
||||
-26
@@ -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
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
public interface Base {
|
||||
var test: String
|
||||
get() = "OK"
|
||||
|
||||
+4
-4
@@ -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() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
-13
@@ -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
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
interface Base {
|
||||
fun test() = "Base"
|
||||
}
|
||||
|
||||
+1
-1
@@ -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"
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -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() {
|
||||
|
||||
}
|
||||
-19
@@ -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
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
public interface Base {
|
||||
fun getValue(): String
|
||||
|
||||
|
||||
Vendored
-17
@@ -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
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
public interface Base {
|
||||
val test: String
|
||||
get() = "OK"
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+16
@@ -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),
|
||||
|
||||
+12
@@ -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
|
||||
|
||||
+18
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user