KT-362 Don't allow autocasts on vals that are not internal
This commit is contained in:
@@ -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<TypeProjection> typeArguments);
|
||||
@@ -53,9 +53,11 @@ public interface ClassDescriptor extends ClassifierDescriptor {
|
||||
@NotNull
|
||||
ClassKind getKind();
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
Modality getModality();
|
||||
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
Visibility getVisibility();
|
||||
|
||||
|
||||
+11
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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<Visibility> INTERNAL_VISIBILITIES = EnumSet.of(PRIVATE, INTERNAL, INTERNAL_PROTECTED, LOCAL);
|
||||
|
||||
private final boolean isAPI;
|
||||
|
||||
private Visibility(boolean visibleOutside) {
|
||||
|
||||
+31
-34
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) <!AUTOCAST_IMPOSSIBLE!>p.public<!> + 1
|
||||
if (p.protected is Int) <!AUTOCAST_IMPOSSIBLE!>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) <!AUTOCAST_IMPOSSIBLE!>i.public<!> + 1
|
||||
if (i.protected is Int) <!AUTOCAST_IMPOSSIBLE!>i.protected<!> + 1
|
||||
if (i.i_protected is Int) i.i_protected + 1
|
||||
if (i.internal is Int) i.internal + 1
|
||||
}
|
||||
Reference in New Issue
Block a user