diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java index 3a43e91b5ea..64221ae6a64 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java @@ -551,68 +551,111 @@ public class OverrideResolver { return factoredMembers; } - private void checkOverrideForMember(@NotNull CallableMemberDescriptor declared) { + private interface CheckOverrideReportStrategy { + void overridingFinalMember(@NotNull CallableMemberDescriptor overridden); + + void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden); + + void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden); + + void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor invisibleOverridden); + + void nothingToOverride(); + } + + private void checkOverrideForMember(@NotNull final CallableMemberDescriptor declared) { if (declared.getKind() != CallableMemberDescriptor.Kind.DECLARATION) { return; } - JetNamedDeclaration member = (JetNamedDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), declared); + final JetNamedDeclaration member = (JetNamedDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), declared); if (member == null) { - if (declared.getKind() != CallableMemberDescriptor.Kind.DELEGATION) { - throw new IllegalStateException( - "descriptor is not resolved to declaration" + - " and it is not delegate: " + declared); - } - return; + throw new IllegalStateException("declared descriptor is not resolved to declaration: " + declared); } JetModifierList modifierList = member.getModifierList(); - ASTNode overrideNode = modifierList != null ? modifierList.getModifierNode(JetTokens.OVERRIDE_KEYWORD) : null; - boolean hasOverrideModifier = overrideNode != null; + final ASTNode overrideNode = modifierList != null ? modifierList.getModifierNode(JetTokens.OVERRIDE_KEYWORD) : null; + Set overriddenDescriptors = declared.getOverriddenDescriptors(); - boolean finalOverriddenError = false; - boolean typeMismatchError = false; - boolean kindMismatchError = false; - for (CallableMemberDescriptor overridden : declared.getOverriddenDescriptors()) { - if (overridden != null) { - if (hasOverrideModifier) { - if (!overridden.getModality().isOverridable() && !finalOverriddenError) { - trace.report(OVERRIDING_FINAL_MEMBER.on(overrideNode.getPsi(), overridden, overridden.getContainingDeclaration())); + if (overrideNode != null) { + checkOverridesForMemberMarkedOverride(declared, new CheckOverrideReportStrategy() { + private boolean finalOverriddenError = false; + private boolean typeMismatchError = false; + private boolean kindMismatchError = false; + + @Override + public void overridingFinalMember( @NotNull CallableMemberDescriptor overridden) { + if (!finalOverriddenError) { finalOverriddenError = true; + trace.report(OVERRIDING_FINAL_MEMBER.on(overrideNode.getPsi(), overridden, overridden.getContainingDeclaration())); } + } - if (!OverridingUtil.isReturnTypeOkForOverride(JetTypeChecker.INSTANCE, overridden, declared) && !typeMismatchError) { - trace.report(RETURN_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden)); + @Override + public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) { + if (!typeMismatchError) { typeMismatchError = true; + trace.report(RETURN_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden)); } + } - if (checkPropertyKind(overridden, true) && checkPropertyKind(declared, false) && !kindMismatchError) { - trace.report(VAR_OVERRIDDEN_BY_VAL.on((JetProperty) member, (PropertyDescriptor) declared, (PropertyDescriptor) overridden)); + @Override + public void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden) { + if (!kindMismatchError) { kindMismatchError = true; + trace.report(VAR_OVERRIDDEN_BY_VAL.on((JetProperty) member, (PropertyDescriptor) declared, (PropertyDescriptor) overridden)); } } + + @Override + public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor invisibleOverridden) { + trace.report(CANNOT_OVERRIDE_INVISIBLE_MEMBER.on(member, declared, invisibleOverridden, invisibleOverridden.getContainingDeclaration())); + } + + @Override + public void nothingToOverride() { + trace.report(NOTHING_TO_OVERRIDE.on(member, declared)); + } + }); + } + else if (!overriddenDescriptors.isEmpty()) { + CallableMemberDescriptor overridden = overriddenDescriptors.iterator().next(); + trace.report(VIRTUAL_MEMBER_HIDDEN.on(member, declared, overridden, overridden.getContainingDeclaration())); + } + } + + private void checkOverridesForMemberMarkedOverride(@NotNull CallableMemberDescriptor declared, @NotNull CheckOverrideReportStrategy reportError) { + Set overriddenDescriptors = declared.getOverriddenDescriptors(); + + for (CallableMemberDescriptor overridden : overriddenDescriptors) { + if (overridden != null) { + if (!overridden.getModality().isOverridable()) { + reportError.overridingFinalMember(overridden); + } + + if (!OverridingUtil.isReturnTypeOkForOverride(JetTypeChecker.INSTANCE, overridden, declared)) { + reportError.returnTypeMismatchOnOverride(overridden); + } + + if (checkPropertyKind(overridden, true) && checkPropertyKind(declared, false)) { + reportError.varOverriddenByVal(overridden); + } } } - if (hasOverrideModifier && declared.getOverriddenDescriptors().size() == 0) { + if (overriddenDescriptors.isEmpty()) { DeclarationDescriptor containingDeclaration = declared.getContainingDeclaration(); assert containingDeclaration instanceof ClassDescriptor : "Overrides may only be resolved in a class, but " + declared + " comes from " + containingDeclaration; ClassDescriptor declaringClass = (ClassDescriptor) containingDeclaration; CallableMemberDescriptor invisibleOverriddenDescriptor = findInvisibleOverriddenDescriptor(declared, declaringClass); if (invisibleOverriddenDescriptor != null) { - trace.report(CANNOT_OVERRIDE_INVISIBLE_MEMBER.on(member, declared, invisibleOverriddenDescriptor, - invisibleOverriddenDescriptor.getContainingDeclaration())); + reportError.cannotOverrideInvisibleMember(invisibleOverriddenDescriptor); } else { - trace.report(NOTHING_TO_OVERRIDE.on(member, declared)); + reportError.nothingToOverride(); } } - PsiElement nameIdentifier = member.getNameIdentifier(); - if (!hasOverrideModifier && declared.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) { - CallableMemberDescriptor overridden = declared.getOverriddenDescriptors().iterator().next(); - trace.report(VIRTUAL_MEMBER_HIDDEN.on(member, declared, overridden, overridden.getContainingDeclaration())); - } } private CallableMemberDescriptor findInvisibleOverriddenDescriptor(CallableMemberDescriptor declared, ClassDescriptor declaringClass) { diff --git a/compiler/testData/diagnostics/tests/override/OverridingFinalMember.kt b/compiler/testData/diagnostics/tests/override/OverridingFinalMember.kt new file mode 100644 index 00000000000..1d90924753d --- /dev/null +++ b/compiler/testData/diagnostics/tests/override/OverridingFinalMember.kt @@ -0,0 +1,7 @@ +open class A { + final fun foo() {} +} + +class B : A() { + override fun foo() {} +} diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index b6ee8f84b70..af968729d0f 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -2352,6 +2352,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/override/NonGenerics.kt"); } + @TestMetadata("OverridingFinalMember.kt") + public void testOverridingFinalMember() throws Exception { + doTest("compiler/testData/diagnostics/tests/override/OverridingFinalMember.kt"); + } + @TestMetadata("ParameterDefaultValues-DefaultValueFromOnlyOneSupertype.kt") public void testParameterDefaultValues_DefaultValueFromOnlyOneSupertype() throws Exception { doTest("compiler/testData/diagnostics/tests/override/ParameterDefaultValues-DefaultValueFromOnlyOneSupertype.kt");