Deal with cases when different visibility of overridden members could produce incorrect fake override.

(by Pavel Talanov and Andrey Breslav)
This commit is contained in:
Pavel V. Talanov
2012-07-20 18:31:05 +04:00
parent d65b6bc69f
commit f861b69d7a
5 changed files with 206 additions and 89 deletions
@@ -16,6 +16,8 @@
package org.jetbrains.jet.lang.resolve; package org.jetbrains.jet.lang.resolve;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@@ -175,83 +177,134 @@ public class OverrideResolver {
} }
public static void generateOverridesInFunctionGroup( public static void generateOverridesInFunctionGroup(
@NotNull Name name, @NotNull Name name, //DO NOT DELETE THIS PARAMETER: needed to make sure all descriptors have the same name
@NotNull Collection<? extends CallableMemberDescriptor> membersFromSupertypes, @NotNull Collection<? extends CallableMemberDescriptor> membersFromSupertypes,
@NotNull Collection<? extends CallableMemberDescriptor> membersFromCurrent, @NotNull Collection<? extends CallableMemberDescriptor> membersFromCurrent,
@NotNull ClassDescriptor current, @NotNull ClassDescriptor current,
@NotNull DescriptorSink sink @NotNull DescriptorSink sink
) { ) {
List<CallableMemberDescriptor> notOverridden = Lists.newArrayList(membersFromSupertypes); List<CallableMemberDescriptor> notOverridden = Lists.newArrayList(membersFromSupertypes);
for (CallableMemberDescriptor fromCurrent : membersFromCurrent) { for (CallableMemberDescriptor fromCurrent : membersFromCurrent) {
extractAndBindOverridesForMember(fromCurrent, notOverridden, current, sink);
// Find what this descriptor overrides, bind them and removed from notOverridden
for (Iterator<CallableMemberDescriptor> iterator = notOverridden.iterator(); iterator.hasNext(); ) {
CallableMemberDescriptor fromSupertype = iterator.next();
OverridingUtil.OverrideCompatibilityInfo.Result result =
OverridingUtil.isOverridableBy(fromSupertype, fromCurrent).getResult();
boolean isVisible = Visibilities.isVisible(fromSupertype, current);
switch (result) {
case OVERRIDABLE:
if (isVisible) {
OverridingUtil.bindOverride(fromCurrent, fromSupertype);
}
iterator.remove();
break;
case CONFLICT:
if (isVisible) {
sink.conflict(fromSupertype, fromCurrent);
}
iterator.remove();
break;
case INCOMPATIBLE:
break;
}
}
} }
bindFakeOverrides(current, notOverridden, sink);
}
private static void extractAndBindOverridesForMember(
@NotNull CallableMemberDescriptor fromCurrent,
@NotNull List<CallableMemberDescriptor> notOverridden, @NotNull ClassDescriptor current,
@NotNull DescriptorSink sink
) {
for (Iterator<CallableMemberDescriptor> iterator = notOverridden.iterator(); iterator.hasNext(); ) {
CallableMemberDescriptor fromSupertype = iterator.next();
OverridingUtil.OverrideCompatibilityInfo.Result result =
OverridingUtil.isOverridableBy(fromSupertype, fromCurrent).getResult();
boolean isVisible = Visibilities.isVisible(fromSupertype, current);
switch (result) {
case OVERRIDABLE:
if (isVisible) {
OverridingUtil.bindOverride(fromCurrent, fromSupertype);
}
iterator.remove();
break;
case CONFLICT:
if (isVisible) {
sink.conflict(fromSupertype, fromCurrent);
}
iterator.remove();
break;
case INCOMPATIBLE:
break;
}
}
}
private static void bindFakeOverrides(
@NotNull ClassDescriptor current,
@NotNull List<CallableMemberDescriptor> notOverridden,
@NotNull DescriptorSink sink
) {
Queue<CallableMemberDescriptor> fromSuperQueue = new LinkedList<CallableMemberDescriptor>(notOverridden); Queue<CallableMemberDescriptor> fromSuperQueue = new LinkedList<CallableMemberDescriptor>(notOverridden);
while (!fromSuperQueue.isEmpty()) { while (!fromSuperQueue.isEmpty()) {
CallableMemberDescriptor aFromSuper = fromSuperQueue.remove(); CallableMemberDescriptor notOverriddenFromSuper = fromSuperQueue.remove();
Collection<CallableMemberDescriptor> overridables = extractMembersOverridableBy(notOverriddenFromSuper, fromSuperQueue, sink);
Collection<CallableMemberDescriptor> overridableByA = Lists.newArrayList(); bindFakeOverride(notOverriddenFromSuper, overridables, current, sink);
overridableByA.add(aFromSuper);
for (Iterator<CallableMemberDescriptor> iterator = fromSuperQueue.iterator(); iterator.hasNext(); ) {
CallableMemberDescriptor bFromSuper = iterator.next();
OverridingUtil.OverrideCompatibilityInfo.Result result =
OverridingUtil.isOverridableBy(bFromSuper, aFromSuper).getResult();
switch (result) {
case OVERRIDABLE:
overridableByA.add(bFromSuper);
iterator.remove();
break;
case CONFLICT:
sink.conflict(aFromSuper, bFromSuper);
iterator.remove();
break;
case INCOMPATIBLE:
break;
}
}
boolean isVisible = true;
Modality modality = Modality.ABSTRACT;
for (CallableMemberDescriptor descriptor : overridableByA) {
isVisible &= Visibilities.isVisible(descriptor, current);
if (descriptor.getModality().compareTo(modality) < 0) {
modality = descriptor.getModality();
}
}
CallableMemberDescriptor fakeOverride =
aFromSuper.copy(current, modality, !isVisible, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false);
for (CallableMemberDescriptor descriptor : overridableByA) {
OverridingUtil.bindOverride(fakeOverride, descriptor);
}
sink.addToScope(fakeOverride);
} }
} }
private static void bindFakeOverride(
@NotNull CallableMemberDescriptor notOverriddenFromSuper,
@NotNull Collection<CallableMemberDescriptor> overridables,
@NotNull ClassDescriptor current,
@NotNull DescriptorSink sink
) {
Collection<CallableMemberDescriptor> visibleOverridables = filterVisible(current, overridables);
Modality modality = getMinimalModality(visibleOverridables);
boolean allInvisible = visibleOverridables.isEmpty();
Collection<CallableMemberDescriptor> effectiveOverridden = allInvisible ? overridables : visibleOverridables;
CallableMemberDescriptor fakeOverride =
notOverriddenFromSuper.copy(current, modality, allInvisible, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false);
for (CallableMemberDescriptor descriptor : effectiveOverridden) {
OverridingUtil.bindOverride(fakeOverride, descriptor);
}
sink.addToScope(fakeOverride);
}
@NotNull
private static Modality getMinimalModality(@NotNull Collection<CallableMemberDescriptor> descriptors) {
Modality modality = Modality.ABSTRACT;
for (CallableMemberDescriptor descriptor : descriptors) {
if (descriptor.getModality().compareTo(modality) < 0) {
modality = descriptor.getModality();
}
}
return modality;
}
@NotNull
private static Collection<CallableMemberDescriptor> filterVisible(
@NotNull final ClassDescriptor current,
@NotNull Collection<CallableMemberDescriptor> toFilter
) {
return Collections2.filter(toFilter, new Predicate<CallableMemberDescriptor>() {
@Override
public boolean apply(@Nullable CallableMemberDescriptor descriptor) {
return Visibilities.isVisible(descriptor, current);
}
});
}
@NotNull
private static Collection<CallableMemberDescriptor> extractMembersOverridableBy(
@NotNull CallableMemberDescriptor overrider,
@NotNull Queue<CallableMemberDescriptor> extractFrom,
@NotNull DescriptorSink sink
) {
Collection<CallableMemberDescriptor> overridable = Lists.newArrayList();
overridable.add(overrider);
for (Iterator<CallableMemberDescriptor> iterator = extractFrom.iterator(); iterator.hasNext(); ) {
CallableMemberDescriptor candidate = iterator.next();
OverridingUtil.OverrideCompatibilityInfo.Result result =
OverridingUtil.isOverridableBy(candidate, overrider).getResult();
switch (result) {
case OVERRIDABLE:
overridable.add(candidate);
iterator.remove();
break;
case CONFLICT:
sink.conflict(overrider, candidate);
iterator.remove();
break;
case INCOMPATIBLE:
break;
}
}
return overridable;
}
private static <T extends DeclarationDescriptor> MultiMap<Name, T> groupDescriptorsByName(Collection<T> properties) { private static <T extends DeclarationDescriptor> MultiMap<Name, T> groupDescriptorsByName(Collection<T> properties) {
MultiMap<Name, T> r = new LinkedMultiMap<Name, T>(); MultiMap<Name, T> r = new LinkedMultiMap<Name, T>();
for (T property : properties) { for (T property : properties) {
@@ -336,30 +389,37 @@ public class OverrideResolver {
} }
} }
private static void collectMissingImplementations(CallableMemberDescriptor descriptor, Set<CallableMemberDescriptor> abstractNoImpl, Set<CallableMemberDescriptor> manyImpl) { private static void collectMissingImplementations(
if (!descriptor.getKind().isReal()) { @NotNull CallableMemberDescriptor descriptor,
Collection<CallableMemberDescriptor> overriddenDeclarations = OverridingUtil.getOverriddenDeclarations(descriptor); @NotNull Set<CallableMemberDescriptor> abstractNoImpl,
if (overriddenDeclarations.size() == 0) { @NotNull Set<CallableMemberDescriptor> manyImpl
throw new IllegalStateException("A 'fake override' must override something"); ) {
} if (descriptor.getKind().isReal()) return;
else {
List<CallableMemberDescriptor> nonAbstractManyImpl = Lists.newArrayList(); Collection<CallableMemberDescriptor> overriddenDeclarations = OverridingUtil.getOverriddenDeclarations(descriptor);
Set<CallableMemberDescriptor> filteredOverriddenDeclarations = OverridingUtil.filterOverrides(Sets.newHashSet(overriddenDeclarations)); if (overriddenDeclarations.size() == 0) {
boolean allSuperAbstract = true; throw new IllegalStateException("A 'fake override' must override something");
for (CallableMemberDescriptor overridden : filteredOverriddenDeclarations) { }
if (overridden.getModality() != Modality.ABSTRACT) {
nonAbstractManyImpl.add(overridden); List<CallableMemberDescriptor> nonAbstractManyImpl = Lists.newArrayList();
allSuperAbstract = false; Set<CallableMemberDescriptor> filteredOverriddenDeclarations = OverridingUtil.filterOverrides(Sets.newHashSet(overriddenDeclarations));
}
} boolean allSuperAbstract = true;
if (nonAbstractManyImpl.size() > 1) { for (CallableMemberDescriptor overridden : filteredOverriddenDeclarations) {
manyImpl.addAll(nonAbstractManyImpl); if (overridden.getModality() != Modality.ABSTRACT) {
} if (descriptor.getVisibility() != Visibilities.INVISIBLE_FAKE) {
else if (allSuperAbstract) { nonAbstractManyImpl.add(overridden);
abstractNoImpl.addAll(overriddenDeclarations);
} }
allSuperAbstract = false;
} }
} }
if (nonAbstractManyImpl.size() > 1) {
manyImpl.addAll(nonAbstractManyImpl);
}
else if (allSuperAbstract) {
abstractNoImpl.addAll(overriddenDeclarations);
}
} }
public static Multimap<CallableMemberDescriptor, CallableMemberDescriptor> collectSuperMethods(MutableClassDescriptor classDescriptor) { public static Multimap<CallableMemberDescriptor, CallableMemberDescriptor> collectSuperMethods(MutableClassDescriptor classDescriptor) {
@@ -395,11 +455,12 @@ public class OverrideResolver {
private void checkOverrideForMember(@NotNull CallableMemberDescriptor declared) { private void checkOverrideForMember(@NotNull CallableMemberDescriptor declared) {
JetNamedDeclaration member = (JetNamedDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), declared); JetNamedDeclaration member = (JetNamedDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), declared);
if (member == null) { if (member == null) {
if (declared.getKind() != CallableMemberDescriptor.Kind.DELEGATION) if (declared.getKind() != CallableMemberDescriptor.Kind.DELEGATION) {
throw new IllegalStateException( throw new IllegalStateException(
"decriptor is not resolved to declaration" + "decriptor is not resolved to declaration" +
" and it is not delegate: " + declared + ", DELEGATED: " + " and it is not delegate: " + declared + ", DELEGATED: " +
(declared.getKind() == CallableMemberDescriptor.Kind.DELEGATION)); (declared.getKind() == CallableMemberDescriptor.Kind.DELEGATION));
}
return; return;
} }
@@ -0,0 +1,14 @@
package test
trait A {
private val a: String
get() = "AAAA!"
}
open class C {
private val a: String = ""
}
class Subject : C(), A {
val c = <!INVISIBLE_MEMBER!>a<!>
}
@@ -0,0 +1,13 @@
package test
trait A {
protected val a: String
}
open class C {
protected val a: String = ""
}
class Subject : C(), A {
val c = a
}
@@ -0,0 +1,17 @@
package test
trait A {
protected val a: String
}
trait B {
protected val a: String
}
open class C {
private val a: String = ""
}
class <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>Subject<!> : C(), A, B {
val c = a
}
@@ -15,15 +15,12 @@
*/ */
package org.jetbrains.jet.checkers; package org.jetbrains.jet.checkers;
import junit.framework.Assert;
import junit.framework.Test; import junit.framework.Test;
import junit.framework.TestSuite; import junit.framework.TestSuite;
import java.io.File;
import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.TestMetadata; import org.jetbrains.jet.test.TestMetadata;
import org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve; import java.io.File;
/** This class is generated by {@link org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve}. DO NOT MODIFY MANUALLY */ /** This class is generated by {@link org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve}. DO NOT MODIFY MANUALLY */
public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEagerResolve { public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEagerResolve {
@@ -1646,6 +1643,16 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve", new File("compiler/testData/diagnostics/tests/override"), "kt", false); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve", new File("compiler/testData/diagnostics/tests/override"), "kt", false);
} }
@TestMetadata("AllPrivateFromSuperTypes.kt")
public void testAllPrivateFromSuperTypes() throws Exception {
doTest("compiler/testData/diagnostics/tests/override/AllPrivateFromSuperTypes.kt");
}
@TestMetadata("AllProtectedFromSupertypes.kt")
public void testAllProtectedFromSupertypes() throws Exception {
doTest("compiler/testData/diagnostics/tests/override/AllProtectedFromSupertypes.kt");
}
@TestMetadata("ComplexValRedeclaration.kt") @TestMetadata("ComplexValRedeclaration.kt")
public void testComplexValRedeclaration() throws Exception { public void testComplexValRedeclaration() throws Exception {
doTest("compiler/testData/diagnostics/tests/override/ComplexValRedeclaration.kt"); doTest("compiler/testData/diagnostics/tests/override/ComplexValRedeclaration.kt");
@@ -1751,6 +1758,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/override/ParameterDefaultValues-DefaultValueFromOnlyOneSupertype.kt"); doTest("compiler/testData/diagnostics/tests/override/ParameterDefaultValues-DefaultValueFromOnlyOneSupertype.kt");
} }
@TestMetadata("ProtectedAndPrivateFromSupertypes.kt")
public void testProtectedAndPrivateFromSupertypes() throws Exception {
doTest("compiler/testData/diagnostics/tests/override/ProtectedAndPrivateFromSupertypes.kt");
}
@TestMetadata("SuspiciousCase1.kt") @TestMetadata("SuspiciousCase1.kt")
public void testSuspiciousCase1() throws Exception { public void testSuspiciousCase1() throws Exception {
doTest("compiler/testData/diagnostics/tests/override/SuspiciousCase1.kt"); doTest("compiler/testData/diagnostics/tests/override/SuspiciousCase1.kt");