From 566dc434cc3be0e35e254bc95d6be01091c28e63 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Mon, 22 Mar 2021 12:58:58 +0300 Subject: [PATCH] FIR: introduce MANY_*_MEMBER_NOT_IMPLEMENTED diagnostic --- .../testData/resolve/incorrectSuperCall.kt | 2 +- .../FirNotImplementedOverrideChecker.kt | 52 +++++++++++++++++-- .../fir/symbols/impl/FirFunctionSymbol.kt | 8 ++- .../fir/symbols/impl/FirVariableSymbol.kt | 4 +- .../rendering/notImplementedMembers.fir.kt | 4 +- .../Delegation_ClashingFunctions.fir.kt | 12 ++--- .../Delegation_MultipleDelegates.fir.kt | 19 ------- .../Delegation_MultipleDelegates.kt | 1 + .../sameDelegationInHierarchy.fir.kt | 2 +- .../deprecated/deprecatedInheritance.fir.kt | 2 +- ...rrideDifferentDeclarationSignatures.fir.kt | 11 ---- ...eOverrideDifferentDeclarationSignatures.kt | 1 + .../override/ObjectDelegationManyImpl.fir.kt | 2 +- .../ParentInheritsManyImplementations.fir.kt | 17 ------ .../ParentInheritsManyImplementations.kt | 1 + .../tests/regressions/kt302.fir.kt | 13 ----- .../diagnostics/tests/regressions/kt302.kt | 1 + .../annotations/jvmDefault/superCall.fir.kt | 2 +- .../coroutines/mixingSuspendability.fir.kt | 2 +- 19 files changed, 73 insertions(+), 83 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/delegation/Delegation_MultipleDelegates.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/override/FakeOverrideDifferentDeclarationSignatures.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/override/ParentInheritsManyImplementations.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/regressions/kt302.fir.kt diff --git a/compiler/fir/analysis-tests/testData/resolve/incorrectSuperCall.kt b/compiler/fir/analysis-tests/testData/resolve/incorrectSuperCall.kt index 923a96486fc..246394e5511 100644 --- a/compiler/fir/analysis-tests/testData/resolve/incorrectSuperCall.kt +++ b/compiler/fir/analysis-tests/testData/resolve/incorrectSuperCall.kt @@ -11,7 +11,7 @@ open class B { open fun baz() {} } -class C : A, B() { +class C : A, B() { override fun foo() { super.foo() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt index dca1deebc5f..895a35b3aaa 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt @@ -16,11 +16,21 @@ import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass import org.jetbrains.kotlin.fir.analysis.checkers.modality import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope 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.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.reportOn +import org.jetbrains.kotlin.fir.containingClass import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.languageVersionSettings +import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionCallableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionOverrideFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionOverridePropertySymbol import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.isNullableAny import org.jetbrains.kotlin.util.OperatorNameConventions @@ -40,6 +50,7 @@ object FirNotImplementedOverrideChecker : FirClassChecker() { val classScope = declaration.unsubstitutedScope(context) val notImplementedSymbols = mutableListOf>() + val notImplementedIntersectionSymbols = mutableListOf>() val invisibleSymbols = mutableListOf>() val classPackage = declaration.symbol.classId.packageFqName @@ -64,6 +75,15 @@ object FirNotImplementedOverrideChecker : FirClassChecker() { for (name in classScope.getCallableNames()) { classScope.processFunctionsByName(name) { namedFunctionSymbol -> val simpleFunction = namedFunctionSymbol.fir + if (namedFunctionSymbol is FirIntersectionOverrideFunctionSymbol) { + if (namedFunctionSymbol.intersections.count { + (it.fir as FirCallableMemberDeclaration).modality != Modality.ABSTRACT + } > 1 && simpleFunction.getContainingClass(context) === declaration + ) { + notImplementedIntersectionSymbols += namedFunctionSymbol + return@processFunctionsByName + } + } if (!simpleFunction.shouldBeImplemented()) return@processFunctionsByName if (declaration is FirRegularClass && declaration.isData && simpleFunction.matchesDataClassSyntheticMemberSignatures) { return@processFunctionsByName @@ -79,6 +99,15 @@ object FirNotImplementedOverrideChecker : FirClassChecker() { } classScope.processPropertiesByName(name) { propertySymbol -> val property = propertySymbol.fir as? FirProperty ?: return@processPropertiesByName + if (propertySymbol is FirIntersectionOverridePropertySymbol) { + if (propertySymbol.intersections.count { + (it.fir as FirCallableMemberDeclaration).modality != Modality.ABSTRACT + } > 1 && property.getContainingClass(context) === declaration + ) { + notImplementedIntersectionSymbols += propertySymbol + return@processPropertiesByName + } + } if (!property.shouldBeImplemented()) return@processPropertiesByName if (property.isInvisible()) { @@ -92,17 +121,30 @@ object FirNotImplementedOverrideChecker : FirClassChecker() { if (notImplementedSymbols.isNotEmpty()) { val notImplemented = notImplementedSymbols.first().fir if (notImplemented.isFromInterfaceOrEnum(context)) { - reporter.reportOn(source, FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context) + reporter.reportOn(source, ABSTRACT_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context) } else { - reporter.reportOn(source, FirErrors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context) + reporter.reportOn(source, ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context) } } if (invisibleSymbols.isNotEmpty()) { val invisible = invisibleSymbols.first().fir if (context.session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitInvisibleAbstractMethodsInSuperclasses)) { - reporter.reportOn(source, FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER, declaration, invisible, context) + reporter.reportOn(source, INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER, declaration, invisible, context) } else { - reporter.reportOn(source, FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING, declaration, invisible, context) + reporter.reportOn(source, INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING, declaration, invisible, context) + } + } + 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 + } + ) { + reporter.reportOn(source, MANY_IMPL_MEMBER_NOT_IMPLEMENTED, declaration, notImplementedIntersection, context) + } else { + reporter.reportOn(source, MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED, declaration, notImplementedIntersection, context) } } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirFunctionSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirFunctionSymbol.kt index fd667321402..54201497423 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirFunctionSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirFunctionSymbol.kt @@ -25,10 +25,14 @@ open class FirNamedFunctionSymbol( callableId: CallableId, ) : FirFunctionSymbol(callableId) +interface FirIntersectionCallableSymbol { + val intersections: Collection> +} + class FirIntersectionOverrideFunctionSymbol( callableId: CallableId, - val intersections: Collection> -) : FirNamedFunctionSymbol(callableId) + override val intersections: Collection> +) : FirNamedFunctionSymbol(callableId), FirIntersectionCallableSymbol class FirConstructorSymbol( callableId: CallableId diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt index 30ded9f822e..9021b29c56f 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt @@ -29,8 +29,8 @@ open class FirPropertySymbol( class FirIntersectionOverridePropertySymbol( callableId: CallableId, - val intersections: Collection> -) : FirPropertySymbol(callableId) + override val intersections: Collection> +) : FirPropertySymbol(callableId), FirIntersectionCallableSymbol class FirBackingFieldSymbol(callableId: CallableId) : FirVariableSymbol(callableId) diff --git a/compiler/testData/diagnostics/tests/annotations/rendering/notImplementedMembers.fir.kt b/compiler/testData/diagnostics/tests/annotations/rendering/notImplementedMembers.fir.kt index 1aa58d30f08..1e7e9872d7b 100644 --- a/compiler/testData/diagnostics/tests/annotations/rendering/notImplementedMembers.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/rendering/notImplementedMembers.fir.kt @@ -44,5 +44,5 @@ interface GI : G { override fun a(@An arg: @An Int) {} } -class AG1(val a: A, val g: G) : A by a, G by g -class AG2() : AI, GI +class AG1(val a: A, val g: G) : A by a, G by g +class AG2() : AI, GI diff --git a/compiler/testData/diagnostics/tests/delegation/Delegation_ClashingFunctions.fir.kt b/compiler/testData/diagnostics/tests/delegation/Delegation_ClashingFunctions.fir.kt index 075ec0d7e46..dd22f583e75 100644 --- a/compiler/testData/diagnostics/tests/delegation/Delegation_ClashingFunctions.fir.kt +++ b/compiler/testData/diagnostics/tests/delegation/Delegation_ClashingFunctions.fir.kt @@ -10,9 +10,9 @@ interface Three { public fun foo(): String } -class Test123(val v1: One, val v2: Two, val v3: Three) : One by v1, Two by v2, Three by v3 { } -class Test132(val v1: One, val v2: Two, val v3: Three) : One by v1, Three by v3, Two by v2 { } -class Test312(val v1: One, val v2: Two, val v3: Three) : Three by v3, One by v1, Two by v2 { } -class Test321(val v1: One, val v2: Two, val v3: Three) : Three by v3, Two by v2, One by v1 { } -class Test231(val v1: One, val v2: Two, val v3: Three) : Two by v2, Three by v3, One by v1 { } -class Test213(val v1: One, val v2: Two, val v3: Three) : Two by v2, One by v1, Three by v3 { } \ No newline at end of file +class Test123(val v1: One, val v2: Two, val v3: Three) : One by v1, Two by v2, Three by v3 { } +class Test132(val v1: One, val v2: Two, val v3: Three) : One by v1, Three by v3, Two by v2 { } +class Test312(val v1: One, val v2: Two, val v3: Three) : Three by v3, One by v1, Two by v2 { } +class Test321(val v1: One, val v2: Two, val v3: Three) : Three by v3, Two by v2, One by v1 { } +class Test231(val v1: One, val v2: Two, val v3: Three) : Two by v2, Three by v3, One by v1 { } +class Test213(val v1: One, val v2: Two, val v3: Three) : Two by v2, One by v1, Three by v3 { } diff --git a/compiler/testData/diagnostics/tests/delegation/Delegation_MultipleDelegates.fir.kt b/compiler/testData/diagnostics/tests/delegation/Delegation_MultipleDelegates.fir.kt deleted file mode 100644 index 76eeed7b956..00000000000 --- a/compiler/testData/diagnostics/tests/delegation/Delegation_MultipleDelegates.fir.kt +++ /dev/null @@ -1,19 +0,0 @@ -// !DIAGNOSTICS: -CONFLICTING_JVM_DECLARATIONS -interface One { - public open fun foo() : Int - private fun boo() = 10 -} -interface Two { - public open fun foo() : Int -} - -interface OneImpl : One { - public override fun foo() = 1 -} -interface TwoImpl : Two { - public override fun foo() = 2 -} - -class Test1() : TwoImpl, OneImpl {} -class Test2(a : One) : One by a, Two {} -class Test3(a : One, b : Two) : Two by b, One by a {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegation/Delegation_MultipleDelegates.kt b/compiler/testData/diagnostics/tests/delegation/Delegation_MultipleDelegates.kt index 49639167e4e..93288159c5b 100644 --- a/compiler/testData/diagnostics/tests/delegation/Delegation_MultipleDelegates.kt +++ b/compiler/testData/diagnostics/tests/delegation/Delegation_MultipleDelegates.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -CONFLICTING_JVM_DECLARATIONS interface One { public open fun foo() : Int diff --git a/compiler/testData/diagnostics/tests/delegation/memberHidesSupertypeOverride/sameDelegationInHierarchy.fir.kt b/compiler/testData/diagnostics/tests/delegation/memberHidesSupertypeOverride/sameDelegationInHierarchy.fir.kt index 382b104432c..9df5bada552 100644 --- a/compiler/testData/diagnostics/tests/delegation/memberHidesSupertypeOverride/sameDelegationInHierarchy.fir.kt +++ b/compiler/testData/diagnostics/tests/delegation/memberHidesSupertypeOverride/sameDelegationInHierarchy.fir.kt @@ -9,7 +9,7 @@ class Delegate : Base { public open class MyClass : Base by Delegate() fun box(): String { - object : MyClass(), Base by Delegate() { + object : MyClass(), Base by Delegate() { } return "OK" } diff --git a/compiler/testData/diagnostics/tests/deprecated/deprecatedInheritance.fir.kt b/compiler/testData/diagnostics/tests/deprecated/deprecatedInheritance.fir.kt index b00759def84..a32de3b38b1 100644 --- a/compiler/testData/diagnostics/tests/deprecated/deprecatedInheritance.fir.kt +++ b/compiler/testData/diagnostics/tests/deprecated/deprecatedInheritance.fir.kt @@ -77,7 +77,7 @@ open class NWEH: NotDeprecated, WarningDeprecated, ErrorDeprecated, HiddenDeprec class WE2: WE() -class NWE2: WE(), NotDeprecated +class NWE2: WE(), NotDeprecated class NWE3: WE(), NotDeprecated { override fun f() { diff --git a/compiler/testData/diagnostics/tests/override/FakeOverrideDifferentDeclarationSignatures.fir.kt b/compiler/testData/diagnostics/tests/override/FakeOverrideDifferentDeclarationSignatures.fir.kt deleted file mode 100644 index 35f3a9059b6..00000000000 --- a/compiler/testData/diagnostics/tests/override/FakeOverrideDifferentDeclarationSignatures.fir.kt +++ /dev/null @@ -1,11 +0,0 @@ -interface A { - fun f(): String = "string" -} - -open class B { - open fun f(): CharSequence = "charSequence" -} - -class C : B(), A - -val obj: A = object : B(), A {} diff --git a/compiler/testData/diagnostics/tests/override/FakeOverrideDifferentDeclarationSignatures.kt b/compiler/testData/diagnostics/tests/override/FakeOverrideDifferentDeclarationSignatures.kt index aba4ace8df5..ebf944e3744 100644 --- a/compiler/testData/diagnostics/tests/override/FakeOverrideDifferentDeclarationSignatures.kt +++ b/compiler/testData/diagnostics/tests/override/FakeOverrideDifferentDeclarationSignatures.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL interface A { fun f(): String = "string" } diff --git a/compiler/testData/diagnostics/tests/override/ObjectDelegationManyImpl.fir.kt b/compiler/testData/diagnostics/tests/override/ObjectDelegationManyImpl.fir.kt index 2dd58530d21..95dbae75529 100644 --- a/compiler/testData/diagnostics/tests/override/ObjectDelegationManyImpl.fir.kt +++ b/compiler/testData/diagnostics/tests/override/ObjectDelegationManyImpl.fir.kt @@ -10,4 +10,4 @@ object Impl : D, E { override fun foo() {} } -val obj: D = object : D by Impl, E by Impl {} \ No newline at end of file +val obj: D = object : D by Impl, E by Impl {} diff --git a/compiler/testData/diagnostics/tests/override/ParentInheritsManyImplementations.fir.kt b/compiler/testData/diagnostics/tests/override/ParentInheritsManyImplementations.fir.kt deleted file mode 100644 index 1a64254694c..00000000000 --- a/compiler/testData/diagnostics/tests/override/ParentInheritsManyImplementations.fir.kt +++ /dev/null @@ -1,17 +0,0 @@ -package d - -interface A { - fun foo() = 1 -} - -interface B { - fun foo() = 2 -} - -open class C : A, B {} - -interface E { - fun foo(): Int -} - -class D : C() {} diff --git a/compiler/testData/diagnostics/tests/override/ParentInheritsManyImplementations.kt b/compiler/testData/diagnostics/tests/override/ParentInheritsManyImplementations.kt index 75d9920c5c9..6e6bfa47ddc 100644 --- a/compiler/testData/diagnostics/tests/override/ParentInheritsManyImplementations.kt +++ b/compiler/testData/diagnostics/tests/override/ParentInheritsManyImplementations.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL package d interface A { diff --git a/compiler/testData/diagnostics/tests/regressions/kt302.fir.kt b/compiler/testData/diagnostics/tests/regressions/kt302.fir.kt deleted file mode 100644 index b13c4b483a2..00000000000 --- a/compiler/testData/diagnostics/tests/regressions/kt302.fir.kt +++ /dev/null @@ -1,13 +0,0 @@ -// KT-302 Report an error when inheriting many implementations of the same member - -package kt302 - -interface A { - open fun foo() {} -} - -interface B { - open fun foo() {} -} - -class C : A, B {} //should be error here \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/kt302.kt b/compiler/testData/diagnostics/tests/regressions/kt302.kt index 299fd7fafae..9d1e0328baa 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt302.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt302.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // KT-302 Report an error when inheriting many implementations of the same member package kt302 diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCall.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCall.fir.kt index e9100064875..b9a9e3d0af0 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCall.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCall.fir.kt @@ -53,7 +53,7 @@ class ManySupers2: Foo2(), C { } } -class ManySupers3: Bar2(), C { +class ManySupers3: Bar2(), C { fun foo() { super.test() super.test() diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/mixingSuspendability.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/mixingSuspendability.fir.kt index 083722fdefb..1d9f1e9478a 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/mixingSuspendability.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/mixingSuspendability.fir.kt @@ -1,6 +1,6 @@ interface AsyncVal { suspend fun getVal(): Int = 1} interface SyncVal { fun getVal(): Int = 1 } -class MixSuspend : AsyncVal, SyncVal { +class MixSuspend : AsyncVal, SyncVal { }