diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index cb3dbea82f1..4da5a350e6c 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -392,6 +392,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.ABSTRACT_SUPER_CALL_WARNING) { firDiagnostic -> + AbstractSuperCallWarningImpl( + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.INSTANCE_ACCESS_BEFORE_SUPER_CALL) { firDiagnostic -> InstanceAccessBeforeSuperCallImpl( firDiagnostic.a, diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index ba968aeb275..858671948fe 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -307,6 +307,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = AbstractSuperCall::class } + abstract class AbstractSuperCallWarning : KtFirDiagnostic() { + override val diagnosticClass get() = AbstractSuperCallWarning::class + } + abstract class InstanceAccessBeforeSuperCall : KtFirDiagnostic() { override val diagnosticClass get() = InstanceAccessBeforeSuperCall::class abstract val target: String diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 01035e38ea1..f799915f5ac 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -356,6 +356,11 @@ internal class AbstractSuperCallImpl( override val token: ValidityToken, ) : KtFirDiagnostic.AbstractSuperCall(), KtAbstractFirDiagnostic +internal class AbstractSuperCallWarningImpl( + override val firDiagnostic: KtPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.AbstractSuperCallWarning(), KtAbstractFirDiagnostic + internal class InstanceAccessBeforeSuperCallImpl( override val target: String, override val firDiagnostic: KtPsiDiagnostic, diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index b8be619eb90..7873b2ec537 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -18587,6 +18587,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented_15.kt"); } + @Test + @TestMetadata("abstractFakeOverrideSuperCall.kt") + public void testAbstractFakeOverrideSuperCall() throws Exception { + runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.kt"); + } + + @Test + @TestMetadata("abstractFakeOverrideSuperCallForbidden.kt") + public void testAbstractFakeOverrideSuperCallForbidden() throws Exception { + runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCallForbidden.kt"); + } + @Test @TestMetadata("abstractVsAbstract.kt") public void testAbstractVsAbstract() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 490ee6e461c..3055c46dc72 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -18587,6 +18587,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented_15.kt"); } + @Test + @TestMetadata("abstractFakeOverrideSuperCall.kt") + public void testAbstractFakeOverrideSuperCall() throws Exception { + runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.kt"); + } + + @Test + @TestMetadata("abstractFakeOverrideSuperCallForbidden.kt") + public void testAbstractFakeOverrideSuperCallForbidden() throws Exception { + runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCallForbidden.kt"); + } + @Test @TestMetadata("abstractVsAbstract.kt") public void testAbstractVsAbstract() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index 434b57649cb..f7dbefedf24 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -18587,6 +18587,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented_15.kt"); } + @Test + @TestMetadata("abstractFakeOverrideSuperCall.kt") + public void testAbstractFakeOverrideSuperCall() throws Exception { + runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.kt"); + } + + @Test + @TestMetadata("abstractFakeOverrideSuperCallForbidden.kt") + public void testAbstractFakeOverrideSuperCallForbidden() throws Exception { + runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCallForbidden.kt"); + } + @Test @TestMetadata("abstractVsAbstract.kt") public void testAbstractVsAbstract() throws Exception { diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 0b2f505e155..ac3badaf97e 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -149,6 +149,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val SUPER_IS_NOT_AN_EXPRESSION by error(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) val SUPER_NOT_AVAILABLE by error(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) val ABSTRACT_SUPER_CALL by error(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) + val ABSTRACT_SUPER_CALL_WARNING by warning(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) val INSTANCE_ACCESS_BEFORE_SUPER_CALL by error { parameter("target") } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index fea7433e511..f232750c90a 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -165,6 +165,7 @@ object FirErrors { val SUPER_IS_NOT_AN_EXPRESSION by error0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val SUPER_NOT_AVAILABLE by error0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val ABSTRACT_SUPER_CALL by error0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) + val ABSTRACT_SUPER_CALL_WARNING by warning0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val INSTANCE_ACCESS_BEFORE_SUPER_CALL by error1() // Supertypes diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirAbstractSuperCallChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirAbstractSuperCallChecker.kt index 4101f315bf1..1cd34a24788 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirAbstractSuperCallChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirAbstractSuperCallChecker.kt @@ -5,12 +5,14 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.findClosest import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.classKind import org.jetbrains.kotlin.fir.containingClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.utils.isAbstract @@ -18,6 +20,7 @@ import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol import org.jetbrains.kotlin.fir.references.FirSuperReference import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -37,8 +40,22 @@ object FirAbstractSuperCallChecker : FirQualifiedAccessExpressionChecker() { val containingClassSymbol = declarationSymbol.containingClass()?.toSymbol(context.session) as? FirRegularClassSymbol ?: return - if (containingClassSymbol.isAbstract && declarationSymbol.isAbstract) { - reporter.reportOn(expression.calleeReference.source, FirErrors.ABSTRACT_SUPER_CALL, context) + if (containingClassSymbol.isAbstract) { + if (declarationSymbol.isAbstract) { + reporter.reportOn(expression.calleeReference.source, FirErrors.ABSTRACT_SUPER_CALL, context) + } + if (declarationSymbol is FirIntersectionCallableSymbol) { + val symbolFromBaseClass = declarationSymbol.intersections.firstOrNull { + it.containingClass()?.toSymbol(context.session)?.classKind != ClassKind.INTERFACE + } + if (symbolFromBaseClass?.isAbstract == true) { + if (context.languageVersionSettings.supportsFeature(LanguageFeature.ForbidSuperDelegationToAbstractFakeOverride)) { + reporter.reportOn(expression.calleeReference.source, FirErrors.ABSTRACT_SUPER_CALL, context) + } else { + reporter.reportOn(expression.calleeReference.source, FirErrors.ABSTRACT_SUPER_CALL_WARNING, context) + } + } + } } } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index ec30430801b..a56a81e8c53 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -45,6 +45,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_PROPERTY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_PROPERTY_WITH_INITIALIZER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_PROPERTY_WITH_SETTER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_SUPER_CALL +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_SUPER_CALL_WARNING import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACCESSOR_FOR_DELEGATED_PROPERTY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS @@ -642,6 +643,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { map.put(SUPER_IS_NOT_AN_EXPRESSION, "Super cannot be a callee") map.put(SUPER_NOT_AVAILABLE, "No supertypes are accessible in this context") map.put(ABSTRACT_SUPER_CALL, "Abstract member cannot be accessed directly") + map.put(ABSTRACT_SUPER_CALL_WARNING, "Abstract fake override member access is deprecated") map.put( INSTANCE_ACCESS_BEFORE_SUPER_CALL, "Cannot access ''{0}'' before superclass constructor has been called", diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 19ac37634de..cf5e07a8679 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -933,6 +933,7 @@ public interface Errors { DiagnosticFactory0 SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 AMBIGUOUS_SUPER = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 ABSTRACT_SUPER_CALL = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 ABSTRACT_SUPER_CALL_WARNING = DiagnosticFactory0.create(WARNING); DiagnosticFactory0 NOT_A_SUPERTYPE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER = DiagnosticFactory0.create(WARNING); DiagnosticFactory1 QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index e11b04f53f4..077f874c95c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -491,6 +491,7 @@ public class DefaultErrorMessages { MAP.put(SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE, "Superclass is not accessible from interface"); MAP.put(AMBIGUOUS_SUPER, "Many supertypes available, please specify the one you mean in angle brackets, e.g. 'super'"); MAP.put(ABSTRACT_SUPER_CALL, "Abstract member cannot be accessed directly"); + MAP.put(ABSTRACT_SUPER_CALL_WARNING, "Abstract fake override member access is deprecated"); MAP.put(NOT_A_SUPERTYPE, "Not an immediate supertype"); MAP.put(TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER, "Type arguments do not need to be specified in a 'super' qualifier"); MAP.put(QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE, "Explicitly qualified supertype is extended by another supertype ''{0}''", RENDER_TYPE); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt index 2d4d4a27139..843c82bf358 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt @@ -77,6 +77,13 @@ class DiagnosticReporterByTrackingStrategy( ) InstantiationOfAbstractClass::class.java -> tracingStrategy.instantiationOfAbstractClass(trace) AbstractSuperCall::class.java -> tracingStrategy.abstractSuperCall(trace) + AbstractFakeOverrideSuperCall::class.java -> { + if (context.languageVersionSettings.supportsFeature(LanguageFeature.ForbidSuperDelegationToAbstractFakeOverride)) { + tracingStrategy.abstractSuperCall(trace) + } else { + tracingStrategy.abstractFakeOverrideSuperCall(trace) + } + } NonApplicableCallForBuilderInferenceDiagnostic::class.java -> { val reportOn = (diagnostic as NonApplicableCallForBuilderInferenceDiagnostic).kotlinCall trace.reportDiagnosticOnce(NON_APPLICABLE_CALL_FOR_BUILDER_INFERENCE.on(reportOn.psiKotlinCall.psiCall.callElement)) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java index 615bc25b188..66e920b8053 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java @@ -142,6 +142,11 @@ public abstract class AbstractTracingStrategy implements TracingStrategy { trace.report(ABSTRACT_SUPER_CALL.on(reference)); } + @Override + public void abstractFakeOverrideSuperCall(@NotNull BindingTrace trace) { + trace.report(ABSTRACT_SUPER_CALL_WARNING.on(reference)); + } + @Override public void nestedClassAccessViaInstanceReference( @NotNull BindingTrace trace, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TracingStrategy.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TracingStrategy.java index 3f1389d1378..3b01a0351e5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TracingStrategy.java @@ -148,6 +148,10 @@ public interface TracingStrategy { void abstractSuperCall(@NotNull BindingTrace trace); + default void abstractFakeOverrideSuperCall(@NotNull BindingTrace trace) { + abstractSuperCall(trace); + } + void nestedClassAccessViaInstanceReference( @NotNull BindingTrace trace, @NotNull ClassDescriptor classDescriptor, diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index 159a6175bbe..8ddd12ebde6 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.ContextReceiverAmbiguity import org.jetbrains.kotlin.resolve.calls.tower.InfixCallNoInfixModifier import org.jetbrains.kotlin.resolve.calls.tower.InvokeConventionCallNoOperatorModifier import org.jetbrains.kotlin.resolve.calls.tower.VisibilityError +import org.jetbrains.kotlin.resolve.descriptorUtil.isInsideInterface import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf @@ -809,8 +810,17 @@ internal object CheckSuperExpressionCallPart : ResolutionPart() { val candidateDescriptor = resolvedCall.candidateDescriptor if (callComponents.statelessCallbacks.isSuperExpression(resolvedCall.dispatchReceiverArgument)) { - if (candidateDescriptor is MemberDescriptor && candidateDescriptor.modality == Modality.ABSTRACT) { - addDiagnostic(AbstractSuperCall) + if (candidateDescriptor is CallableMemberDescriptor) { + if (candidateDescriptor.modality == Modality.ABSTRACT) { + addDiagnostic(AbstractSuperCall) + } + if (candidateDescriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE && + candidateDescriptor.overriddenDescriptors.size > 1 + ) { + if (candidateDescriptor.overriddenDescriptors.firstOrNull { !it.isInsideInterface }?.modality == Modality.ABSTRACT) { + addDiagnostic(AbstractFakeOverrideSuperCall) + } + } } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt index 9230b276926..437a2fc9a8b 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt @@ -208,6 +208,12 @@ object AbstractSuperCall : KotlinCallDiagnostic(RUNTIME_ERROR) { } } +object AbstractFakeOverrideSuperCall : KotlinCallDiagnostic(RUNTIME_ERROR) { + override fun report(reporter: DiagnosticReporter) { + reporter.onCall(this) + } +} + class SuperAsExtensionReceiver(val receiver: SimpleKotlinCallArgument) : KotlinCallDiagnostic(RUNTIME_ERROR) { override fun report(reporter: DiagnosticReporter) { reporter.onCallReceiver(receiver, this) diff --git a/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.kt b/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.kt new file mode 100644 index 00000000000..cafd2b38996 --- /dev/null +++ b/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.kt @@ -0,0 +1,26 @@ +// FIR_IDENTICAL +// !LANGUAGE: -ForbidSuperDelegationToAbstractFakeOverride +interface Foo { + fun check(): String = "OK" +} +abstract class Base { + abstract fun check(): String +} +abstract class Derived : Base(), Foo + +class Derived2 : Derived() { + override fun check(): String { + super.check() + return super.check() + } +} + +abstract class A { + abstract override fun hashCode(): Int +} + +interface I + +class B : A(), I { // I is necessary here + override fun hashCode() = super.hashCode() +} diff --git a/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.txt b/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.txt new file mode 100644 index 00000000000..206b633a85d --- /dev/null +++ b/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.txt @@ -0,0 +1,52 @@ +package + +public abstract class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class B : A, I { + public constructor B() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class Base { + public constructor Base() + public abstract fun check(): kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class Derived : Base, Foo { + public constructor Derived() + public open override /*2*/ /*fake_override*/ fun check(): kotlin.String + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Derived2 : Derived { + public constructor Derived2() + public open override /*1*/ fun check(): kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Foo { + public open fun check(): kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface I { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCallForbidden.kt b/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCallForbidden.kt new file mode 100644 index 00000000000..357d95abf82 --- /dev/null +++ b/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCallForbidden.kt @@ -0,0 +1,26 @@ +// FIR_IDENTICAL +// !LANGUAGE: +ForbidSuperDelegationToAbstractFakeOverride +interface Foo { + fun check(): String = "OK" +} +abstract class Base { + abstract fun check(): String +} +abstract class Derived : Base(), Foo + +class Derived2 : Derived() { + override fun check(): String { + super.check() + return super.check() + } +} + +abstract class A { + abstract override fun hashCode(): Int +} + +interface I + +class B : A(), I { // I is necessary here + override fun hashCode() = super.hashCode() +} diff --git a/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCallForbidden.txt b/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCallForbidden.txt new file mode 100644 index 00000000000..206b633a85d --- /dev/null +++ b/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCallForbidden.txt @@ -0,0 +1,52 @@ +package + +public abstract class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class B : A, I { + public constructor B() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class Base { + public constructor Base() + public abstract fun check(): kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class Derived : Base, Foo { + public constructor Derived() + public open override /*2*/ /*fake_override*/ fun check(): kotlin.String + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Derived2 : Derived { + public constructor Derived2() + public open override /*1*/ fun check(): kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Foo { + public open fun check(): kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface I { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 9b408185e8e..c73d4e2d776 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -18593,6 +18593,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented_15.kt"); } + @Test + @TestMetadata("abstractFakeOverrideSuperCall.kt") + public void testAbstractFakeOverrideSuperCall() throws Exception { + runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.kt"); + } + + @Test + @TestMetadata("abstractFakeOverrideSuperCallForbidden.kt") + public void testAbstractFakeOverrideSuperCallForbidden() throws Exception { + runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCallForbidden.kt"); + } + @Test @TestMetadata("abstractVsAbstract.kt") public void testAbstractVsAbstract() throws Exception { diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 69a936b9f61..b4ddb326ed2 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -253,6 +253,7 @@ enum class LanguageFeature( ProhibitConfusingSyntaxInWhenBranches(KOTLIN_1_8, kind = BUG_FIX), // KT-48385 UseConsistentRulesForPrivateConstructorsOfSealedClasses(sinceVersion = KOTLIN_1_8, kind = BUG_FIX), // KT-44866 ProgressionsChangingResolve(KOTLIN_1_8), // KT-49276 + ForbidSuperDelegationToAbstractFakeOverride(KOTLIN_1_8), // KT-49017 (+ KT-38078) // 1.9