KT-151 Inherit visibility when overriding

#KT-151 Fixed

Visibilities.INHERITED constant added (occurs only during resolve), changed after overridden descriptors resolve
Fake descriptors are created for invisible properties as well (is necessary for better error reporting)
This commit is contained in:
Svetlana Isakova
2012-04-18 19:01:26 +04:00
parent b5bf4a626c
commit 1ed79d534f
14 changed files with 236 additions and 99 deletions
@@ -1394,7 +1394,7 @@ public class JavaDescriptorResolver {
if (owner instanceof ClassDescriptor) { if (owner instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) owner; ClassDescriptor classDescriptor = (ClassDescriptor) owner;
OverrideResolver.generateOverridesInFunctionGroup(propertyName, propertiesFromSupertypes, propertiesFromCurrent, classDescriptor, new OverrideResolver.DescriptorSink() { OverrideResolver.generateOverridesInFunctionGroup(propertyName, null, propertiesFromSupertypes, propertiesFromCurrent, classDescriptor, new OverrideResolver.DescriptorSink() {
@Override @Override
public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) { public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) {
properties.add((PropertyDescriptor) fakeOverride); properties.add((PropertyDescriptor) fakeOverride);
@@ -1433,7 +1433,7 @@ public class JavaDescriptorResolver {
Set<SimpleFunctionDescriptor> functionsFromSupertypes = getFunctionsFromSupertypes(scopeData, methodName); Set<SimpleFunctionDescriptor> functionsFromSupertypes = getFunctionsFromSupertypes(scopeData, methodName);
OverrideResolver.generateOverridesInFunctionGroup(methodName, functionsFromSupertypes, functionsFromCurrent, classDescriptor, new OverrideResolver.DescriptorSink() { OverrideResolver.generateOverridesInFunctionGroup(methodName, null, functionsFromSupertypes, functionsFromCurrent, classDescriptor, new OverrideResolver.DescriptorSink() {
@Override @Override
public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) { public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) {
functions.add((FunctionDescriptor) fakeOverride); functions.add((FunctionDescriptor) fakeOverride);
@@ -106,6 +106,10 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorImpl i
return this; return this;
} }
public void setVisibility(@NotNull Visibility visibility) {
this.visibility = visibility;
}
public void setReturnType(@NotNull JetType unsubstitutedReturnType) { public void setReturnType(@NotNull JetType unsubstitutedReturnType) {
this.unsubstitutedReturnType = unsubstitutedReturnType; this.unsubstitutedReturnType = unsubstitutedReturnType;
} }
@@ -34,9 +34,9 @@ public abstract class PropertyAccessorDescriptor extends DeclarationDescriptorIm
private final boolean hasBody; private final boolean hasBody;
private final boolean isDefault; private final boolean isDefault;
private final Modality modality; private final Modality modality;
private final Visibility visibility;
private final PropertyDescriptor correspondingProperty; private final PropertyDescriptor correspondingProperty;
private final Kind kind; private final Kind kind;
private Visibility visibility;
public PropertyAccessorDescriptor( public PropertyAccessorDescriptor(
@NotNull Modality modality, @NotNull Modality modality,
@@ -99,6 +99,10 @@ public abstract class PropertyAccessorDescriptor extends DeclarationDescriptorIm
return visibility; return visibility;
} }
public void setVisibility(Visibility visibility) {
this.visibility = visibility;
}
@NotNull @NotNull
public PropertyDescriptor getCorrespondingProperty() { public PropertyDescriptor getCorrespondingProperty() {
return correspondingProperty; return correspondingProperty;
@@ -131,6 +131,10 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
this.setter = setter; this.setter = setter;
} }
public void setVisibility(@NotNull Visibility visibility) {
this.visibility = visibility;
}
@NotNull @NotNull
@Override @Override
public List<TypeParameterDescriptor> getTypeParameters() { public List<TypeParameterDescriptor> getTypeParameters() {
@@ -32,6 +32,9 @@ public class Visibilities {
public static final Visibility PRIVATE = new Visibility("private", false) { public static final Visibility PRIVATE = new Visibility("private", false) {
@Override @Override
protected boolean isVisible(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) { protected boolean isVisible(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
if (what instanceof CallableMemberDescriptor && ((CallableMemberDescriptor)what).getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
return false;
}
DeclarationDescriptor parent = what; DeclarationDescriptor parent = what;
while (parent != null) { while (parent != null) {
parent = parent.getContainingDeclaration(); parent = parent.getContainingDeclaration();
@@ -93,7 +96,14 @@ public class Visibilities {
public static final Visibility LOCAL = new Visibility("local", false) { public static final Visibility LOCAL = new Visibility("local", false) {
@Override @Override
protected boolean isVisible(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) { protected boolean isVisible(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
return true; throw new IllegalStateException(); //This method shouldn't be invoked for LOCAL visibility
}
};
public static final Visibility INHERITED = new Visibility("inherited", false) {
@Override
protected boolean isVisible(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
throw new IllegalStateException("Visibility is unknown yet"); //This method shouldn't be invoked for INHERITED visibility
} }
}; };
@@ -102,6 +112,9 @@ public class Visibilities {
public static boolean isVisible(DeclarationDescriptorWithVisibility what, DeclarationDescriptor from) { public static boolean isVisible(DeclarationDescriptorWithVisibility what, DeclarationDescriptor from) {
DeclarationDescriptorWithVisibility parent = what; DeclarationDescriptorWithVisibility parent = what;
while (parent != null) { while (parent != null) {
if (parent.getVisibility() == LOCAL) {
return true;
}
if (!parent.getVisibility().isVisible(parent, from)) { if (!parent.getVisibility().isVisible(parent, from)) {
return false; return false;
} }
@@ -157,7 +157,10 @@ public interface Errors {
DiagnosticFactory<JetDelegatorToSuperClass> INITIALIZER_WITH_NO_ARGUMENTS = DiagnosticFactory.create(ERROR, "Constructor arguments required"); DiagnosticFactory<JetDelegatorToSuperClass> INITIALIZER_WITH_NO_ARGUMENTS = DiagnosticFactory.create(ERROR, "Constructor arguments required");
DiagnosticFactory<JetDelegationSpecifier> MANY_CALLS_TO_THIS = DiagnosticFactory.create(ERROR, "Only one call to 'this(...)' is allowed"); DiagnosticFactory<JetDelegationSpecifier> MANY_CALLS_TO_THIS = DiagnosticFactory.create(ERROR, "Only one call to 'this(...)' is allowed");
DiagnosticFactory1<JetModifierListOwner, CallableMemberDescriptor> NOTHING_TO_OVERRIDE = DiagnosticFactory1.create(ERROR, "{0} overrides nothing", PositioningStrategies.positionModifier(JetTokens.OVERRIDE_KEYWORD), DescriptorRenderer.TEXT); DiagnosticFactory1<JetModifierListOwner, CallableMemberDescriptor> NOTHING_TO_OVERRIDE = DiagnosticFactory1.create(ERROR, "{0} overrides nothing", PositioningStrategies.positionModifier(JetTokens.OVERRIDE_KEYWORD), DescriptorRenderer.TEXT);
DiagnosticFactory3<PsiNameIdentifierOwner, CallableMemberDescriptor, CallableMemberDescriptor, DeclarationDescriptor> VIRTUAL_MEMBER_HIDDEN = DiagnosticFactory3.create(ERROR, "''{0}'' hides ''{1}'' in class {2} and needs 'override' modifier", PositioningStrategies.POSITION_NAME_IDENTIFIER, DescriptorRenderer.TEXT, DescriptorRenderer.TEXT, DescriptorRenderer.TEXT); DiagnosticFactory3<PsiNameIdentifierOwner, CallableMemberDescriptor, CallableMemberDescriptor, DeclarationDescriptor> VIRTUAL_MEMBER_HIDDEN =
DiagnosticFactory3.create(ERROR, "''{0}'' hides ''{1}'' in class {2} and needs 'override' modifier", PositioningStrategies.POSITION_NAME_IDENTIFIER, DescriptorRenderer.TEXT, DescriptorRenderer.TEXT, DescriptorRenderer.TEXT);
DiagnosticFactory3<JetModifierListOwner, CallableMemberDescriptor, CallableDescriptor, DeclarationDescriptor> CANNOT_OVERRIDE_INVISIBLE_MEMBER =
DiagnosticFactory3.create(ERROR, "''{0}'' cannot has no access to ''{1}'' in class {2}, so it cannot override it", PositioningStrategies.positionModifier(JetTokens.OVERRIDE_KEYWORD), DescriptorRenderer.TEXT, DescriptorRenderer.TEXT, DescriptorRenderer.TEXT);
DiagnosticFactory1<JetClass, ClassDescriptor> ENUM_ENTRY_SHOULD_BE_INITIALIZED = DiagnosticFactory1.create(ERROR, "Missing delegation specifier ''{0}''", PositioningStrategies.POSITION_NAME_IDENTIFIER, NAME); DiagnosticFactory1<JetClass, ClassDescriptor> ENUM_ENTRY_SHOULD_BE_INITIALIZED = DiagnosticFactory1.create(ERROR, "Missing delegation specifier ''{0}''", PositioningStrategies.POSITION_NAME_IDENTIFIER, NAME);
DiagnosticFactory1<JetTypeReference, ClassDescriptor> ENUM_ENTRY_ILLEGAL_TYPE = DiagnosticFactory1.create(ERROR, "The type constructor of enum entry should be ''{0}''", NAME); DiagnosticFactory1<JetTypeReference, ClassDescriptor> ENUM_ENTRY_ILLEGAL_TYPE = DiagnosticFactory1.create(ERROR, "The type constructor of enum entry should be ''{0}''", NAME);
@@ -223,7 +223,7 @@ public class DeclarationResolver {
parameter, trace parameter, trace
); );
classDescriptor.addPropertyDescriptor(propertyDescriptor); classDescriptor.addPropertyDescriptor(propertyDescriptor);
context.getPrimaryConstructorParameterProperties().add(propertyDescriptor); context.getPrimaryConstructorParameterProperties().put(parameter, propertyDescriptor);
} }
} }
if (constructorDescriptor != null) { if (constructorDescriptor != null) {
@@ -673,7 +673,8 @@ public class DescriptorResolver {
@NotNull @NotNull
/*package*/ static Visibility resolveVisibilityFromModifiers(@Nullable JetModifierList modifierList) { /*package*/ static Visibility resolveVisibilityFromModifiers(@Nullable JetModifierList modifierList) {
return resolveVisibilityFromModifiers(modifierList, Visibilities.INTERNAL); Visibility defaultVisibility = modifierList != null && modifierList.hasModifier(JetTokens.OVERRIDE_KEYWORD) ? Visibilities.INHERITED : Visibilities.INTERNAL;
return resolveVisibilityFromModifiers(modifierList, defaultVisibility);
} }
@NotNull @NotNull
@@ -16,14 +16,13 @@
package org.jetbrains.jet.lang.resolve; package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists; import com.google.common.collect.*;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.util.containers.LinkedMultiMap; import com.intellij.util.containers.LinkedMultiMap;
import com.intellij.util.containers.MultiMap; import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
@@ -67,15 +66,26 @@ public class OverrideResolver {
public void process() { public void process() {
generateOverrides(); //all created fake descriptors are stored to resolve visibility on them later
checkOverrides(); Set<CallableMemberDescriptor> fakeOverrides = Sets.newHashSet();
checkVisibilityForOverriddenMembers(); generateOverrides(fakeOverrides);
//functions and properties visibility can be inherited when overriding, so for overridden members
//it can be resolved only after overrides resolve is finished
resolveUnknownVisibilityForMembers(fakeOverrides);
//invisible overridden descriptors are saved for proper error reporting
Multimap<CallableDescriptor, CallableDescriptor> invisibleOverriddenDescriptors = LinkedHashMultimap.create();
removeInvisibleOverriddenDescriptors(invisibleOverriddenDescriptors);
checkVisibility();
checkOverrides(invisibleOverriddenDescriptors);
} }
/** /**
* Generate fake overrides and add overriden descriptors to existing descriptors. * Generate fake overrides and add overridden descriptors to existing descriptors.
*/ */
private void generateOverrides() { private void generateOverrides(@NotNull Set<CallableMemberDescriptor> fakeOverrides) {
Set<MutableClassDescriptor> ourClasses = new HashSet<MutableClassDescriptor>(); Set<MutableClassDescriptor> ourClasses = new HashSet<MutableClassDescriptor>();
ourClasses.addAll(context.getClasses().values()); ourClasses.addAll(context.getClasses().values());
ourClasses.addAll(context.getObjects().values()); ourClasses.addAll(context.getObjects().values());
@@ -83,11 +93,12 @@ public class OverrideResolver {
Set<ClassifierDescriptor> processed = new HashSet<ClassifierDescriptor>(); Set<ClassifierDescriptor> processed = new HashSet<ClassifierDescriptor>();
for (MutableClassDescriptor clazz : ourClasses) { for (MutableClassDescriptor clazz : ourClasses) {
generateOverridesInAClass(clazz, processed, ourClasses); generateOverridesInAClass(clazz, processed, ourClasses, fakeOverrides);
} }
} }
private void generateOverridesInAClass(final MutableClassDescriptor classDescriptor, Set<ClassifierDescriptor> processed, Set<MutableClassDescriptor> ourClasses) { private void generateOverridesInAClass(@NotNull final MutableClassDescriptor classDescriptor, @NotNull Set<ClassifierDescriptor> processed,
@NotNull Set<MutableClassDescriptor> ourClasses, @NotNull Set<CallableMemberDescriptor> fakeOverrides) {
if (!processed.add(classDescriptor)) { if (!processed.add(classDescriptor)) {
return; return;
} }
@@ -100,7 +111,7 @@ public class OverrideResolver {
for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
ClassDescriptor superclass = (ClassDescriptor) supertype.getConstructor().getDeclarationDescriptor(); ClassDescriptor superclass = (ClassDescriptor) supertype.getConstructor().getDeclarationDescriptor();
if (superclass instanceof MutableClassDescriptor) { if (superclass instanceof MutableClassDescriptor) {
generateOverridesInAClass((MutableClassDescriptor) superclass, processed, ourClasses); generateOverridesInAClass((MutableClassDescriptor) superclass, processed, ourClasses, fakeOverrides);
} }
} }
@@ -115,7 +126,7 @@ public class OverrideResolver {
functionNames.addAll(functionsFromCurrentByName.keySet()); functionNames.addAll(functionsFromCurrentByName.keySet());
for (String functionName : functionNames) { for (String functionName : functionNames) {
generateOverridesInFunctionGroup(functionName, generateOverridesInFunctionGroup(functionName, fakeOverrides,
functionsFromSupertypesByName.get(functionName), functionsFromSupertypesByName.get(functionName),
functionsFromCurrentByName.get(functionName), functionsFromCurrentByName.get(functionName),
classDescriptor, classDescriptor,
@@ -150,18 +161,15 @@ public class OverrideResolver {
public static void generateOverridesInFunctionGroup( public static void generateOverridesInFunctionGroup(
@NotNull String name, @NotNull String name,
@Nullable Set<CallableMemberDescriptor> fakeOverrides,
@NotNull Collection<? extends CallableMemberDescriptor> functionsFromSupertypes, @NotNull Collection<? extends CallableMemberDescriptor> functionsFromSupertypes,
@NotNull Collection<? extends CallableMemberDescriptor> functionsFromCurrent, @NotNull Collection<? extends CallableMemberDescriptor> functionsFromCurrent,
@NotNull ClassDescriptor current, @NotNull ClassDescriptor current,
@NotNull DescriptorSink sink) { @NotNull DescriptorSink sink) {
List<CallableMemberDescriptor> fakeOverrides = Lists.newArrayList(); List<CallableMemberDescriptor> fakeOverrideList = Lists.newArrayList();
for (CallableMemberDescriptor functionFromSupertype : functionsFromSupertypes) { for (CallableMemberDescriptor functionFromSupertype : functionsFromSupertypes) {
if (!Visibilities.isVisible(functionFromSupertype, current)) {
continue;
}
boolean overrides = false; boolean overrides = false;
for (CallableMemberDescriptor functionFromCurrent : functionsFromCurrent) { for (CallableMemberDescriptor functionFromCurrent : functionsFromCurrent) {
@@ -175,7 +183,7 @@ public class OverrideResolver {
} }
} }
for (CallableMemberDescriptor fakeOverride : fakeOverrides) { for (CallableMemberDescriptor fakeOverride : fakeOverrideList) {
if (OverridingUtil.isOverridableBy(functionFromSupertype, fakeOverride).getResult() == OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE) { if (OverridingUtil.isOverridableBy(functionFromSupertype, fakeOverride).getResult() == OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE) {
fakeOverride.addOverriddenDescriptor(functionFromSupertype); fakeOverride.addOverriddenDescriptor(functionFromSupertype);
overrides = true; overrides = true;
@@ -185,9 +193,10 @@ public class OverrideResolver {
if (!overrides) { if (!overrides) {
CallableMemberDescriptor fakeOverride = functionFromSupertype.copy(current, false, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false); CallableMemberDescriptor fakeOverride = functionFromSupertype.copy(current, false, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false);
fakeOverride.addOverriddenDescriptor(functionFromSupertype); fakeOverride.addOverriddenDescriptor(functionFromSupertype);
fakeOverrideList.add(fakeOverride);
fakeOverrides.add(fakeOverride); if (fakeOverrides != null) {
fakeOverrides.add(fakeOverride);
}
sink.addToScope(fakeOverride); sink.addToScope(fakeOverride);
} }
} }
@@ -222,21 +231,22 @@ public class OverrideResolver {
return r; return r;
} }
private void checkOverrides() { private void checkOverrides(@NotNull Multimap<CallableDescriptor, CallableDescriptor> invisibleOverriddenDescriptors) {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) { for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
checkOverridesInAClass(entry.getValue(), entry.getKey()); checkOverridesInAClass(entry.getValue(), entry.getKey(), invisibleOverriddenDescriptors);
} }
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) { for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
checkOverridesInAClass(entry.getValue(), entry.getKey()); checkOverridesInAClass(entry.getValue(), entry.getKey(), invisibleOverriddenDescriptors);
} }
} }
protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) { protected void checkOverridesInAClass(@NotNull MutableClassDescriptor classDescriptor, @NotNull JetClassOrObject klass,
@NotNull Multimap<CallableDescriptor, CallableDescriptor> invisibleOverriddenDescriptors) {
if (topDownAnalysisParameters.isAnalyzingBootstrapLibrary()) return; if (topDownAnalysisParameters.isAnalyzingBootstrapLibrary()) return;
// Check overrides for internal consistency // Check overrides for internal consistency
for (CallableMemberDescriptor member : classDescriptor.getCallableMembers()) { for (CallableMemberDescriptor member : classDescriptor.getCallableMembers()) {
checkOverride(member); checkOverrideForMember(member, invisibleOverriddenDescriptors);
} }
// Check if everything that must be overridden, actually is // Check if everything that must be overridden, actually is
@@ -271,34 +281,6 @@ public class OverrideResolver {
trace.report(ABSTRACT_MEMBER_NOT_IMPLEMENTED.on(nameIdentifier, klass, memberDescriptor)); trace.report(ABSTRACT_MEMBER_NOT_IMPLEMENTED.on(nameIdentifier, klass, memberDescriptor));
break; break;
} }
// Set<FunctionDescriptor> allOverriddenFunctions = Sets.newHashSet();
// Collection<DeclarationDescriptor> allDescriptors = classDescriptor.getDefaultType().getMemberScope().getAllDescriptors();
// for (DeclarationDescriptor descriptor : allDescriptors) {
// if (descriptor instanceof FunctionDescriptor) {
// FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
// if (functionDescriptor.getModality() != Modality.ABSTRACT) {
// for (FunctionDescriptor overriddenDescriptor : functionDescriptor.getOverriddenDescriptors()) {
// allOverriddenFunctions.add(overriddenDescriptor.getOriginal());
// }
// }
// }
// }
// boolean foundError = false;
// for (DeclarationDescriptor descriptor : allDescriptors) {
// if (descriptor instanceof FunctionDescriptor) {
// FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
// if (functionDescriptor.getModality() == Modality.ABSTRACT && !allOverriddenFunctions.contains(functionDescriptor.getOriginal()) && !foundError && nameIdentifier != null) {
// DeclarationDescriptor declarationDescriptor = functionDescriptor.getContainingDeclaration();
// if (declarationDescriptor != classDescriptor) {
//// trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Class '" + klass.getName() + "' must be declared abstract or implement abstract method '" +
//// functionDescriptor.getName() + "' declared in " + declarationDescriptor.getName());
// trace.report(ABSTRACT_MEMBER_NOT_IMPLEMENTED.on(nameIdentifier, klass, functionDescriptor));
// foundError = true;
// }
// }
// }
// }
} }
public static void collectMissingImplementations(MutableClassDescriptor classDescriptor, Set<CallableMemberDescriptor> abstractNoImpl, Set<CallableMemberDescriptor> manyImpl) { public static void collectMissingImplementations(MutableClassDescriptor classDescriptor, Set<CallableMemberDescriptor> abstractNoImpl, Set<CallableMemberDescriptor> manyImpl) {
@@ -317,21 +299,21 @@ public class OverrideResolver {
} }
} }
else { else {
Collection<CallableMemberDescriptor> overridenDeclarations = OverridingUtil.getOverridenDeclarations(descriptor); Collection<CallableMemberDescriptor> overriddenDeclarations = OverridingUtil.getOverridenDeclarations(descriptor);
if (overridenDeclarations.size() == 0) { if (overriddenDeclarations.size() == 0) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
else if (overridenDeclarations.size() == 1) { else if (overriddenDeclarations.size() == 1) {
CallableMemberDescriptor single = overridenDeclarations.iterator().next(); CallableMemberDescriptor single = overriddenDeclarations.iterator().next();
if (single.getModality() == Modality.ABSTRACT) { if (single.getModality() == Modality.ABSTRACT) {
abstractNoImpl.add(single); abstractNoImpl.add(single);
} }
} }
else { else {
List<CallableMemberDescriptor> nonAbstractManyImpl = Lists.newArrayList(); List<CallableMemberDescriptor> nonAbstractManyImpl = Lists.newArrayList();
for (CallableMemberDescriptor overriden : overridenDeclarations) { for (CallableMemberDescriptor overridden : overriddenDeclarations) {
if (overriden.getModality() != Modality.ABSTRACT) { if (overridden.getModality() != Modality.ABSTRACT) {
nonAbstractManyImpl.add(overriden); nonAbstractManyImpl.add(overridden);
} }
} }
if (nonAbstractManyImpl.size() > 1) { if (nonAbstractManyImpl.size() > 1) {
@@ -371,7 +353,8 @@ public class OverrideResolver {
return factoredMembers; return factoredMembers;
} }
private void checkOverride(CallableMemberDescriptor declared) { private void checkOverrideForMember(@NotNull CallableMemberDescriptor declared,
@NotNull Multimap<CallableDescriptor, CallableDescriptor> invisibleOverriddenDescriptors) {
JetNamedDeclaration member = (JetNamedDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), declared); JetNamedDeclaration member = (JetNamedDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), declared);
if (member == null) { if (member == null) {
assert trace.get(DELEGATED, declared); assert trace.get(DELEGATED, declared);
@@ -410,7 +393,13 @@ public class OverrideResolver {
} }
} }
if (hasOverrideModifier && declared.getOverriddenDescriptors().size() == 0) { if (hasOverrideModifier && declared.getOverriddenDescriptors().size() == 0) {
trace.report(NOTHING_TO_OVERRIDE.on(member, declared)); if (!invisibleOverriddenDescriptors.get(declared).isEmpty()) {
CallableDescriptor descriptor = invisibleOverriddenDescriptors.values().iterator().next();
trace.report(CANNOT_OVERRIDE_INVISIBLE_MEMBER.on(member, declared, descriptor, descriptor.getContainingDeclaration()));
}
else {
trace.report(NOTHING_TO_OVERRIDE.on(member, declared));
}
} }
PsiElement nameIdentifier = member.getNameIdentifier(); PsiElement nameIdentifier = member.getNameIdentifier();
if (!hasOverrideModifier && declared.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) { if (!hasOverrideModifier && declared.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) {
@@ -427,38 +416,102 @@ public class OverrideResolver {
return false; return false;
} }
private void checkVisibilityForOverriddenMembers() { private void resolveUnknownVisibilityForMembers(@NotNull Set<CallableMemberDescriptor> fakeOverrides) {
for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : context.getFunctions().entrySet()) { for (CallableMemberDescriptor override : fakeOverrides) {
JetNamedFunction function = entry.getKey(); resolveUnknownVisibilityForMember(override);
SimpleFunctionDescriptor functionDescriptor = entry.getValue();
checkVisibilityForMember(functionDescriptor.getVisibility(), function, functionDescriptor.getOverriddenDescriptors());
} }
for (Map.Entry<JetProperty, PropertyDescriptor> entry : context.getProperties().entrySet()) { for (CallableMemberDescriptor memberDescriptor : context.getMembers().values()) {
JetProperty property = entry.getKey(); resolveUnknownVisibilityForMember(memberDescriptor);
PropertyDescriptor propertyDescriptor = entry.getValue();
checkVisibilityForMember(propertyDescriptor.getVisibility(), property, propertyDescriptor.getOverriddenDescriptors());
} }
for (PropertyDescriptor propertyDescriptor : context.getPrimaryConstructorParameterProperties()) { for (PropertyDescriptor propertyDescriptor : context.getProperties().values()) {
PsiElement parameter = BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), propertyDescriptor); for (PropertyAccessorDescriptor accessor : propertyDescriptor.getAccessors()) {
if (parameter instanceof JetParameter) { if (accessor != null && accessor.getVisibility() == Visibilities.INHERITED) {
checkVisibilityForMember(propertyDescriptor.getVisibility(), (JetParameter)parameter, propertyDescriptor.getOverriddenDescriptors()); accessor.setVisibility(propertyDescriptor.getVisibility());
}
} }
} }
} }
private void checkVisibilityForMember(@NotNull Visibility visibility, private void resolveUnknownVisibilityForMember(@NotNull CallableMemberDescriptor memberDescriptor) {
@NotNull JetModifierListOwner modifierListOwner, resolveUnknownVisibilityForOverriddenDescriptors(memberDescriptor.getOverriddenDescriptors());
@NotNull Collection<? extends CallableMemberDescriptor> descriptors) { if (memberDescriptor.getVisibility() != Visibilities.INHERITED) {
return;
}
Visibility visibility = findMaxVisibility(memberDescriptor.getOverriddenDescriptors());
if (memberDescriptor instanceof PropertyDescriptor) {
((PropertyDescriptor)memberDescriptor).setVisibility(visibility);
}
else {
assert memberDescriptor instanceof FunctionDescriptorImpl;
((FunctionDescriptorImpl)memberDescriptor).setVisibility(visibility);
}
}
private void removeInvisibleOverriddenDescriptors(@NotNull Multimap<CallableDescriptor, CallableDescriptor> invisibleOverriddenDescriptors) {
for (CallableMemberDescriptor memberDescriptor : context.getMembers().values()) {
Set<? extends CallableDescriptor> overriddenDescriptors = memberDescriptor.getOverriddenDescriptors();
for (Iterator<? extends CallableDescriptor> iterator = overriddenDescriptors.iterator(); iterator.hasNext(); ) {
CallableDescriptor superDescriptor = iterator.next();
if (!Visibilities.isVisible(superDescriptor, memberDescriptor)) {
invisibleOverriddenDescriptors.put(memberDescriptor, superDescriptor);
iterator.remove();
}
}
}
}
private void resolveUnknownVisibilityForOverriddenDescriptors(@NotNull Collection<? extends CallableMemberDescriptor> descriptors) {
for (CallableMemberDescriptor descriptor : descriptors) { for (CallableMemberDescriptor descriptor : descriptors) {
if (descriptor.getVisibility() == Visibilities.INHERITED) {
resolveUnknownVisibilityForMember(descriptor);
}
}
}
@NotNull
private Visibility findMaxVisibility(@NotNull Collection<? extends CallableMemberDescriptor> descriptors) {
if (descriptors.isEmpty()) {
return Visibilities.INTERNAL;
}
Visibility maxVisibility = null;
for (CallableMemberDescriptor descriptor : descriptors) {
Visibility visibility = descriptor.getVisibility();
assert visibility != Visibilities.INHERITED;
if (maxVisibility == null) {
maxVisibility = visibility;
continue;
}
Integer compare = Visibilities.compare(visibility, maxVisibility);
if (compare == null) {
maxVisibility = Visibilities.PUBLIC; //todo error or warning when inference only from incomparable visibilities
continue;
}
if (compare > 0) {
maxVisibility = visibility;
}
}
assert maxVisibility != null;
return maxVisibility;
}
private void checkVisibility() {
for (Map.Entry<JetDeclaration, CallableMemberDescriptor> entry : context.getMembers().entrySet()) {
checkVisibilityForMember(entry.getKey(), entry.getValue());
}
}
private void checkVisibilityForMember(@NotNull JetDeclaration declaration, @NotNull CallableMemberDescriptor memberDescriptor) {
Visibility visibility = memberDescriptor.getVisibility();
for (CallableMemberDescriptor descriptor : memberDescriptor.getOverriddenDescriptors()) {
Integer compare = Visibilities.compare(visibility, descriptor.getVisibility()); Integer compare = Visibilities.compare(visibility, descriptor.getVisibility());
if (compare == null) { if (compare == null) {
trace.report(CANNOT_CHANGE_ACCESS_PRIVILEGE.on(modifierListOwner, descriptor.getVisibility(), descriptor, descriptor.getContainingDeclaration())); trace.report(CANNOT_CHANGE_ACCESS_PRIVILEGE.on(declaration, descriptor.getVisibility(), descriptor, descriptor.getContainingDeclaration()));
return; return;
} }
if (compare < 0) { else if (compare < 0) {
trace.report(CANNOT_WEAKEN_ACCESS_PRIVILEGE.on(modifierListOwner, descriptor.getVisibility(), descriptor, descriptor.getContainingDeclaration())); trace.report(CANNOT_WEAKEN_ACCESS_PRIVILEGE.on(declaration, descriptor.getVisibility(), descriptor, descriptor.getContainingDeclaration()));
return; return;
} }
} }
@@ -16,6 +16,7 @@
package org.jetbrains.jet.lang.resolve; package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
@@ -46,7 +47,8 @@ public class TopDownAnalysisContext {
private final Map<JetNamedFunction, SimpleFunctionDescriptor> functions = Maps.newLinkedHashMap(); private final Map<JetNamedFunction, SimpleFunctionDescriptor> functions = Maps.newLinkedHashMap();
private final Map<JetSecondaryConstructor, ConstructorDescriptor> constructors = Maps.newLinkedHashMap(); private final Map<JetSecondaryConstructor, ConstructorDescriptor> constructors = Maps.newLinkedHashMap();
private final Map<JetProperty, PropertyDescriptor> properties = Maps.newLinkedHashMap(); private final Map<JetProperty, PropertyDescriptor> properties = Maps.newLinkedHashMap();
private final Set<PropertyDescriptor> primaryConstructorParameterProperties = Sets.newHashSet(); private final Map<JetParameter, PropertyDescriptor> primaryConstructorParameterProperties = Maps.newHashMap();
private Map<JetDeclaration, CallableMemberDescriptor> members = null;
private StringBuilder debugOutput; private StringBuilder debugOutput;
@@ -114,7 +116,7 @@ public class TopDownAnalysisContext {
return namespaceDescriptors; return namespaceDescriptors;
} }
public Set<PropertyDescriptor> getPrimaryConstructorParameterProperties() { public Map<JetParameter, PropertyDescriptor> getPrimaryConstructorParameterProperties() {
return primaryConstructorParameterProperties; return primaryConstructorParameterProperties;
} }
@@ -134,4 +136,13 @@ public class TopDownAnalysisContext {
return functions; return functions;
} }
public Map<JetDeclaration, CallableMemberDescriptor> getMembers() {
if (members == null) {
members = Maps.newHashMap();
members.putAll(functions);
members.putAll(properties);
members.putAll(primaryConstructorParameterProperties);
}
return members;
}
} }
@@ -18,7 +18,7 @@ open class D {
} }
class E : D() { class E : D() {
internal <!NOTHING_TO_OVERRIDE!>override<!> fun self() = this internal <!CANNOT_OVERRIDE_INVISIBLE_MEMBER!>override<!> fun self() = this
fun test() { fun test() {
val <!UNUSED_VARIABLE!>s<!> : E = self() val <!UNUSED_VARIABLE!>s<!> : E = self()
@@ -31,7 +31,11 @@ open class F {
} }
class G : F() { class G : F() {
<!CANNOT_CHANGE_ACCESS_PRIVILEGE!>override<!> fun protected_fun() {} override fun protected_fun() {}
}
fun test_fun_stays_protected(g: G) {
g.<!INVISIBLE_MEMBER!>protected_fun<!>()
} }
//------------ //------------
@@ -57,11 +61,11 @@ trait T {
} }
open class L : T { open class L : T {
<!CANNOT_WEAKEN_ACCESS_PRIVILEGE!>override<!> fun foo() {} override fun foo() {}
} }
class M : L() { class M : L() {
internal override fun foo() {} <!CANNOT_WEAKEN_ACCESS_PRIVILEGE!>internal<!> override fun foo() {}
} }
//--------------- //---------------
trait R { trait R {
@@ -0,0 +1,40 @@
//KT-151 Inherit visibility when overriding
package kt151
open class A {
protected open fun x() {}
}
class B : A() {
override fun x() {} // No visibility modifier required
}
fun test(b: B) {
b.<!INVISIBLE_MEMBER!>x<!>()
}
//more tests
open class C {
internal open fun foo() {}
}
trait T {
protected fun foo() {}
}
class D : C(), T {
<!CANNOT_CHANGE_ACCESS_PRIVILEGE!>protected<!> override fun foo() {}
}
class E : C(), T {
<!CANNOT_CHANGE_ACCESS_PRIVILEGE!>internal<!> override fun foo() {}
}
class F : C(), T {
<!CANNOT_WEAKEN_ACCESS_PRIVILEGE!>private<!> override fun foo() {}
}
class G : C(), T {
override fun foo() {}
}
@@ -4,5 +4,5 @@ open class A {
} }
class B : A() { class B : A() {
<caret>override fun run() {} <caret>internal override fun run() {}
} }
@@ -4,6 +4,6 @@ trait ParseResult<out T> {
public val value : T public val value : T
} }
class Success<T>(<caret>override val value : T) : ParseResult<T> { class Success<T>(<caret>internal override val value : T) : ParseResult<T> {
public override val success : Boolean = true public override val success : Boolean = true
} }