KT-1934 & KT-10197:
Naive approximation for fake overriding signature: use upper bound for flexible types. Check delegation errors.
This commit is contained in:
@@ -329,6 +329,15 @@ public interface Errors {
|
||||
DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor> PROPERTY_TYPE_MISMATCH_ON_INHERITANCE =
|
||||
DiagnosticFactory2.create(ERROR, DECLARATION_NAME);
|
||||
|
||||
DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor> OVERRIDING_FINAL_MEMBER_BY_DELEGATION =
|
||||
DiagnosticFactory2.create(ERROR, DECLARATION_NAME);
|
||||
DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor> RETURN_TYPE_MISMATCH_ON_OVERRIDE_BY_DELEGATION =
|
||||
DiagnosticFactory2.create(ERROR, DECLARATION_NAME);
|
||||
DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor> PROPERTY_TYPE_MISMATCH_ON_OVERRIDE_BY_DELEGATION =
|
||||
DiagnosticFactory2.create(ERROR, DECLARATION_NAME);
|
||||
DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor> VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION =
|
||||
DiagnosticFactory2.create(ERROR, DECLARATION_NAME);
|
||||
|
||||
DiagnosticFactory2<KtClassOrObject, KtClassOrObject, CallableMemberDescriptor> ABSTRACT_MEMBER_NOT_IMPLEMENTED =
|
||||
DiagnosticFactory2.create(ERROR, DECLARATION_NAME);
|
||||
DiagnosticFactory2<KtClassOrObject, KtClassOrObject, CallableMemberDescriptor> ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED =
|
||||
|
||||
+9
@@ -563,6 +563,15 @@ public class DefaultErrorMessages {
|
||||
MAP.put(PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, "''{0}'' clashes with ''{1}'': property types are incompatible",
|
||||
SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES);
|
||||
|
||||
MAP.put(OVERRIDING_FINAL_MEMBER_BY_DELEGATION, "''{0}'' implicitly overrides a final member ''{1}'' by delegation",
|
||||
SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES);
|
||||
MAP.put(RETURN_TYPE_MISMATCH_ON_OVERRIDE_BY_DELEGATION, "Return type of ''{0}'' doesn't match ''{1}'' implicitly overridden by delegation",
|
||||
SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES);
|
||||
MAP.put(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE_BY_DELEGATION, "Property type of ''{0}'' doesn't match ''{1}'' implicitly overridden by delegation",
|
||||
SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES);
|
||||
MAP.put(VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION, "val-property ''{0}'' implicitly overrides a var-property ''{1}'' by delegation",
|
||||
SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES);
|
||||
|
||||
MAP.put(VAR_OVERRIDDEN_BY_VAL, "Var-property {0} cannot be overridden by val-property {1}", FQ_NAMES_IN_TYPES, FQ_NAMES_IN_TYPES);
|
||||
|
||||
MAP.put(ABSTRACT_MEMBER_NOT_IMPLEMENTED, "{0} must be declared abstract or implement abstract member {1}", RENDER_CLASS_OR_OBJECT,
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.LinkedMultiMap;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.containers.SmartHashSet;
|
||||
import com.intellij.util.containers.hash.EqualityPolicy;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
@@ -32,6 +33,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.ReadOnly;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory2;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactoryWithPsiElement;
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
@@ -263,144 +266,229 @@ public class OverrideResolver {
|
||||
checkOverrideForMember(member);
|
||||
}
|
||||
|
||||
// Check if everything that must be overridden, actually is
|
||||
// More than one implementation or no implementations at all
|
||||
final Set<CallableMemberDescriptor> abstractNoImpl = Sets.newLinkedHashSet();
|
||||
final Set<CallableMemberDescriptor> manyImpl = Sets.newLinkedHashSet();
|
||||
final Set<CallableMemberDescriptor> abstractInBaseClassNoImpl = Sets.newLinkedHashSet();
|
||||
final Set<CallableMemberDescriptor> conflictingInterfaceOverrides = Sets.newLinkedHashSet();
|
||||
CollectErrorInformationForInheritedMembersStrategy inheritedMemberErrors =
|
||||
new CollectErrorInformationForInheritedMembersStrategy(klass, classDescriptor);
|
||||
|
||||
checkInheritedSignatures(
|
||||
classDescriptor,
|
||||
new CheckInheritedSignaturesReportingStrategy() {
|
||||
private boolean returnTypeMismatch = false;
|
||||
private boolean propertyTypeMismatch = false;
|
||||
|
||||
@Override
|
||||
public void abstractMemberNoImpl(CallableMemberDescriptor descriptor) {
|
||||
abstractNoImpl.add(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abstractBaseClassMemberNoImpl(CallableMemberDescriptor descriptor) {
|
||||
abstractInBaseClassNoImpl.add(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void manyImplMemberNoImpl(CallableMemberDescriptor descriptor) {
|
||||
manyImpl.add(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void conflictingMemberFromInterface(CallableMemberDescriptor descriptor) {
|
||||
conflictingInterfaceOverrides.add(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clashingWithReturnType(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) {
|
||||
if (!returnTypeMismatch) {
|
||||
returnTypeMismatch = true;
|
||||
trace.report(RETURN_TYPE_MISMATCH_ON_INHERITANCE.on(klass, descriptor1, descriptor2));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clashingWithPropertyType(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) {
|
||||
if (!propertyTypeMismatch) {
|
||||
propertyTypeMismatch = true;
|
||||
trace.report(PROPERTY_TYPE_MISMATCH_ON_INHERITANCE.on(klass, descriptor1, descriptor2));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!classCanHaveAbstractMembers(classDescriptor)) {
|
||||
if (!abstractInBaseClassNoImpl.isEmpty()) {
|
||||
trace.report(ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractInBaseClassNoImpl.iterator().next()));
|
||||
}
|
||||
else if (!abstractNoImpl.isEmpty()) {
|
||||
trace.report(ABSTRACT_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractNoImpl.iterator().next()));
|
||||
}
|
||||
}
|
||||
|
||||
if (!conflictingInterfaceOverrides.isEmpty()) {
|
||||
trace.report(MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED.on(klass, klass, conflictingInterfaceOverrides.iterator().next()));
|
||||
}
|
||||
else if (!manyImpl.isEmpty()) {
|
||||
trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(klass, klass, manyImpl.iterator().next()));
|
||||
}
|
||||
checkInheritedAndDelegatedSignatures(classDescriptor, inheritedMemberErrors, inheritedMemberErrors);
|
||||
inheritedMemberErrors.doReportErrors();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Set<CallableMemberDescriptor> getMissingImplementations(@NotNull ClassDescriptor classDescriptor) {
|
||||
CollectMissingImplementationsStrategy collector = new CollectMissingImplementationsStrategy();
|
||||
checkInheritedSignatures(classDescriptor, collector);
|
||||
checkInheritedAndDelegatedSignatures(classDescriptor, collector, null);
|
||||
return collector.shouldImplement;
|
||||
}
|
||||
|
||||
private interface CheckInheritedSignaturesReportingStrategy {
|
||||
void abstractMemberNoImpl(CallableMemberDescriptor descriptor);
|
||||
void abstractBaseClassMemberNoImpl(CallableMemberDescriptor descriptor);
|
||||
void manyImplMemberNoImpl(CallableMemberDescriptor descriptor);
|
||||
void conflictingMemberFromInterface(CallableMemberDescriptor descriptor);
|
||||
void clashingWithReturnType(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2);
|
||||
void clashingWithPropertyType(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2);
|
||||
private interface CheckInheritedSignaturesReportStrategy {
|
||||
void abstractMemberNotImplemented(CallableMemberDescriptor descriptor);
|
||||
void abstractBaseClassMemberNotImplemented(CallableMemberDescriptor descriptor);
|
||||
void multipleImplementationsMemberNotImplemented(CallableMemberDescriptor descriptor);
|
||||
void conflictingInterfaceMemberNotImplemented(CallableMemberDescriptor descriptor);
|
||||
void returnTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2);
|
||||
void propertyTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2);
|
||||
}
|
||||
|
||||
private static class CollectMissingImplementationsStrategy implements CheckInheritedSignaturesReportingStrategy {
|
||||
private static class CollectMissingImplementationsStrategy implements CheckInheritedSignaturesReportStrategy {
|
||||
private Set<CallableMemberDescriptor> shouldImplement = new LinkedHashSet<CallableMemberDescriptor>();
|
||||
|
||||
@Override
|
||||
public void abstractMemberNoImpl(CallableMemberDescriptor descriptor) {
|
||||
public void abstractMemberNotImplemented(CallableMemberDescriptor descriptor) {
|
||||
shouldImplement.add(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abstractBaseClassMemberNoImpl(CallableMemberDescriptor descriptor) {
|
||||
public void abstractBaseClassMemberNotImplemented(CallableMemberDescriptor descriptor) {
|
||||
// don't care
|
||||
}
|
||||
|
||||
@Override
|
||||
public void manyImplMemberNoImpl(CallableMemberDescriptor descriptor) {
|
||||
public void multipleImplementationsMemberNotImplemented(CallableMemberDescriptor descriptor) {
|
||||
shouldImplement.add(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void conflictingMemberFromInterface(CallableMemberDescriptor descriptor) {
|
||||
public void conflictingInterfaceMemberNotImplemented(CallableMemberDescriptor descriptor) {
|
||||
// don't care
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clashingWithReturnType(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) {
|
||||
public void returnTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) {
|
||||
// don't care
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clashingWithPropertyType(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) {
|
||||
public void propertyTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) {
|
||||
// don't care
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkInheritedSignatures(
|
||||
@NotNull ClassDescriptor classDescriptor,
|
||||
@NotNull CheckInheritedSignaturesReportingStrategy reportingStrategy
|
||||
) {
|
||||
for (DeclarationDescriptor member : DescriptorUtils.getAllDescriptors(classDescriptor.getDefaultType().getMemberScope())) {
|
||||
if (member instanceof CallableMemberDescriptor) {
|
||||
checkInheritedSignatures((CallableMemberDescriptor) member, reportingStrategy);
|
||||
private class CollectErrorInformationForInheritedMembersStrategy
|
||||
implements CheckInheritedSignaturesReportStrategy, CheckOverrideReportStrategy {
|
||||
private final KtClassOrObject klass;
|
||||
private final ClassDescriptor classDescriptor;
|
||||
|
||||
private final Set<CallableMemberDescriptor> abstractNoImpl = Sets.newLinkedHashSet();
|
||||
private final Set<CallableMemberDescriptor> multipleImplementations = Sets.newLinkedHashSet();
|
||||
private final Set<CallableMemberDescriptor> abstractInBaseClassNoImpl = Sets.newLinkedHashSet();
|
||||
private final Set<CallableMemberDescriptor> conflictingInterfaceMembers = Sets.newLinkedHashSet();
|
||||
private final Set<CallableMemberDescriptor> conflictingReturnTypes = Sets.newHashSet();
|
||||
|
||||
private final Set<DiagnosticFactoryWithPsiElement> onceErrorsReported = new SmartHashSet<DiagnosticFactoryWithPsiElement>();
|
||||
|
||||
public CollectErrorInformationForInheritedMembersStrategy(
|
||||
@NotNull KtClassOrObject klass,
|
||||
@NotNull ClassDescriptor classDescriptor
|
||||
) {
|
||||
this.klass = klass;
|
||||
this.classDescriptor = classDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abstractMemberNotImplemented(CallableMemberDescriptor descriptor) {
|
||||
abstractNoImpl.add(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abstractBaseClassMemberNotImplemented(CallableMemberDescriptor descriptor) {
|
||||
abstractInBaseClassNoImpl.add(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void multipleImplementationsMemberNotImplemented(CallableMemberDescriptor descriptor) {
|
||||
multipleImplementations.add(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void conflictingInterfaceMemberNotImplemented(CallableMemberDescriptor descriptor) {
|
||||
conflictingInterfaceMembers.add(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) {
|
||||
conflictingReturnTypes.add(descriptor1);
|
||||
conflictingReturnTypes.add(descriptor2);
|
||||
|
||||
reportInheritanceConflictIfRequired(RETURN_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) {
|
||||
conflictingReturnTypes.add(descriptor1);
|
||||
conflictingReturnTypes.add(descriptor2);
|
||||
|
||||
reportInheritanceConflictIfRequired(PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2);
|
||||
}
|
||||
|
||||
private void reportInheritanceConflictIfRequired(
|
||||
@NotNull DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor> diagnosticFactory,
|
||||
@NotNull CallableMemberDescriptor descriptor1,
|
||||
@NotNull CallableMemberDescriptor descriptor2
|
||||
) {
|
||||
if (!onceErrorsReported.contains(diagnosticFactory)) {
|
||||
onceErrorsReported.add(diagnosticFactory);
|
||||
trace.report(diagnosticFactory.on(klass, descriptor1, descriptor2));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void overridingFinalMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
|
||||
reportDelegationProblemIfRequired(OVERRIDING_FINAL_MEMBER_BY_DELEGATION, overriding, overridden);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnTypeMismatchOnOverride(
|
||||
@NotNull CallableMemberDescriptor overriding,
|
||||
@NotNull CallableMemberDescriptor overridden
|
||||
) {
|
||||
conflictingReturnTypes.add(overridden);
|
||||
reportDelegationProblemIfRequired(RETURN_TYPE_MISMATCH_ON_OVERRIDE_BY_DELEGATION, overriding, overridden);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyTypeMismatchOnOverride(
|
||||
@NotNull CallableMemberDescriptor overriding,
|
||||
@NotNull CallableMemberDescriptor overridden
|
||||
) {
|
||||
conflictingReturnTypes.add(overridden);
|
||||
reportDelegationProblemIfRequired(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE_BY_DELEGATION, overriding, overridden);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
|
||||
reportDelegationProblemIfRequired(VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION, overriding, overridden);
|
||||
}
|
||||
|
||||
private void reportDelegationProblemIfRequired(
|
||||
@NotNull DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor> diagnosticFactory,
|
||||
@NotNull CallableMemberDescriptor delegate,
|
||||
@NotNull CallableMemberDescriptor overridden
|
||||
) {
|
||||
assert delegate.getKind() == DELEGATION : "Delegate expected, got " + delegate + " of kind " + delegate.getKind();
|
||||
|
||||
if (!onceErrorsReported.contains(diagnosticFactory)) {
|
||||
onceErrorsReported.add(diagnosticFactory);
|
||||
trace.report(diagnosticFactory.on(klass, delegate, overridden));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor invisibleOverridden) {
|
||||
assert overriding.getKind() == DELEGATION : "Delegate expected, got " + overriding + " of kind " + overriding.getKind();
|
||||
assert overriding.getKind() != DELEGATION : "Delegated member can't override an invisible member; " + invisibleOverridden;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nothingToOverride(@NotNull CallableMemberDescriptor overriding) {
|
||||
assert overriding.getKind() == DELEGATION : "Delegate expected, got " + overriding + " of kind " + overriding.getKind();
|
||||
assert overriding.getKind() != DELEGATION : "Delegated member can't override nothing; " + overriding;
|
||||
}
|
||||
|
||||
void doReportErrors() {
|
||||
if (!classCanHaveAbstractMembers(classDescriptor)) {
|
||||
if (!abstractInBaseClassNoImpl.isEmpty()) {
|
||||
trace.report(ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractInBaseClassNoImpl.iterator().next()));
|
||||
}
|
||||
else if (!abstractNoImpl.isEmpty()) {
|
||||
trace.report(ABSTRACT_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractNoImpl.iterator().next()));
|
||||
}
|
||||
}
|
||||
|
||||
conflictingInterfaceMembers.removeAll(conflictingReturnTypes);
|
||||
multipleImplementations.removeAll(conflictingReturnTypes);
|
||||
if (!conflictingInterfaceMembers.isEmpty()) {
|
||||
trace.report(MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED.on(klass, klass, conflictingInterfaceMembers.iterator().next()));
|
||||
}
|
||||
else if (!multipleImplementations.isEmpty()) {
|
||||
trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(klass, klass, multipleImplementations.iterator().next()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkInheritedSignatures(
|
||||
@NotNull CallableMemberDescriptor descriptor,
|
||||
@NotNull CheckInheritedSignaturesReportingStrategy reportingStrategy
|
||||
private static void checkInheritedAndDelegatedSignatures(
|
||||
@NotNull ClassDescriptor classDescriptor,
|
||||
@NotNull CheckInheritedSignaturesReportStrategy inheritedReportStrategy,
|
||||
@Nullable CheckOverrideReportStrategy overrideReportStrategyForDelegates
|
||||
) {
|
||||
if (descriptor.getKind().isReal()) return;
|
||||
for (DeclarationDescriptor member : DescriptorUtils.getAllDescriptors(classDescriptor.getDefaultType().getMemberScope())) {
|
||||
if (member instanceof CallableMemberDescriptor) {
|
||||
checkInheritedAndDelegatedSignatures((CallableMemberDescriptor) member, inheritedReportStrategy, overrideReportStrategyForDelegates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkInheritedAndDelegatedSignatures(
|
||||
@NotNull CallableMemberDescriptor descriptor,
|
||||
@NotNull CheckInheritedSignaturesReportStrategy reportingStrategy,
|
||||
@Nullable CheckOverrideReportStrategy overrideReportStrategyForDelegates
|
||||
) {
|
||||
CallableMemberDescriptor.Kind kind = descriptor.getKind();
|
||||
if (kind != FAKE_OVERRIDE && kind != DELEGATION) return;
|
||||
if (descriptor.getVisibility() == Visibilities.INVISIBLE_FAKE) return;
|
||||
|
||||
Collection<? extends CallableMemberDescriptor> directOverridden = descriptor.getOverriddenDescriptors();
|
||||
if (directOverridden.size() == 0) {
|
||||
throw new IllegalStateException("A 'fake override' " + descriptor.getName().asString() + " must override something");
|
||||
throw new IllegalStateException(kind + " " + descriptor.getName().asString() + " must override something");
|
||||
}
|
||||
|
||||
// collects map from the directly overridden descriptor to the set of declarations:
|
||||
@@ -415,39 +503,55 @@ public class OverrideResolver {
|
||||
Set<CallableMemberDescriptor> relevantDirectlyOverridden =
|
||||
getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations);
|
||||
|
||||
checkInheritedSignaturesForFakeOverride(descriptor, relevantDirectlyOverridden, reportingStrategy);
|
||||
checkInheritedDescriptorsGroup(relevantDirectlyOverridden, reportingStrategy);
|
||||
|
||||
collectJava8MissingOverrides(relevantDirectlyOverridden, reportingStrategy);
|
||||
if (kind == DELEGATION) {
|
||||
if (overrideReportStrategyForDelegates != null) {
|
||||
checkOverridesForMember(descriptor, relevantDirectlyOverridden, overrideReportStrategyForDelegates);
|
||||
}
|
||||
}
|
||||
|
||||
if (kind != DELEGATION) {
|
||||
checkMissingOverridesByJava8Restrictions(descriptor, relevantDirectlyOverridden, reportingStrategy);
|
||||
}
|
||||
|
||||
List<CallableMemberDescriptor> implementations = collectImplementations(relevantDirectlyOverridden);
|
||||
if (implementations.size() == 1 && isReturnTypeOkForOverride(descriptor, implementations.get(0))) return;
|
||||
|
||||
int numImplementations = implementations.size();
|
||||
|
||||
if (numImplementations == 1 && isReturnTypeOkForOverride(descriptor, implementations.get(0))) return;
|
||||
|
||||
List<CallableMemberDescriptor> abstractOverridden = new ArrayList<CallableMemberDescriptor>(allFilteredOverriddenDeclarations.size());
|
||||
List<CallableMemberDescriptor> concreteOverridden = new ArrayList<CallableMemberDescriptor>(allFilteredOverriddenDeclarations.size());
|
||||
filterNotSynthesizedDescriptorsByModality(allFilteredOverriddenDeclarations, abstractOverridden, concreteOverridden);
|
||||
|
||||
if (implementations.isEmpty()) {
|
||||
for (CallableMemberDescriptor member : abstractOverridden) {
|
||||
reportingStrategy.abstractMemberNoImpl(member);
|
||||
if (numImplementations == 0) {
|
||||
if (kind != DELEGATION) {
|
||||
for (CallableMemberDescriptor member : abstractOverridden) {
|
||||
reportingStrategy.abstractMemberNotImplemented(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (implementations.size() > 1) {
|
||||
else if (numImplementations > 1) {
|
||||
for (CallableMemberDescriptor member : concreteOverridden) {
|
||||
reportingStrategy.manyImplMemberNoImpl(member);
|
||||
reportingStrategy.multipleImplementationsMemberNotImplemented(member);
|
||||
}
|
||||
}
|
||||
else {
|
||||
List<CallableMemberDescriptor> membersWithMoreSpecificReturnType =
|
||||
collectAbstractMethodsWithMoreSpecificReturnType(abstractOverridden, implementations.get(0));
|
||||
for (CallableMemberDescriptor member : membersWithMoreSpecificReturnType) {
|
||||
reportingStrategy.abstractMemberNoImpl(member);
|
||||
if (kind != DELEGATION) {
|
||||
List<CallableMemberDescriptor> membersWithMoreSpecificReturnType =
|
||||
collectAbstractMethodsWithMoreSpecificReturnType(abstractOverridden, implementations.get(0));
|
||||
for (CallableMemberDescriptor member : membersWithMoreSpecificReturnType) {
|
||||
reportingStrategy.abstractMemberNotImplemented(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void collectJava8MissingOverrides(
|
||||
private static void checkMissingOverridesByJava8Restrictions(
|
||||
@NotNull CallableMemberDescriptor descriptor,
|
||||
@NotNull Set<CallableMemberDescriptor> relevantDirectlyOverridden,
|
||||
@NotNull CheckInheritedSignaturesReportingStrategy reportingStrategy
|
||||
@NotNull CheckInheritedSignaturesReportStrategy reportingStrategy
|
||||
) {
|
||||
// Java 8:
|
||||
// -- class should implement an abstract member of a super-class,
|
||||
@@ -479,12 +583,11 @@ public class OverrideResolver {
|
||||
}
|
||||
|
||||
if (overridesAbstractInBaseClass != null) {
|
||||
reportingStrategy.abstractBaseClassMemberNoImpl(overridesAbstractInBaseClass);
|
||||
reportingStrategy.abstractBaseClassMemberNotImplemented(overridesAbstractInBaseClass);
|
||||
}
|
||||
|
||||
if (!overridesClassMember && overridesNonAbstractInterfaceMember && overriddenInterfaceMembers.size() > 1) {
|
||||
for (CallableMemberDescriptor member : overriddenInterfaceMembers) {
|
||||
reportingStrategy.conflictingMemberFromInterface(member);
|
||||
reportingStrategy.conflictingInterfaceMemberNotImplemented(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -634,17 +737,12 @@ public class OverrideResolver {
|
||||
}
|
||||
|
||||
private interface CheckOverrideReportStrategy {
|
||||
void overridingFinalMember(@NotNull CallableMemberDescriptor overridden);
|
||||
|
||||
void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden);
|
||||
|
||||
void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden);
|
||||
|
||||
void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden);
|
||||
|
||||
void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor invisibleOverridden);
|
||||
|
||||
void nothingToOverride();
|
||||
void overridingFinalMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden);
|
||||
void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden);
|
||||
void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden);
|
||||
void varOverriddenByVal(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden);
|
||||
void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor invisibleOverridden);
|
||||
void nothingToOverride(@NotNull CallableMemberDescriptor overriding);
|
||||
}
|
||||
|
||||
private void checkOverrideForMember(@NotNull final CallableMemberDescriptor declared) {
|
||||
@@ -675,7 +773,7 @@ public class OverrideResolver {
|
||||
private boolean kindMismatchError = false;
|
||||
|
||||
@Override
|
||||
public void overridingFinalMember(@NotNull CallableMemberDescriptor overridden) {
|
||||
public void overridingFinalMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
|
||||
if (!finalOverriddenError) {
|
||||
finalOverriddenError = true;
|
||||
trace.report(OVERRIDING_FINAL_MEMBER.on(member, overridden, overridden.getContainingDeclaration()));
|
||||
@@ -683,7 +781,7 @@ public class OverrideResolver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) {
|
||||
public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
|
||||
if (!typeMismatchError) {
|
||||
typeMismatchError = true;
|
||||
trace.report(RETURN_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden));
|
||||
@@ -691,7 +789,7 @@ public class OverrideResolver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) {
|
||||
public void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
|
||||
if (!typeMismatchError) {
|
||||
typeMismatchError = true;
|
||||
trace.report(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden));
|
||||
@@ -699,7 +797,7 @@ public class OverrideResolver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden) {
|
||||
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
|
||||
if (!kindMismatchError) {
|
||||
kindMismatchError = true;
|
||||
trace.report(VAR_OVERRIDDEN_BY_VAL.on(member, (PropertyDescriptor) declared, (PropertyDescriptor) overridden));
|
||||
@@ -707,12 +805,12 @@ public class OverrideResolver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor invisibleOverridden) {
|
||||
public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor invisibleOverridden) {
|
||||
trace.report(CANNOT_OVERRIDE_INVISIBLE_MEMBER.on(member, declared, invisibleOverridden));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nothingToOverride() {
|
||||
public void nothingToOverride(@NotNull CallableMemberDescriptor overriding) {
|
||||
trace.report(NOTHING_TO_OVERRIDE.on(member, declared));
|
||||
}
|
||||
});
|
||||
@@ -723,33 +821,28 @@ public class OverrideResolver {
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkInheritedSignaturesForFakeOverride(
|
||||
@NotNull CallableMemberDescriptor fakeOverride,
|
||||
@NotNull Collection<CallableMemberDescriptor> relevantDirectlyOverridden,
|
||||
@NotNull CheckInheritedSignaturesReportingStrategy reportingStrategy
|
||||
private static void checkInheritedDescriptorsGroup(
|
||||
@NotNull Collection<CallableMemberDescriptor> inheritedDescriptors,
|
||||
@NotNull CheckInheritedSignaturesReportStrategy reportingStrategy
|
||||
) {
|
||||
assert fakeOverride.getKind() == FAKE_OVERRIDE
|
||||
: "Fake override expected; actual: " + fakeOverride + " of kind " + fakeOverride.getKind();
|
||||
|
||||
// FIXME This algorithm depends on transitiveness of sub-typing relation, which is broken in presence of flexible types.
|
||||
// See override/clashesOnInheritance/flexibleReturnType.kt.
|
||||
if (relevantDirectlyOverridden.size() > 1) {
|
||||
Iterator<CallableMemberDescriptor> overriddenIterator = relevantDirectlyOverridden.iterator();
|
||||
CallableMemberDescriptor mostSpecificOverridden = overriddenIterator.next();
|
||||
while (overriddenIterator.hasNext()) {
|
||||
CallableMemberDescriptor overriddenDescriptor = overriddenIterator.next();
|
||||
if (OverridingUtil.isMoreSpecific(overriddenDescriptor, mostSpecificOverridden)) {
|
||||
mostSpecificOverridden = overriddenDescriptor;
|
||||
if (inheritedDescriptors.size() > 1) {
|
||||
Iterator<CallableMemberDescriptor> inheritedIterator = inheritedDescriptors.iterator();
|
||||
CallableMemberDescriptor mostSpecificInherited = inheritedIterator.next();
|
||||
while (inheritedIterator.hasNext()) {
|
||||
CallableMemberDescriptor overriddenDescriptor = inheritedIterator.next();
|
||||
if (OverridingUtil.isMoreSpecific(overriddenDescriptor, mostSpecificInherited)) {
|
||||
mostSpecificInherited = overriddenDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
for (CallableMemberDescriptor overriddenDescriptor : relevantDirectlyOverridden) {
|
||||
if (!OverridingUtil.isMoreSpecific(mostSpecificOverridden, overriddenDescriptor)) {
|
||||
if (overriddenDescriptor instanceof PropertyDescriptor) {
|
||||
reportingStrategy.clashingWithPropertyType(mostSpecificOverridden, overriddenDescriptor);
|
||||
for (CallableMemberDescriptor inheritedDescriptor : inheritedDescriptors) {
|
||||
if (!OverridingUtil.isMoreSpecific(mostSpecificInherited, inheritedDescriptor)) {
|
||||
if (inheritedDescriptor instanceof PropertyDescriptor) {
|
||||
reportingStrategy.propertyTypeMismatchOnInheritance(mostSpecificInherited, inheritedDescriptor);
|
||||
}
|
||||
else {
|
||||
reportingStrategy.clashingWithReturnType(mostSpecificOverridden, overriddenDescriptor);
|
||||
reportingStrategy.returnTypeMismatchOnInheritance(mostSpecificInherited, inheritedDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -763,25 +856,7 @@ public class OverrideResolver {
|
||||
) {
|
||||
Collection<? extends CallableMemberDescriptor> overriddenDescriptors = declared.getOverriddenDescriptors();
|
||||
|
||||
for (CallableMemberDescriptor overridden : overriddenDescriptors) {
|
||||
if (overridden == null) continue;
|
||||
|
||||
if (!overridden.getModality().isOverridable()) {
|
||||
reportError.overridingFinalMember(overridden);
|
||||
}
|
||||
|
||||
if (declared instanceof PropertyDescriptor &&
|
||||
!isPropertyTypeOkForOverride((PropertyDescriptor) overridden, (PropertyDescriptor) declared)) {
|
||||
reportError.propertyTypeMismatchOnOverride(overridden);
|
||||
}
|
||||
else if (!isReturnTypeOkForOverride(overridden, declared)) {
|
||||
reportError.returnTypeMismatchOnOverride(overridden);
|
||||
}
|
||||
|
||||
if (checkPropertyKind(overridden, true) && checkPropertyKind(declared, false)) {
|
||||
reportError.varOverriddenByVal(overridden);
|
||||
}
|
||||
}
|
||||
checkOverridesForMember(declared, overriddenDescriptors, reportError);
|
||||
|
||||
if (checkIfOverridesNothing && overriddenDescriptors.isEmpty()) {
|
||||
DeclarationDescriptor containingDeclaration = declared.getContainingDeclaration();
|
||||
@@ -790,10 +865,36 @@ public class OverrideResolver {
|
||||
|
||||
CallableMemberDescriptor invisibleOverriddenDescriptor = findInvisibleOverriddenDescriptor(declared, declaringClass);
|
||||
if (invisibleOverriddenDescriptor != null) {
|
||||
reportError.cannotOverrideInvisibleMember(invisibleOverriddenDescriptor);
|
||||
reportError.cannotOverrideInvisibleMember(declared, invisibleOverriddenDescriptor);
|
||||
}
|
||||
else {
|
||||
reportError.nothingToOverride();
|
||||
reportError.nothingToOverride(declared);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkOverridesForMember(
|
||||
CallableMemberDescriptor memberDescriptor,
|
||||
Collection<? extends CallableMemberDescriptor> overriddenDescriptors,
|
||||
@NotNull CheckOverrideReportStrategy reportError
|
||||
) {
|
||||
for (CallableMemberDescriptor overridden : overriddenDescriptors) {
|
||||
if (overridden == null) continue;
|
||||
|
||||
if (!overridden.getModality().isOverridable()) {
|
||||
reportError.overridingFinalMember(memberDescriptor, overridden);
|
||||
}
|
||||
|
||||
if (memberDescriptor instanceof PropertyDescriptor &&
|
||||
!isPropertyTypeOkForOverride((PropertyDescriptor) overridden, (PropertyDescriptor) memberDescriptor)) {
|
||||
reportError.propertyTypeMismatchOnOverride(memberDescriptor, overridden);
|
||||
}
|
||||
else if (!isReturnTypeOkForOverride(overridden, memberDescriptor)) {
|
||||
reportError.returnTypeMismatchOnOverride(memberDescriptor, overridden);
|
||||
}
|
||||
|
||||
if (checkPropertyKind(overridden, true) && checkPropertyKind(memberDescriptor, false)) {
|
||||
reportError.varOverriddenByVal(memberDescriptor, overridden);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -855,7 +956,7 @@ public class OverrideResolver {
|
||||
private boolean overrideConflict = false;
|
||||
|
||||
@Override
|
||||
public void overridingFinalMember(@NotNull CallableMemberDescriptor overridden) {
|
||||
public void overridingFinalMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
|
||||
if (!overrideConflict) {
|
||||
overrideConflict = true;
|
||||
trace.report(DATA_CLASS_OVERRIDE_CONFLICT.on(dataModifier, componentFunction, overridden.getContainingDeclaration()));
|
||||
@@ -863,7 +964,7 @@ public class OverrideResolver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) {
|
||||
public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
|
||||
if (!overrideConflict) {
|
||||
overrideConflict = true;
|
||||
trace.report(DATA_CLASS_OVERRIDE_CONFLICT.on(dataModifier, componentFunction, overridden.getContainingDeclaration()));
|
||||
@@ -871,22 +972,22 @@ public class OverrideResolver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) {
|
||||
public void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
|
||||
throw new IllegalStateException("Component functions are not properties");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden) {
|
||||
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) {
|
||||
throw new IllegalStateException("Component functions are not properties");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor invisibleOverridden) {
|
||||
public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor invisibleOverridden) {
|
||||
throw new IllegalStateException("CANNOT_OVERRIDE_INVISIBLE_MEMBER should be reported on the corresponding property");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nothingToOverride() {
|
||||
public void nothingToOverride(@NotNull CallableMemberDescriptor overriding) {
|
||||
throw new IllegalStateException("Component functions are OK to override nothing");
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user