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;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
@@ -175,83 +177,134 @@ public class OverrideResolver {
}
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> membersFromCurrent,
@NotNull ClassDescriptor current,
@NotNull DescriptorSink sink
) {
List<CallableMemberDescriptor> notOverridden = Lists.newArrayList(membersFromSupertypes);
for (CallableMemberDescriptor fromCurrent : membersFromCurrent) {
// 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;
}
}
extractAndBindOverridesForMember(fromCurrent, notOverridden, current, sink);
}
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);
while (!fromSuperQueue.isEmpty()) {
CallableMemberDescriptor aFromSuper = fromSuperQueue.remove();
Collection<CallableMemberDescriptor> overridableByA = Lists.newArrayList();
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);
CallableMemberDescriptor notOverriddenFromSuper = fromSuperQueue.remove();
Collection<CallableMemberDescriptor> overridables = extractMembersOverridableBy(notOverriddenFromSuper, fromSuperQueue, sink);
bindFakeOverride(notOverriddenFromSuper, overridables, current, sink);
}
}
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) {
MultiMap<Name, T> r = new LinkedMultiMap<Name, T>();
for (T property : properties) {
@@ -336,30 +389,37 @@ public class OverrideResolver {
}
}
private static void collectMissingImplementations(CallableMemberDescriptor descriptor, Set<CallableMemberDescriptor> abstractNoImpl, Set<CallableMemberDescriptor> manyImpl) {
if (!descriptor.getKind().isReal()) {
Collection<CallableMemberDescriptor> overriddenDeclarations = OverridingUtil.getOverriddenDeclarations(descriptor);
if (overriddenDeclarations.size() == 0) {
throw new IllegalStateException("A 'fake override' must override something");
}
else {
List<CallableMemberDescriptor> nonAbstractManyImpl = Lists.newArrayList();
Set<CallableMemberDescriptor> filteredOverriddenDeclarations = OverridingUtil.filterOverrides(Sets.newHashSet(overriddenDeclarations));
boolean allSuperAbstract = true;
for (CallableMemberDescriptor overridden : filteredOverriddenDeclarations) {
if (overridden.getModality() != Modality.ABSTRACT) {
nonAbstractManyImpl.add(overridden);
allSuperAbstract = false;
}
}
if (nonAbstractManyImpl.size() > 1) {
manyImpl.addAll(nonAbstractManyImpl);
}
else if (allSuperAbstract) {
abstractNoImpl.addAll(overriddenDeclarations);
private static void collectMissingImplementations(
@NotNull CallableMemberDescriptor descriptor,
@NotNull Set<CallableMemberDescriptor> abstractNoImpl,
@NotNull Set<CallableMemberDescriptor> manyImpl
) {
if (descriptor.getKind().isReal()) return;
Collection<CallableMemberDescriptor> overriddenDeclarations = OverridingUtil.getOverriddenDeclarations(descriptor);
if (overriddenDeclarations.size() == 0) {
throw new IllegalStateException("A 'fake override' must override something");
}
List<CallableMemberDescriptor> nonAbstractManyImpl = Lists.newArrayList();
Set<CallableMemberDescriptor> filteredOverriddenDeclarations = OverridingUtil.filterOverrides(Sets.newHashSet(overriddenDeclarations));
boolean allSuperAbstract = true;
for (CallableMemberDescriptor overridden : filteredOverriddenDeclarations) {
if (overridden.getModality() != Modality.ABSTRACT) {
if (descriptor.getVisibility() != Visibilities.INVISIBLE_FAKE) {
nonAbstractManyImpl.add(overridden);
}
allSuperAbstract = false;
}
}
if (nonAbstractManyImpl.size() > 1) {
manyImpl.addAll(nonAbstractManyImpl);
}
else if (allSuperAbstract) {
abstractNoImpl.addAll(overriddenDeclarations);
}
}
public static Multimap<CallableMemberDescriptor, CallableMemberDescriptor> collectSuperMethods(MutableClassDescriptor classDescriptor) {
@@ -395,11 +455,12 @@ public class OverrideResolver {
private void checkOverrideForMember(@NotNull CallableMemberDescriptor declared) {
JetNamedDeclaration member = (JetNamedDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), declared);
if (member == null) {
if (declared.getKind() != CallableMemberDescriptor.Kind.DELEGATION)
if (declared.getKind() != CallableMemberDescriptor.Kind.DELEGATION) {
throw new IllegalStateException(
"decriptor is not resolved to declaration" +
" and it is not delegate: " + declared + ", DELEGATED: " +
(declared.getKind() == CallableMemberDescriptor.Kind.DELEGATION));
}
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;
import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestSuite;
import java.io.File;
import org.jetbrains.jet.JetTestUtils;
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 */
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);
}
@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")
public void testComplexValRedeclaration() throws Exception {
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");
}
@TestMetadata("ProtectedAndPrivateFromSupertypes.kt")
public void testProtectedAndPrivateFromSupertypes() throws Exception {
doTest("compiler/testData/diagnostics/tests/override/ProtectedAndPrivateFromSupertypes.kt");
}
@TestMetadata("SuspiciousCase1.kt")
public void testSuspiciousCase1() throws Exception {
doTest("compiler/testData/diagnostics/tests/override/SuspiciousCase1.kt");