Refactor OverrideResolver.checkOverrideForMember()
Create CheckOverrideReportStrategy interface to report override errors (will be used later for synthesized members override checks). Add diagnostic test on OVERRIDING_FINAL_MEMBER, as no such test happened to exist before.
This commit is contained in:
@@ -551,68 +551,111 @@ public class OverrideResolver {
|
|||||||
return factoredMembers;
|
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) {
|
if (declared.getKind() != CallableMemberDescriptor.Kind.DECLARATION) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JetNamedDeclaration member = (JetNamedDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), declared);
|
final JetNamedDeclaration member = (JetNamedDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), declared);
|
||||||
if (member == null) {
|
if (member == null) {
|
||||||
if (declared.getKind() != CallableMemberDescriptor.Kind.DELEGATION) {
|
throw new IllegalStateException("declared descriptor is not resolved to declaration: " + declared);
|
||||||
throw new IllegalStateException(
|
|
||||||
"descriptor is not resolved to declaration" +
|
|
||||||
" and it is not delegate: " + declared);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JetModifierList modifierList = member.getModifierList();
|
JetModifierList modifierList = member.getModifierList();
|
||||||
ASTNode overrideNode = modifierList != null ? modifierList.getModifierNode(JetTokens.OVERRIDE_KEYWORD) : null;
|
final ASTNode overrideNode = modifierList != null ? modifierList.getModifierNode(JetTokens.OVERRIDE_KEYWORD) : null;
|
||||||
boolean hasOverrideModifier = overrideNode != null;
|
Set<? extends CallableMemberDescriptor> overriddenDescriptors = declared.getOverriddenDescriptors();
|
||||||
|
|
||||||
boolean finalOverriddenError = false;
|
if (overrideNode != null) {
|
||||||
boolean typeMismatchError = false;
|
checkOverridesForMemberMarkedOverride(declared, new CheckOverrideReportStrategy() {
|
||||||
boolean kindMismatchError = false;
|
private boolean finalOverriddenError = false;
|
||||||
for (CallableMemberDescriptor overridden : declared.getOverriddenDescriptors()) {
|
private boolean typeMismatchError = false;
|
||||||
if (overridden != null) {
|
private boolean kindMismatchError = false;
|
||||||
if (hasOverrideModifier) {
|
|
||||||
if (!overridden.getModality().isOverridable() && !finalOverriddenError) {
|
@Override
|
||||||
trace.report(OVERRIDING_FINAL_MEMBER.on(overrideNode.getPsi(), overridden, overridden.getContainingDeclaration()));
|
public void overridingFinalMember( @NotNull CallableMemberDescriptor overridden) {
|
||||||
|
if (!finalOverriddenError) {
|
||||||
finalOverriddenError = true;
|
finalOverriddenError = true;
|
||||||
|
trace.report(OVERRIDING_FINAL_MEMBER.on(overrideNode.getPsi(), overridden, overridden.getContainingDeclaration()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!OverridingUtil.isReturnTypeOkForOverride(JetTypeChecker.INSTANCE, overridden, declared) && !typeMismatchError) {
|
@Override
|
||||||
trace.report(RETURN_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden));
|
public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) {
|
||||||
|
if (!typeMismatchError) {
|
||||||
typeMismatchError = true;
|
typeMismatchError = true;
|
||||||
|
trace.report(RETURN_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (checkPropertyKind(overridden, true) && checkPropertyKind(declared, false) && !kindMismatchError) {
|
@Override
|
||||||
trace.report(VAR_OVERRIDDEN_BY_VAL.on((JetProperty) member, (PropertyDescriptor) declared, (PropertyDescriptor) overridden));
|
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden) {
|
||||||
|
if (!kindMismatchError) {
|
||||||
kindMismatchError = true;
|
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<? extends CallableMemberDescriptor> 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();
|
DeclarationDescriptor containingDeclaration = declared.getContainingDeclaration();
|
||||||
assert containingDeclaration instanceof ClassDescriptor : "Overrides may only be resolved in a class, but " + declared + " comes from " + containingDeclaration;
|
assert containingDeclaration instanceof ClassDescriptor : "Overrides may only be resolved in a class, but " + declared + " comes from " + containingDeclaration;
|
||||||
ClassDescriptor declaringClass = (ClassDescriptor) containingDeclaration;
|
ClassDescriptor declaringClass = (ClassDescriptor) containingDeclaration;
|
||||||
|
|
||||||
CallableMemberDescriptor invisibleOverriddenDescriptor = findInvisibleOverriddenDescriptor(declared, declaringClass);
|
CallableMemberDescriptor invisibleOverriddenDescriptor = findInvisibleOverriddenDescriptor(declared, declaringClass);
|
||||||
if (invisibleOverriddenDescriptor != null) {
|
if (invisibleOverriddenDescriptor != null) {
|
||||||
trace.report(CANNOT_OVERRIDE_INVISIBLE_MEMBER.on(member, declared, invisibleOverriddenDescriptor,
|
reportError.cannotOverrideInvisibleMember(invisibleOverriddenDescriptor);
|
||||||
invisibleOverriddenDescriptor.getContainingDeclaration()));
|
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
private CallableMemberDescriptor findInvisibleOverriddenDescriptor(CallableMemberDescriptor declared, ClassDescriptor declaringClass) {
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
open class A {
|
||||||
|
final fun foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A() {
|
||||||
|
<!OVERRIDING_FINAL_MEMBER!>override<!> fun foo() {}
|
||||||
|
}
|
||||||
@@ -2352,6 +2352,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
|||||||
doTest("compiler/testData/diagnostics/tests/override/NonGenerics.kt");
|
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")
|
@TestMetadata("ParameterDefaultValues-DefaultValueFromOnlyOneSupertype.kt")
|
||||||
public void testParameterDefaultValues_DefaultValueFromOnlyOneSupertype() throws Exception {
|
public void testParameterDefaultValues_DefaultValueFromOnlyOneSupertype() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/override/ParameterDefaultValues-DefaultValueFromOnlyOneSupertype.kt");
|
doTest("compiler/testData/diagnostics/tests/override/ParameterDefaultValues-DefaultValueFromOnlyOneSupertype.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user