member visibility inheritance; check visibility is not weaken added
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.lang.diagnostics;
|
package org.jetbrains.jet.lang.diagnostics;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.intellij.openapi.util.TextRange;
|
import com.intellij.openapi.util.TextRange;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||||
@@ -32,15 +33,11 @@ import org.jetbrains.jet.resolve.DescriptorRenderer;
|
|||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
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 static org.jetbrains.jet.lang.diagnostics.Renderers.*;
|
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
|
* @author abreslav
|
||||||
@@ -374,7 +371,9 @@ public interface Errors {
|
|||||||
}
|
}
|
||||||
}, TO_STRING, TO_STRING);
|
}, 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<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);
|
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;
|
package org.jetbrains.jet.lang.diagnostics;
|
||||||
|
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
import com.intellij.openapi.util.TextRange;
|
import com.intellij.openapi.util.TextRange;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
@@ -111,4 +112,20 @@ public class PositioningStrategies {
|
|||||||
return markElement(element.getIndicesNode());
|
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() {
|
public void process() {
|
||||||
generateOverrides();
|
generateOverrides();
|
||||||
checkOverrides();
|
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;
|
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() {
|
public abstract class BaseClass() {
|
||||||
protected open val kind : String = "BaseClass "
|
open val kind : String = "BaseClass "
|
||||||
|
|
||||||
fun getKindValue() : String {
|
fun getKindValue() : String {
|
||||||
return kind
|
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() {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user