Always null detection
This commit is contained in:
@@ -657,6 +657,7 @@ public interface Errors {
|
||||
DiagnosticFactory1<KtExpression, KotlinType> IMPLICIT_CAST_TO_UNIT_OR_ANY = DiagnosticFactory1.create(WARNING);
|
||||
|
||||
DiagnosticFactory3<KtExpression, KotlinType, String, String> SMARTCAST_IMPOSSIBLE = DiagnosticFactory3.create(ERROR);
|
||||
DiagnosticFactory0<KtExpression> ALWAYS_NULL = DiagnosticFactory0.create(WARNING);
|
||||
|
||||
DiagnosticFactory0<KtNullableType> USELESS_NULLABLE_CHECK = DiagnosticFactory0.create(WARNING, NULLABLE_TYPE);
|
||||
|
||||
|
||||
+1
@@ -481,6 +481,7 @@ public class DefaultErrorMessages {
|
||||
}, DECLARATION_NAME);
|
||||
MAP.put(SMARTCAST_IMPOSSIBLE,
|
||||
"Smart cast to ''{0}'' is impossible, because ''{1}'' is a {2}", RENDER_TYPE, STRING, STRING);
|
||||
MAP.put(ALWAYS_NULL, "The result of the expression is always null");
|
||||
|
||||
MAP.put(MISSING_CONSTRUCTOR_KEYWORD, "Use 'constructor' keyword after modifiers of primary constructor");
|
||||
|
||||
|
||||
+16
@@ -97,12 +97,28 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
super(facade);
|
||||
}
|
||||
|
||||
private static boolean isLValue(@NotNull KtSimpleNameExpression expression) {
|
||||
PsiElement parent = PsiTreeUtil.skipParentsOfType(expression, KtParenthesizedExpression.class);
|
||||
if (!(parent instanceof KtBinaryExpression)) return false;
|
||||
KtBinaryExpression binaryExpression = (KtBinaryExpression) parent;
|
||||
if (!KtTokens.ALL_ASSIGNMENTS.contains(binaryExpression.getOperationToken())) return false;
|
||||
return PsiTreeUtil.isAncestor(binaryExpression.getLeft(), expression, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KotlinTypeInfo visitSimpleNameExpression(@NotNull KtSimpleNameExpression expression, ExpressionTypingContext context) {
|
||||
// TODO : other members
|
||||
// TODO : type substitutions???
|
||||
CallExpressionResolver callExpressionResolver = components.callExpressionResolver;
|
||||
KotlinTypeInfo typeInfo = callExpressionResolver.getSimpleNameExpressionTypeInfo(expression, NO_RECEIVER, null, context);
|
||||
if (typeInfo.getType() != null && !typeInfo.getType().isError() && !isLValue(expression)) {
|
||||
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, typeInfo.getType(), context);
|
||||
Nullability nullability = context.dataFlowInfo.getPredictableNullability(dataFlowValue);
|
||||
if (!nullability.canBeNonNull() && nullability.canBeNull()) {
|
||||
context.trace.report(ALWAYS_NULL.on(expression));
|
||||
}
|
||||
}
|
||||
|
||||
return components.dataFlowAnalyzer.checkType(typeInfo, expression, context); // TODO : Extensions to this
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ object SenselessComparisonChecker {
|
||||
val nullability = getNullability(value)
|
||||
|
||||
val expressionIsAlways =
|
||||
if (nullability == Nullability.NULL) equality
|
||||
if (nullability == Nullability.NULL) return
|
||||
else if (nullability == Nullability.NOT_NULL) !equality
|
||||
else if (nullability == Nullability.IMPOSSIBLE) false
|
||||
else return
|
||||
|
||||
Reference in New Issue
Block a user