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);
|
DiagnosticFactory1<KtExpression, KotlinType> IMPLICIT_CAST_TO_UNIT_OR_ANY = DiagnosticFactory1.create(WARNING);
|
||||||
|
|
||||||
DiagnosticFactory3<KtExpression, KotlinType, String, String> SMARTCAST_IMPOSSIBLE = DiagnosticFactory3.create(ERROR);
|
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);
|
DiagnosticFactory0<KtNullableType> USELESS_NULLABLE_CHECK = DiagnosticFactory0.create(WARNING, NULLABLE_TYPE);
|
||||||
|
|
||||||
|
|||||||
+1
@@ -481,6 +481,7 @@ public class DefaultErrorMessages {
|
|||||||
}, DECLARATION_NAME);
|
}, DECLARATION_NAME);
|
||||||
MAP.put(SMARTCAST_IMPOSSIBLE,
|
MAP.put(SMARTCAST_IMPOSSIBLE,
|
||||||
"Smart cast to ''{0}'' is impossible, because ''{1}'' is a {2}", RENDER_TYPE, STRING, STRING);
|
"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");
|
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);
|
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
|
@Override
|
||||||
public KotlinTypeInfo visitSimpleNameExpression(@NotNull KtSimpleNameExpression expression, ExpressionTypingContext context) {
|
public KotlinTypeInfo visitSimpleNameExpression(@NotNull KtSimpleNameExpression expression, ExpressionTypingContext context) {
|
||||||
// TODO : other members
|
// TODO : other members
|
||||||
// TODO : type substitutions???
|
// TODO : type substitutions???
|
||||||
CallExpressionResolver callExpressionResolver = components.callExpressionResolver;
|
CallExpressionResolver callExpressionResolver = components.callExpressionResolver;
|
||||||
KotlinTypeInfo typeInfo = callExpressionResolver.getSimpleNameExpressionTypeInfo(expression, NO_RECEIVER, null, context);
|
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
|
return components.dataFlowAnalyzer.checkType(typeInfo, expression, context); // TODO : Extensions to this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -50,7 +50,7 @@ object SenselessComparisonChecker {
|
|||||||
val nullability = getNullability(value)
|
val nullability = getNullability(value)
|
||||||
|
|
||||||
val expressionIsAlways =
|
val expressionIsAlways =
|
||||||
if (nullability == Nullability.NULL) equality
|
if (nullability == Nullability.NULL) return
|
||||||
else if (nullability == Nullability.NOT_NULL) !equality
|
else if (nullability == Nullability.NOT_NULL) !equality
|
||||||
else if (nullability == Nullability.IMPOSSIBLE) false
|
else if (nullability == Nullability.IMPOSSIBLE) false
|
||||||
else return
|
else return
|
||||||
|
|||||||
@@ -5,24 +5,24 @@ class A() {
|
|||||||
fun f(): Unit {
|
fun f(): Unit {
|
||||||
var x: Int? = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>1<!>
|
var x: Int? = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>1<!>
|
||||||
x = null
|
x = null
|
||||||
x <!UNSAFE_INFIX_CALL!>+<!> 1
|
<!ALWAYS_NULL!>x<!> <!UNSAFE_INFIX_CALL!>+<!> 1
|
||||||
x <!UNSAFE_INFIX_CALL, INFIX_MODIFIER_REQUIRED!>plus<!> 1
|
<!ALWAYS_NULL!>x<!> <!UNSAFE_INFIX_CALL, INFIX_MODIFIER_REQUIRED!>plus<!> 1
|
||||||
x <!UNSAFE_INFIX_CALL!><<!> 1
|
<!ALWAYS_NULL!>x<!> <!UNSAFE_INFIX_CALL!><<!> 1
|
||||||
x <!UNSAFE_INFIX_CALL!>+=<!> 1
|
x <!UNSAFE_INFIX_CALL!>+=<!> 1
|
||||||
|
|
||||||
x == 1
|
<!ALWAYS_NULL!>x<!> == 1
|
||||||
x != 1
|
<!ALWAYS_NULL!>x<!> != 1
|
||||||
|
|
||||||
<!EQUALITY_NOT_APPLICABLE!>A() == 1<!>
|
<!EQUALITY_NOT_APPLICABLE!>A() == 1<!>
|
||||||
|
|
||||||
<!EQUALITY_NOT_APPLICABLE!>x === "1"<!>
|
<!EQUALITY_NOT_APPLICABLE!><!ALWAYS_NULL!>x<!> === "1"<!>
|
||||||
<!EQUALITY_NOT_APPLICABLE!>x !== "1"<!>
|
<!EQUALITY_NOT_APPLICABLE!><!ALWAYS_NULL!>x<!> !== "1"<!>
|
||||||
|
|
||||||
x === 1
|
<!ALWAYS_NULL!>x<!> === 1
|
||||||
x !== 1
|
<!ALWAYS_NULL!>x<!> !== 1
|
||||||
|
|
||||||
x<!UNSAFE_INFIX_CALL!>..<!>2
|
<!ALWAYS_NULL!>x<!><!UNSAFE_INFIX_CALL!>..<!>2
|
||||||
<!TYPE_MISMATCH!>x<!> in 1..2
|
<!ALWAYS_NULL, TYPE_MISMATCH!>x<!> in 1..2
|
||||||
|
|
||||||
val y : Boolean? = true
|
val y : Boolean? = true
|
||||||
<!UNUSED_EXPRESSION!>false || <!TYPE_MISMATCH!>y<!><!>
|
<!UNUSED_EXPRESSION!>false || <!TYPE_MISMATCH!>y<!><!>
|
||||||
|
|||||||
+9
-9
@@ -4,7 +4,7 @@ fun test() {
|
|||||||
<!DEBUG_INFO_SMARTCAST!>a<!>.plus(1)
|
<!DEBUG_INFO_SMARTCAST!>a<!>.plus(1)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
a?.plus(1)
|
<!ALWAYS_NULL!>a<!>?.plus(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
val out : java.io.PrintStream? = null
|
val out : java.io.PrintStream? = null
|
||||||
@@ -28,7 +28,7 @@ fun test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (out == null) {
|
if (out == null) {
|
||||||
out?.println()
|
<!ALWAYS_NULL!>out<!>?.println()
|
||||||
} else {
|
} else {
|
||||||
<!DEBUG_INFO_SMARTCAST!>out<!>.println()
|
<!DEBUG_INFO_SMARTCAST!>out<!>.println()
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ fun test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (out == null) {
|
if (out == null) {
|
||||||
out?.println()
|
<!ALWAYS_NULL!>out<!>?.println()
|
||||||
} else {
|
} else {
|
||||||
<!DEBUG_INFO_SMARTCAST!>out<!>.println()
|
<!DEBUG_INFO_SMARTCAST!>out<!>.println()
|
||||||
}
|
}
|
||||||
@@ -140,13 +140,13 @@ fun test() {
|
|||||||
while (out != null) {
|
while (out != null) {
|
||||||
<!DEBUG_INFO_SMARTCAST!>out<!>.println();
|
<!DEBUG_INFO_SMARTCAST!>out<!>.println();
|
||||||
}
|
}
|
||||||
out?.println();
|
<!ALWAYS_NULL!>out<!>?.println();
|
||||||
|
|
||||||
val out2 : java.io.PrintStream? = null
|
val out2 : java.io.PrintStream? = null
|
||||||
|
|
||||||
while (out2 == null) {
|
while (out2 == null) {
|
||||||
out2?.println();
|
<!ALWAYS_NULL!>out2<!>?.println();
|
||||||
out2<!UNSAFE_CALL!>.<!>println();
|
<!ALWAYS_NULL!>out2<!><!UNSAFE_CALL!>.<!>println();
|
||||||
}
|
}
|
||||||
<!DEBUG_INFO_SMARTCAST!>out2<!>.println()
|
<!DEBUG_INFO_SMARTCAST!>out2<!>.println()
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ fun f7(s : String?, t : String?) {
|
|||||||
}
|
}
|
||||||
s?.get(0)
|
s?.get(0)
|
||||||
if (!(s != null)) {
|
if (!(s != null)) {
|
||||||
s?.get(0)
|
<!ALWAYS_NULL!>s<!>?.get(0)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
<!DEBUG_INFO_SMARTCAST!>s<!>.get(0)
|
<!DEBUG_INFO_SMARTCAST!>s<!>.get(0)
|
||||||
@@ -245,7 +245,7 @@ fun f7(s : String?, t : String?) {
|
|||||||
<!DEBUG_INFO_SMARTCAST!>s<!>.get(0)
|
<!DEBUG_INFO_SMARTCAST!>s<!>.get(0)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
s?.get(0)
|
<!ALWAYS_NULL!>s<!>?.get(0)
|
||||||
}
|
}
|
||||||
s?.get(0)
|
s?.get(0)
|
||||||
t?.get(0)
|
t?.get(0)
|
||||||
@@ -264,7 +264,7 @@ fun f7(s : String?, t : String?) {
|
|||||||
t?.get(0)
|
t?.get(0)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
s?.get(0)
|
<!ALWAYS_NULL!>s<!>?.get(0)
|
||||||
t?.get(0)
|
t?.get(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ fun foo() {
|
|||||||
val x: Int? = null
|
val x: Int? = null
|
||||||
val a = Array<Int>(3, {0})
|
val a = Array<Int>(3, {0})
|
||||||
|
|
||||||
if (x != null) bar(a[<!DEBUG_INFO_SMARTCAST!>x<!>]) else bar(a[<!TYPE_MISMATCH!>x<!>])
|
if (x != null) bar(a[<!DEBUG_INFO_SMARTCAST!>x<!>]) else bar(a[<!ALWAYS_NULL, TYPE_MISMATCH!>x<!>])
|
||||||
bar(a[if (x == null) 0 else <!DEBUG_INFO_SMARTCAST!>x<!>])
|
bar(a[if (x == null) 0 else <!DEBUG_INFO_SMARTCAST!>x<!>])
|
||||||
bar(a[<!TYPE_MISMATCH!>x<!>])
|
bar(a[<!TYPE_MISMATCH!>x<!>])
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -5,6 +5,6 @@ fun foo() {
|
|||||||
val x: Int? = null
|
val x: Int? = null
|
||||||
|
|
||||||
bar(1 + (if (x == null) 0 else x))
|
bar(1 + (if (x == null) 0 else x))
|
||||||
bar(if (x == null) <!TYPE_MISMATCH!>x<!> else x)
|
bar(if (x == null) <!ALWAYS_NULL, TYPE_MISMATCH!>x<!> else x)
|
||||||
if (x != null) bar(x + x/(x-x*x))
|
if (x != null) bar(x + x/(x-x*x))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,15 +16,15 @@ fun foo() {
|
|||||||
}
|
}
|
||||||
if (<!SENSELESS_COMPARISON!>x == null<!>) bar(x) else bar(x)
|
if (<!SENSELESS_COMPARISON!>x == null<!>) bar(x) else bar(x)
|
||||||
bar(bar(x))
|
bar(bar(x))
|
||||||
} else if (<!SENSELESS_COMPARISON!>x == null<!>) {
|
} else if (<!ALWAYS_NULL!>x<!> == null) {
|
||||||
bar(<!TYPE_MISMATCH!>x<!>)
|
bar(<!ALWAYS_NULL, TYPE_MISMATCH!>x<!>)
|
||||||
if (<!SENSELESS_COMPARISON!>x != null<!>) {
|
if (<!ALWAYS_NULL!>x<!> != null) {
|
||||||
bar(x)
|
bar(x)
|
||||||
if (<!SENSELESS_COMPARISON!>x == null<!>) bar(x)
|
if (<!SENSELESS_COMPARISON!>x == null<!>) bar(x)
|
||||||
if (<!SENSELESS_COMPARISON!>x == null<!>) bar(x) else bar(x)
|
if (<!SENSELESS_COMPARISON!>x == null<!>) bar(x) else bar(x)
|
||||||
bar(bar(x) + bar(x))
|
bar(bar(x) + bar(x))
|
||||||
} else if (<!SENSELESS_COMPARISON!>x == null<!>) {
|
} else if (<!ALWAYS_NULL!>x<!> == null) {
|
||||||
bar(<!TYPE_MISMATCH!>x<!>)
|
bar(<!ALWAYS_NULL, TYPE_MISMATCH!>x<!>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,5 +12,5 @@ fun foo() {
|
|||||||
do {
|
do {
|
||||||
bar(<!TYPE_MISMATCH!>y<!>)
|
bar(<!TYPE_MISMATCH!>y<!>)
|
||||||
} while (y != null)
|
} while (y != null)
|
||||||
bar(<!TYPE_MISMATCH!>y<!>)
|
bar(<!ALWAYS_NULL, TYPE_MISMATCH!>y<!>)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,19 +3,19 @@ fun bar(x: Int) = x + 1
|
|||||||
fun f1(x: Int?) {
|
fun f1(x: Int?) {
|
||||||
bar(<!TYPE_MISMATCH!>x<!>)
|
bar(<!TYPE_MISMATCH!>x<!>)
|
||||||
if (x != null) bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
if (x != null) bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
if (x == null) <!UNREACHABLE_CODE!>bar(<!><!DEBUG_INFO_SMARTCAST!>x<!>!!<!UNREACHABLE_CODE!>)<!>
|
if (x == null) <!UNREACHABLE_CODE!>bar(<!><!ALWAYS_NULL, DEBUG_INFO_SMARTCAST!>x<!>!!<!UNREACHABLE_CODE!>)<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun f2(x: Int?) {
|
fun f2(x: Int?) {
|
||||||
if (x != null) else <!DEBUG_INFO_SMARTCAST!>x<!>!!
|
if (x != null) else <!ALWAYS_NULL, DEBUG_INFO_SMARTCAST!>x<!>!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun f3(x: Int?) {
|
fun f3(x: Int?) {
|
||||||
if (x != null) bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) else <!DEBUG_INFO_SMARTCAST!>x<!>!!
|
if (x != null) bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) else <!ALWAYS_NULL, DEBUG_INFO_SMARTCAST!>x<!>!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun f4(x: Int?) {
|
fun f4(x: Int?) {
|
||||||
if (x == null) <!DEBUG_INFO_SMARTCAST!>x<!>!! else bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
if (x == null) <!ALWAYS_NULL, DEBUG_INFO_SMARTCAST!>x<!>!! else bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun f5(x: Int?) {
|
fun f5(x: Int?) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ fun foo() {
|
|||||||
bar(if (x == null) 0 else <!DEBUG_INFO_SMARTCAST!>x<!>)
|
bar(if (x == null) 0 else <!DEBUG_INFO_SMARTCAST!>x<!>)
|
||||||
|
|
||||||
if (x == null) {
|
if (x == null) {
|
||||||
bar(<!TYPE_MISMATCH!>x<!>)
|
bar(<!ALWAYS_NULL, TYPE_MISMATCH!>x<!>)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
bar(<!DEBUG_INFO_SMARTCAST!>x<!>)
|
bar(<!DEBUG_INFO_SMARTCAST!>x<!>)
|
||||||
|
|||||||
+1
-1
@@ -5,6 +5,6 @@ fun foo() {
|
|||||||
|
|
||||||
val <!UNUSED_VARIABLE!>a<!> = object {
|
val <!UNUSED_VARIABLE!>a<!> = object {
|
||||||
fun baz() = bar(if (x == null) 0 else <!DEBUG_INFO_SMARTCAST!>x<!>)
|
fun baz() = bar(if (x == null) 0 else <!DEBUG_INFO_SMARTCAST!>x<!>)
|
||||||
fun quux(): Int = if (x == null) <!TYPE_MISMATCH!>x<!> else <!DEBUG_INFO_SMARTCAST!>x<!>
|
fun quux(): Int = if (x == null) <!ALWAYS_NULL, TYPE_MISMATCH!>x<!> else <!DEBUG_INFO_SMARTCAST!>x<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ fun foo(): Int {
|
|||||||
if (x != null) return x
|
if (x != null) return x
|
||||||
|
|
||||||
val y: Int? = null
|
val y: Int? = null
|
||||||
if (y == null) return if (<!SENSELESS_COMPARISON!>y != null<!>) y else <!TYPE_MISMATCH!>y<!>
|
if (y == null) return if (<!ALWAYS_NULL!>y<!> != null) y else <!ALWAYS_NULL, TYPE_MISMATCH!>y<!>
|
||||||
|
|
||||||
val z: Int? = null
|
val z: Int? = null
|
||||||
if (z != null) return if (<!SENSELESS_COMPARISON!>z == null<!>) z else z
|
if (z != null) return if (<!SENSELESS_COMPARISON!>z == null<!>) z else z
|
||||||
|
|
||||||
return <!TYPE_MISMATCH!>z<!>
|
return <!ALWAYS_NULL, TYPE_MISMATCH!>z<!>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,6 @@ class Derived : Base() {
|
|||||||
|
|
||||||
val y: Int? = null
|
val y: Int? = null
|
||||||
if (y != null) super.bar(this.baz(<!DEBUG_INFO_SMARTCAST!>y<!>))
|
if (y != null) super.bar(this.baz(<!DEBUG_INFO_SMARTCAST!>y<!>))
|
||||||
else this.baz(super.bar(<!TYPE_MISMATCH!>y<!>))
|
else this.baz(super.bar(<!ALWAYS_NULL, TYPE_MISMATCH!>y<!>))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ fun bar(x: Int): RuntimeException = RuntimeException(x.toString())
|
|||||||
fun foo() {
|
fun foo() {
|
||||||
val x: Int? = null
|
val x: Int? = null
|
||||||
|
|
||||||
if (x == null) throw bar(<!TYPE_MISMATCH!>x<!>)
|
if (x == null) throw bar(<!ALWAYS_NULL, TYPE_MISMATCH!>x<!>)
|
||||||
throw bar(<!DEBUG_INFO_SMARTCAST!>x<!>)
|
throw bar(<!DEBUG_INFO_SMARTCAST!>x<!>)
|
||||||
<!UNREACHABLE_CODE!>throw bar(<!DEBUG_INFO_SMARTCAST!>x<!>)<!>
|
<!UNREACHABLE_CODE!>throw bar(<!DEBUG_INFO_SMARTCAST!>x<!>)<!>
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ fun bar(x: Int): Int = x + 1
|
|||||||
fun foo() {
|
fun foo() {
|
||||||
val x: Int? = null
|
val x: Int? = null
|
||||||
while (x == null) {
|
while (x == null) {
|
||||||
bar(<!TYPE_MISMATCH!>x<!>)
|
bar(<!ALWAYS_NULL, TYPE_MISMATCH!>x<!>)
|
||||||
}
|
}
|
||||||
bar(<!DEBUG_INFO_SMARTCAST!>x<!>)
|
bar(<!DEBUG_INFO_SMARTCAST!>x<!>)
|
||||||
|
|
||||||
@@ -11,11 +11,11 @@ fun foo() {
|
|||||||
while (y != null) {
|
while (y != null) {
|
||||||
bar(<!DEBUG_INFO_SMARTCAST!>y<!>)
|
bar(<!DEBUG_INFO_SMARTCAST!>y<!>)
|
||||||
}
|
}
|
||||||
bar(<!TYPE_MISMATCH!>y<!>)
|
bar(<!ALWAYS_NULL, TYPE_MISMATCH!>y<!>)
|
||||||
|
|
||||||
val z: Int? = null
|
val z: Int? = null
|
||||||
while (z == null) {
|
while (z == null) {
|
||||||
bar(<!TYPE_MISMATCH!>z<!>)
|
bar(<!ALWAYS_NULL, TYPE_MISMATCH!>z<!>)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
bar(<!TYPE_MISMATCH!>z<!>)
|
bar(<!TYPE_MISMATCH!>z<!>)
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ interface A<T>
|
|||||||
fun <T> infer(<!UNUSED_PARAMETER!>a<!>: A<T>) : T {<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
|
fun <T> infer(<!UNUSED_PARAMETER!>a<!>: A<T>) : T {<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
|
||||||
|
|
||||||
fun test(nothing: Nothing?) {
|
fun test(nothing: Nothing?) {
|
||||||
val <!UNUSED_VARIABLE!>i<!> = <!TYPE_INFERENCE_INCORPORATION_ERROR!>infer<!>(<!TYPE_MISMATCH!>nothing<!>)
|
val <!UNUSED_VARIABLE!>i<!> = <!TYPE_INFERENCE_INCORPORATION_ERROR!>infer<!>(<!ALWAYS_NULL, TYPE_MISMATCH!>nothing<!>)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sum(<!UNUSED_PARAMETER!>a<!> : IntArray) : Int {
|
fun sum(<!UNUSED_PARAMETER!>a<!> : IntArray) : Int {
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
fun test() {
|
fun test() {
|
||||||
val out : Int? = null
|
val out : Int? = null
|
||||||
val x : Nothing? = null
|
val x : Nothing? = null
|
||||||
if (out != x)
|
if (out != <!ALWAYS_NULL!>x<!>)
|
||||||
<!DEBUG_INFO_SMARTCAST!>out<!>.plus(1)
|
<!DEBUG_INFO_SMARTCAST!>out<!>.plus(1)
|
||||||
if (out == x) return
|
if (out == <!ALWAYS_NULL!>x<!>) return
|
||||||
<!DEBUG_INFO_SMARTCAST!>out<!>.plus(1)
|
<!DEBUG_INFO_SMARTCAST!>out<!>.plus(1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ fun f3(s: Int?): Int {
|
|||||||
fun f4(s: Int?): Int {
|
fun f4(s: Int?): Int {
|
||||||
return when {
|
return when {
|
||||||
s == 4 -> <!DEBUG_INFO_SMARTCAST!>s<!>
|
s == 4 -> <!DEBUG_INFO_SMARTCAST!>s<!>
|
||||||
s == null -> <!TYPE_MISMATCH!>s<!>
|
s == null -> <!ALWAYS_NULL, TYPE_MISMATCH!>s<!>
|
||||||
else -> <!DEBUG_INFO_SMARTCAST!>s<!>
|
else -> <!DEBUG_INFO_SMARTCAST!>s<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ fun main(args : Array<String>) {
|
|||||||
foo(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
foo(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||||
foo(<!DEBUG_INFO_SMARTCAST!>x<!>)
|
foo(<!DEBUG_INFO_SMARTCAST!>x<!>)
|
||||||
} else {
|
} else {
|
||||||
foo(<!TYPE_MISMATCH!>x<!>)
|
foo(<!ALWAYS_NULL, TYPE_MISMATCH!>x<!>)
|
||||||
<!UNREACHABLE_CODE!>foo(<!><!DEBUG_INFO_SMARTCAST!>x<!>!!<!UNREACHABLE_CODE!>)<!>
|
<!UNREACHABLE_CODE!>foo(<!><!ALWAYS_NULL, DEBUG_INFO_SMARTCAST!>x<!>!!<!UNREACHABLE_CODE!>)<!>
|
||||||
<!UNREACHABLE_CODE!>foo(<!DEBUG_INFO_SMARTCAST!>x<!>)<!>
|
<!UNREACHABLE_CODE!>foo(<!DEBUG_INFO_SMARTCAST!>x<!>)<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -2,7 +2,7 @@ fun <T> test(t: T): T {
|
|||||||
if (t != null) {
|
if (t != null) {
|
||||||
return t<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
|
return t<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
|
||||||
}
|
}
|
||||||
return <!DEBUG_INFO_SMARTCAST!>t<!>!!
|
return <!ALWAYS_NULL, DEBUG_INFO_SMARTCAST!>t<!>!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> T.testThis(): String {
|
fun <T> T.testThis(): String {
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ fun <T> test(t: T): String? {
|
|||||||
if (t != null) {
|
if (t != null) {
|
||||||
return t<!UNNECESSARY_SAFE_CALL!>?.<!>toString()
|
return t<!UNNECESSARY_SAFE_CALL!>?.<!>toString()
|
||||||
}
|
}
|
||||||
return t?.toString()
|
return <!ALWAYS_NULL!>t<!>?.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> T.testThis(): String? {
|
fun <T> T.testThis(): String? {
|
||||||
|
|||||||
Vendored
+2
-2
@@ -33,10 +33,10 @@ fun test() {
|
|||||||
|
|
||||||
if (platformN != null) {}
|
if (platformN != null) {}
|
||||||
if (platformN == null) {}
|
if (platformN == null) {}
|
||||||
if (a == null && platformN == a) {}
|
if (a == null && platformN == <!ALWAYS_NULL!>a<!>) {}
|
||||||
|
|
||||||
if (platformJ != null) {}
|
if (platformJ != null) {}
|
||||||
if (platformJ == null) {}
|
if (platformJ == null) {}
|
||||||
if (a == null && platformJ == a) {}
|
if (a == null && platformJ == <!ALWAYS_NULL!>a<!>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -31,10 +31,10 @@ fun test() {
|
|||||||
|
|
||||||
if (platformN !== null) {}
|
if (platformN !== null) {}
|
||||||
if (platformN === null) {}
|
if (platformN === null) {}
|
||||||
if (a === null && platformN === a) {}
|
if (a === null && platformN === <!ALWAYS_NULL!>a<!>) {}
|
||||||
|
|
||||||
if (platformJ !== null) {}
|
if (platformJ !== null) {}
|
||||||
if (platformJ === null) {}
|
if (platformJ === null) {}
|
||||||
if (a === null && platformJ === a) {}
|
if (a === null && platformJ === <!ALWAYS_NULL!>a<!>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fun foo(): String {
|
||||||
|
var s: String?
|
||||||
|
s = null
|
||||||
|
<!ALWAYS_NULL!>s<!>?.length
|
||||||
|
if (<!ALWAYS_NULL!>s<!> == null) s = "z"
|
||||||
|
var t: String? = "y"
|
||||||
|
if (t == null) t = "x"
|
||||||
|
var x: Int? = null
|
||||||
|
if (x == null) <!TYPE_MISMATCH!><!DEBUG_INFO_SMARTCAST!>x<!> += null<!>
|
||||||
|
return <!DEBUG_INFO_SMARTCAST!>t<!> + s
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun foo(): kotlin.String
|
||||||
@@ -8,19 +8,19 @@ fun foo(x : String?, y : String?) {
|
|||||||
x<!UNSAFE_CALL!>.<!>length
|
x<!UNSAFE_CALL!>.<!>length
|
||||||
y<!UNSAFE_CALL!>.<!>length
|
y<!UNSAFE_CALL!>.<!>length
|
||||||
}
|
}
|
||||||
if (y != null || x == y) {
|
if (y != null || x == <!ALWAYS_NULL!>y<!>) {
|
||||||
x<!UNSAFE_CALL!>.<!>length
|
x<!UNSAFE_CALL!>.<!>length
|
||||||
y<!UNSAFE_CALL!>.<!>length
|
y<!UNSAFE_CALL!>.<!>length
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// y == null but x != y
|
// y == null but x != y
|
||||||
<!DEBUG_INFO_SMARTCAST!>x<!>.length
|
<!DEBUG_INFO_SMARTCAST!>x<!>.length
|
||||||
y<!UNSAFE_CALL!>.<!>length
|
<!ALWAYS_NULL!>y<!><!UNSAFE_CALL!>.<!>length
|
||||||
}
|
}
|
||||||
if (y == null && x != y) {
|
if (y == null && x != <!ALWAYS_NULL!>y<!>) {
|
||||||
// y == null but x != y
|
// y == null but x != y
|
||||||
<!DEBUG_INFO_SMARTCAST!>x<!>.length
|
<!DEBUG_INFO_SMARTCAST!>x<!>.length
|
||||||
y<!UNSAFE_CALL!>.<!>length
|
<!ALWAYS_NULL!>y<!><!UNSAFE_CALL!>.<!>length
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
x<!UNSAFE_CALL!>.<!>length
|
x<!UNSAFE_CALL!>.<!>length
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ fun foo(x: String?, y: String?, z: String?, w: String?) {
|
|||||||
<!DEBUG_INFO_SMARTCAST!>z<!>.length
|
<!DEBUG_INFO_SMARTCAST!>z<!>.length
|
||||||
else
|
else
|
||||||
z<!UNSAFE_CALL!>.<!>length
|
z<!UNSAFE_CALL!>.<!>length
|
||||||
if (x != null || y != null || (x != z && y != z))
|
if (x != null || y != null || (<!ALWAYS_NULL!>x<!> != z && <!ALWAYS_NULL!>y<!> != z))
|
||||||
z<!UNSAFE_CALL!>.<!>length
|
z<!UNSAFE_CALL!>.<!>length
|
||||||
else
|
else
|
||||||
z<!UNSAFE_CALL!>.<!>length
|
<!ALWAYS_NULL!>z<!><!UNSAFE_CALL!>.<!>length
|
||||||
if (x == null || y == null || (x != z && y != z))
|
if (x == null || y == null || (x != z && y != z))
|
||||||
z<!UNSAFE_CALL!>.<!>length
|
z<!UNSAFE_CALL!>.<!>length
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
class IncDec {
|
||||||
|
<!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun inc(): Unit {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(): IncDec {
|
||||||
|
var x = IncDec()
|
||||||
|
x = <!UNUSED_CHANGED_VALUE!>x<!INC_DEC_SHOULD_NOT_RETURN_UNIT!>++<!><!>
|
||||||
|
x<!INC_DEC_SHOULD_NOT_RETURN_UNIT!>++<!>
|
||||||
|
return x
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun foo(): IncDec
|
||||||
|
|
||||||
|
public final class IncDec {
|
||||||
|
public constructor IncDec()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public final operator fun inc(): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
fun bar(x: Int?): Int {
|
fun bar(x: Int?): Int {
|
||||||
if (x != null) return -1
|
if (x != null) return -1
|
||||||
if (<!SENSELESS_COMPARISON!>x == null<!>) return -2
|
if (<!ALWAYS_NULL!>x<!> == null) return -2
|
||||||
// Should be unreachable
|
// Should be unreachable
|
||||||
return 2 + 2
|
return 2 + 2
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ fun foo() {
|
|||||||
v = "abc"
|
v = "abc"
|
||||||
<!DEBUG_INFO_SMARTCAST!>v<!>.length
|
<!DEBUG_INFO_SMARTCAST!>v<!>.length
|
||||||
v = null
|
v = null
|
||||||
v<!UNSAFE_CALL!>.<!>length
|
<!ALWAYS_NULL!>v<!><!UNSAFE_CALL!>.<!>length
|
||||||
v = "abc"
|
v = "abc"
|
||||||
<!DEBUG_INFO_SMARTCAST!>v<!>.length
|
<!DEBUG_INFO_SMARTCAST!>v<!>.length
|
||||||
}
|
}
|
||||||
+1
-1
@@ -3,5 +3,5 @@ fun foo() {
|
|||||||
// It is possible in principle to provide smart cast here
|
// It is possible in principle to provide smart cast here
|
||||||
v<!UNSAFE_CALL!>.<!>length
|
v<!UNSAFE_CALL!>.<!>length
|
||||||
v = null
|
v = null
|
||||||
v<!UNSAFE_CALL!>.<!>length
|
<!ALWAYS_NULL!>v<!><!UNSAFE_CALL!>.<!>length
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fun foo(): Int {
|
fun foo(): Int {
|
||||||
var i: Int? = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>42<!>
|
var i: Int? = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>42<!>
|
||||||
i = null
|
i = null
|
||||||
return i <!UNSAFE_INFIX_CALL!>+<!> 1
|
return <!ALWAYS_NULL!>i<!> <!UNSAFE_INFIX_CALL!>+<!> 1
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fun foo(): Int {
|
fun foo(): Int {
|
||||||
var s: String? = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>"abc"<!>
|
var s: String? = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>"abc"<!>
|
||||||
s = null
|
s = null
|
||||||
return s<!UNSAFE_CALL!>.<!>length
|
return <!ALWAYS_NULL!>s<!><!UNSAFE_CALL!>.<!>length
|
||||||
}
|
}
|
||||||
+1
-1
@@ -6,6 +6,6 @@ fun foo(e: E, something: Any?): Int {
|
|||||||
return when (e) {
|
return when (e) {
|
||||||
E.A -> 1
|
E.A -> 1
|
||||||
E.B -> 2
|
E.B -> 2
|
||||||
something -> 3
|
<!ALWAYS_NULL!>something<!> -> 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ fun test() {
|
|||||||
|
|
||||||
fun <T> dynamic(body: dynamic.() -> T): T {
|
fun <T> dynamic(body: dynamic.() -> T): T {
|
||||||
val topLevel = null
|
val topLevel = null
|
||||||
return topLevel.body()
|
return <!ALWAYS_NULL!>topLevel<!>.body()
|
||||||
}
|
}
|
||||||
@@ -14367,6 +14367,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/smartCasts"), Pattern.compile("^(.+)\\.kt$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/smartCasts"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("alwaysNull.kt")
|
||||||
|
public void testAlwaysNull() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/alwaysNull.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("classObjectMember.kt")
|
@TestMetadata("classObjectMember.kt")
|
||||||
public void testClassObjectMember() throws Exception {
|
public void testClassObjectMember() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/classObjectMember.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/classObjectMember.kt");
|
||||||
@@ -14463,6 +14469,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("incDecToNull.kt")
|
||||||
|
public void testIncDecToNull() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/incDecToNull.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt1461.kt")
|
@TestMetadata("kt1461.kt")
|
||||||
public void testKt1461() throws Exception {
|
public void testKt1461() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/kt1461.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/kt1461.kt");
|
||||||
|
|||||||
Vendored
+8
-8
@@ -4,7 +4,7 @@ fun test() {
|
|||||||
a.plus(1)
|
a.plus(1)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
a?.plus(1)
|
<warning>a</warning>?.plus(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
val out : java.io.PrintStream? = null
|
val out : java.io.PrintStream? = null
|
||||||
@@ -28,7 +28,7 @@ fun test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (out == null) {
|
if (out == null) {
|
||||||
out?.println()
|
<warning>out</warning>?.println()
|
||||||
} else {
|
} else {
|
||||||
out.println()
|
out.println()
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ fun test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (out == null) {
|
if (out == null) {
|
||||||
out?.println()
|
<warning>out</warning>?.println()
|
||||||
} else {
|
} else {
|
||||||
out.println()
|
out.println()
|
||||||
}
|
}
|
||||||
@@ -131,12 +131,12 @@ fun test() {
|
|||||||
while (out != null) {
|
while (out != null) {
|
||||||
out.println();
|
out.println();
|
||||||
}
|
}
|
||||||
out?.println();
|
<warning>out</warning>?.println();
|
||||||
|
|
||||||
val out2 : java.io.PrintStream? = null
|
val out2 : java.io.PrintStream? = null
|
||||||
|
|
||||||
while (out2 == null) {
|
while (out2 == null) {
|
||||||
out2?.println();
|
<warning>out2</warning>?.println();
|
||||||
}
|
}
|
||||||
out2.println()
|
out2.println()
|
||||||
|
|
||||||
@@ -224,7 +224,7 @@ fun f7(s : String?, t : String?) {
|
|||||||
}
|
}
|
||||||
s?.get(0)
|
s?.get(0)
|
||||||
if (!(s != null)) {
|
if (!(s != null)) {
|
||||||
s?.get(0)
|
<warning>s</warning>?.get(0)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
s.get(0)
|
s.get(0)
|
||||||
@@ -234,7 +234,7 @@ fun f7(s : String?, t : String?) {
|
|||||||
s.get(0)
|
s.get(0)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
s?.get(0)
|
<warning>s</warning>?.get(0)
|
||||||
}
|
}
|
||||||
s?.get(0)
|
s?.get(0)
|
||||||
t?.get(0)
|
t?.get(0)
|
||||||
@@ -253,7 +253,7 @@ fun f7(s : String?, t : String?) {
|
|||||||
t?.get(0)
|
t?.get(0)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
s?.get(0)
|
<warning>s</warning>?.get(0)
|
||||||
t?.get(0)
|
t?.get(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user