member visibility inheritance; check visibility is not weaken added

This commit is contained in:
Svetlana Isakova
2012-04-03 16:35:41 +04:00
parent f64920246a
commit e9788c12d9
5 changed files with 182 additions and 9 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.jet.lang.diagnostics;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNameIdentifierOwner;
@@ -32,15 +33,11 @@ import org.jetbrains.jet.resolve.DescriptorRenderer;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import static org.jetbrains.jet.lang.diagnostics.Severity.ERROR;
import static org.jetbrains.jet.lang.diagnostics.Severity.WARNING;
import java.util.*;
import static org.jetbrains.jet.lang.diagnostics.Renderers.*;
import static org.jetbrains.jet.lang.diagnostics.Severity.ERROR;
import static org.jetbrains.jet.lang.diagnostics.Severity.WARNING;
/**
* @author abreslav
@@ -374,7 +371,9 @@ public interface Errors {
}
}, TO_STRING, TO_STRING);
DiagnosticFactory2<PsiElement, CallableMemberDescriptor, DeclarationDescriptor> OVERRIDING_FINAL_MEMBER = DiagnosticFactory2.create(ERROR, "{0} in {1} is final and cannot be overridden", NAME, NAME);
DiagnosticFactory2<PsiElement, CallableMemberDescriptor, DeclarationDescriptor> OVERRIDING_FINAL_MEMBER = DiagnosticFactory2.create(ERROR, "''{0}'' in ''{1}'' is final and cannot be overridden", NAME, NAME);
DiagnosticFactory3<JetModifierListOwner, Visibility, CallableMemberDescriptor, DeclarationDescriptor> CANNOT_WEAKEN_ACCESS_PRIVILEGE = DiagnosticFactory3.create(ERROR, "Cannot weaken access privilege ''{0}'' for ''{1}'' in ''{2}''", PositioningStrategies.POSITION_VISIBILITY_MODIFIER, TO_STRING, NAME, NAME);
DiagnosticFactory3<JetModifierListOwner, Visibility, CallableMemberDescriptor, DeclarationDescriptor> CANNOT_CHANGE_ACCESS_PRIVILEGE = DiagnosticFactory3.create(ERROR, "Cannot change access privilege ''{0}'' for ''{1}'' in ''{2}''", PositioningStrategies.POSITION_VISIBILITY_MODIFIER, TO_STRING, NAME, NAME);
DiagnosticFactory2<JetNamedDeclaration, CallableMemberDescriptor, CallableMemberDescriptor> RETURN_TYPE_MISMATCH_ON_OVERRIDE =
DiagnosticFactory2.create(ERROR, "Return type of {0} is not a subtype of the return type overridden member {1}", PositioningStrategies.POSITION_DECLARATION, DescriptorRenderer.TEXT, DescriptorRenderer.TEXT);
@@ -17,6 +17,7 @@
package org.jetbrains.jet.lang.diagnostics;
import com.google.common.collect.Lists;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
@@ -111,4 +112,20 @@ public class PositioningStrategies {
return markElement(element.getIndicesNode());
}
};
public static PositioningStrategy<JetModifierListOwner> POSITION_VISIBILITY_MODIFIER = new PositioningStrategy<JetModifierListOwner>() {
@NotNull
@Override
public List<TextRange> mark(@NotNull JetModifierListOwner element) {
List<JetKeywordToken> visibilityTokens = Lists
.newArrayList(JetTokens.PRIVATE_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PUBLIC_KEYWORD, JetTokens.INTERNAL_KEYWORD);
List<TextRange> result = Lists.newArrayList();
for (JetKeywordToken token : visibilityTokens) {
if (element.hasModifier(token)) {
result.add(element.getModifierList().getModifierNode(token).getTextRange());
}
}
return result;
}
};
}
@@ -69,6 +69,9 @@ public class OverrideResolver {
public void process() {
generateOverrides();
checkOverrides();
//functions and properties visibility can be inherited when overriding, so it can be resolved only after overrides resolve is finished
//also invisible overridden descriptors are removed here
resolveVisibilityForFunctionsAndProperties();
}
/**
@@ -417,4 +420,73 @@ public class OverrideResolver {
}
return false;
}
private void resolveVisibilityForFunctionsAndProperties() {
for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : context.getFunctions().entrySet()) {
JetNamedFunction function = entry.getKey();
SimpleFunctionDescriptor functionDescriptor = entry.getValue();
Visibility visibility = resolveVisibilityForMember(function, functionDescriptor);
((SimpleFunctionDescriptorImpl) functionDescriptor).setVisibility(visibility);
}
for (Map.Entry<JetProperty, PropertyDescriptor> entry : context.getProperties().entrySet()) {
JetProperty property = entry.getKey();
PropertyDescriptor propertyDescriptor = entry.getValue();
Visibility visibility = resolveVisibilityForMember(property, propertyDescriptor);
propertyDescriptor.setVisibility(visibility);
}
}
private Visibility resolveVisibilityForMember(JetDeclaration member, CallableMemberDescriptor memberDescriptor) {
removeInvisibleOverriddenDescriptors(memberDescriptor);
Visibility defaultVisibility = findMaxVisibility(memberDescriptor.getOverriddenDescriptors());
Visibility visibility = DescriptorResolver.resolveVisibilityFromModifiers(member.getModifierList(), defaultVisibility);
checkMaxVisibility(visibility, member, memberDescriptor.getOverriddenDescriptors());
return visibility;
}
private void removeInvisibleOverriddenDescriptors(@NotNull CallableDescriptor descriptor) {
Set<? extends CallableDescriptor> overriddenDescriptors = descriptor.getOverriddenDescriptors();
for (Iterator<? extends CallableDescriptor> iterator = overriddenDescriptors.iterator(); iterator.hasNext(); ) {
CallableDescriptor superDescriptor = iterator.next();
if (!Visibilities.isVisible(superDescriptor, descriptor)) {
iterator.remove();
}
}
}
private Visibility findMaxVisibility(@NotNull Collection<? extends DeclarationDescriptorWithVisibility> descriptors) {
Visibility maxVisibility = null;
for (DeclarationDescriptorWithVisibility descriptor : descriptors) {
Visibility visibility = descriptor.getVisibility();
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;
}
}
return maxVisibility != null ? maxVisibility : Visibilities.INTERNAL;
}
private void checkMaxVisibility(@NotNull Visibility visibility, @NotNull JetModifierListOwner modifierListOwner, @NotNull Collection<? extends CallableMemberDescriptor> descriptors) {
for (CallableMemberDescriptor descriptor : descriptors) {
Integer compare = Visibilities.compare(visibility, descriptor.getVisibility());
if (compare == null) {
trace.report(CANNOT_CHANGE_ACCESS_PRIVILEGE.on(modifierListOwner, descriptor.getVisibility(), descriptor, descriptor.getContainingDeclaration()));
return;
}
else if (compare < 0) {
trace.report(CANNOT_WEAKEN_ACCESS_PRIVILEGE.on(modifierListOwner, descriptor.getVisibility(), descriptor, descriptor.getContainingDeclaration()));
return;
}
}
}
}
@@ -1,5 +1,5 @@
public abstract class BaseClass() {
protected open val kind : String = "BaseClass "
open val kind : String = "BaseClass "
fun getKindValue() : String {
return kind
@@ -0,0 +1,85 @@
package b
open class A {
internal open fun foo() {}
}
class B : A() {
<!CANNOT_CHANGE_ACCESS_PRIVILEGE!>protected<!> override fun foo() {}
}
class C : A() {
internal override fun foo() {}
}
//------------
open class D {
private open fun self() : D = this
}
class E : D() {
internal override fun self() = this
fun test() {
val <!UNUSED_VARIABLE!>s<!> : E = self()
}
}
//------------
open class F {
protected open fun protected_fun() {}
}
class G : F() {
override fun protected_fun() {}
}
fun test_fun_stays_protected(g: G) {
g.<!UNRESOLVED_REFERENCE!>protected_fun<!>()
}
//------------
open class H {
internal protected open fun pi_fun() {}
}
class I : H() {
protected override fun pi_fun() {}
}
class J : H() {
internal override fun pi_fun() {}
}
class K : H() {
public override fun pi_fun() {}
}
//-------------
trait T {
public fun foo() {}
}
open class L : T {
override fun foo() {}
}
class M : L() {
<!CANNOT_WEAKEN_ACCESS_PRIVILEGE!>internal<!> override fun foo() {}
}
//---------------
trait R {
internal protected fun foo() {}
}
trait P : R {
internal override fun foo() {}
}
trait Q : R {
protected override fun foo() {}
}
class S : P, Q {
<!CANNOT_CHANGE_ACCESS_PRIVILEGE!>internal<!> override fun foo() {}
}