member visibility inheritance; check visibility is not weaken added
This commit is contained in:
@@ -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() {}
|
||||
}
|
||||
Reference in New Issue
Block a user