diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java index 1b7057a76d4..cf468bee683 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java @@ -14,7 +14,7 @@ import java.util.Set; /** * @author abreslav */ -public interface ClassDescriptor extends ClassifierDescriptor { +public interface ClassDescriptor extends ClassifierDescriptor, MemberDescriptor { @NotNull JetScope getMemberScope(List typeArguments); @@ -53,9 +53,11 @@ public interface ClassDescriptor extends ClassifierDescriptor { @NotNull ClassKind getKind(); + @Override @NotNull Modality getModality(); - + + @Override @NotNull Visibility getVisibility(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/DeclarationDescriptorWithVisibility.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/DeclarationDescriptorWithVisibility.java new file mode 100644 index 00000000000..eab9e41ff5d --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/DeclarationDescriptorWithVisibility.java @@ -0,0 +1,11 @@ +package org.jetbrains.jet.lang.descriptors; + +import org.jetbrains.annotations.NotNull; + +/** + * @author abreslav + */ +public interface DeclarationDescriptorWithVisibility extends DeclarationDescriptor { + @NotNull + Visibility getVisibility(); +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MemberDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MemberDescriptor.java index 5327b981133..29940086e89 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MemberDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MemberDescriptor.java @@ -5,10 +5,11 @@ import org.jetbrains.annotations.NotNull; /** * @author abreslav */ -public interface MemberDescriptor { +public interface MemberDescriptor extends DeclarationDescriptor, DeclarationDescriptorWithVisibility { @NotNull Modality getModality(); - + + @Override @NotNull Visibility getVisibility(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/Visibility.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/Visibility.java index e2c5364dfe3..4b6e70e2e77 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/Visibility.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/Visibility.java @@ -1,5 +1,7 @@ package org.jetbrains.jet.lang.descriptors; +import java.util.EnumSet; + /** * @author svtk */ @@ -11,6 +13,8 @@ public enum Visibility { INTERNAL_PROTECTED(false), LOCAL(false); + public static final EnumSet INTERNAL_VISIBILITIES = EnumSet.of(PRIVATE, INTERNAL, INTERNAL_PROTECTED, LOCAL); + private final boolean isAPI; private Visibility(boolean visibleOutside) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java index bee520f5297..27d964e1656 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java @@ -46,29 +46,6 @@ public class DataFlowValueFactory { return new DataFlowValue(variableDescriptor, type, isStableVariable(variableDescriptor), getImmanentNullability(type)); } -// private Object getId(@NotNull JetExpression expression, @NotNull BindingContext bindingContext) { -// if (expression instanceof JetThisExpression) { -// JetThisExpression thisExpression = (JetThisExpression) expression; -// DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, thisExpression.getThisReference()); -// if (declarationDescriptor instanceof CallableDescriptor) { -// return ((CallableDescriptor) declarationDescriptor).getReceiverParameter(); -// } -// if (declarationDescriptor instanceof ClassDescriptor) { -// return ((ClassDescriptor) declarationDescriptor).getImplicitReceiver(); -// } -//// throw new AssertionError("No resolution data for expression " + expression.getText()); -// } -// else if (expression instanceof JetReferenceExpression) { -// JetReferenceExpression referenceExpression = (JetReferenceExpression) expression; -// DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, referenceExpression); -// if (declarationDescriptor != null) { -// return declarationDescriptor; -// } -//// throw new AssertionError("No resolution data for expression " + expression.getText() + DiagnosticUtils.atLocation(expression)); -// } -// return expression; -// } - private Nullability getImmanentNullability(JetType type) { return type.isNullable() ? Nullability.UNKNOWN : Nullability.NOT_NULL; } @@ -142,18 +119,38 @@ public class DataFlowValueFactory { if (variableDescriptor.isVar()) return false; if (variableDescriptor instanceof PropertyDescriptor) { PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor; - DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); - if (containingDeclaration instanceof ClassDescriptor) { - ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; - if (classDescriptor.getModality().isOverridable() && propertyDescriptor.getModality().isOverridable()) return false; - } - else { - assert !propertyDescriptor.getModality().isOverridable() : "Property outside a class must not be overridable"; - } - // TODO: check that it's internal - PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); - if (getter != null && !getter.isDefault()) return false; + if (!isInternal(propertyDescriptor)) return false; + if (!isFinal(propertyDescriptor)) return false; + if (!hasDefaultGetter(propertyDescriptor)) return false; } return true; } + + private static boolean isFinal(PropertyDescriptor propertyDescriptor) { + DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); + if (containingDeclaration instanceof ClassDescriptor) { + ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; + if (classDescriptor.getModality().isOverridable() && propertyDescriptor.getModality().isOverridable()) return false; + } + else { + assert !propertyDescriptor.getModality().isOverridable() : "Property outside a class must not be overridable"; + } + return true; + } + + private static boolean isInternal(@NotNull DeclarationDescriptorWithVisibility descriptor) { + if (Visibility.INTERNAL_VISIBILITIES.contains(descriptor.getVisibility())) return true; + + DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); + if (!(containingDeclaration instanceof DeclarationDescriptorWithVisibility)) { + return false; + } + + return isInternal((DeclarationDescriptorWithVisibility) containingDeclaration); + } + + private static boolean hasDefaultGetter(PropertyDescriptor propertyDescriptor) { + PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); + return getter == null || getter.isDefault(); + } } diff --git a/idea/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/kt362.jet b/idea/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/kt362.jet new file mode 100644 index 00000000000..5fd5f72bfb1 --- /dev/null +++ b/idea/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/kt362.jet @@ -0,0 +1,30 @@ +// KT-362 Don't allow autocasts on vals that are not internal +namespace example; + +namespace test { + public class Public() { + public val public : Int? = 1; + protected val protected : Int? = 1; + internal protected val i_protected : Int? = 1; + val internal : Int? = 1 + } + internal class Internal() { + public val public : Int? = 1; + protected val protected : Int? = 1; + internal protected val i_protected : Int? = 1; + val internal : Int? = 1 + } +} + +fun test() { + val p = test.Public() + if (p.public is Int) p.public + 1 + if (p.protected is Int) p.protected + 1 + if (p.i_protected is Int) p.i_protected + 1 + if (p.internal is Int) p.internal + 1 + val i = test.Public() + if (i.public is Int) i.public + 1 + if (i.protected is Int) i.protected + 1 + if (i.i_protected is Int) i.i_protected + 1 + if (i.internal is Int) i.internal + 1 +} \ No newline at end of file