x?.y != null and x?.call() != null provoke now x != null, a set of tests #KT-2127 Fixed

This commit is contained in:
Mikhail Glukhikh
2016-07-19 11:17:16 +03:00
committed by Mikhail Glukhikh
parent 9001b9bcc0
commit 11f50186fa
11 changed files with 249 additions and 32 deletions
@@ -9,6 +9,6 @@ fun foo(y: MyClass?): Int {
}
fun bar(y: MyClass?) {
y?.x!!.length
// !! is necessary here
y!!.x
// !! is NOT necessary here, because y?.x != null
y<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.x
}
@@ -0,0 +1,125 @@
// A set of examples for
// "If the result of a safe call is not null, understand that its receiver is not null"
// and some other improvements for nullability detection
fun kt6840_1(s: String?) {
val hash = s?.hashCode()
if (hash != null) {
// To be supported
s<!UNSAFE_CALL!>.<!>length
}
}
fun kt6840_2(s: String?) {
if (s?.hashCode() != null) {
<!DEBUG_INFO_SMARTCAST!>s<!>.length
}
}
fun kt1635(s: String?) {
s?.hashCode()!!
<!DEBUG_INFO_SMARTCAST!>s<!>.hashCode()
}
fun kt2127() {
val s: String? = ""
if (s?.length != null) {
<!DEBUG_INFO_SMARTCAST!>s<!>.hashCode()
}
}
fun kt3356(s: String?): Int {
if (s?.length != 1) return 0
return <!DEBUG_INFO_SMARTCAST!>s<!>.length
}
open class SomeClass(val data: Any)
class SubClass(val extra: Any, data: Any) : SomeClass(data)
fun kt4565_1(a: SomeClass?) {
val data = a?.data
if (data != null) {
<!DEBUG_INFO_SMARTCAST!>data<!>.hashCode()
// To be supported
a<!UNSAFE_CALL!>.<!>hashCode()
a<!UNSAFE_CALL!>.<!>data.hashCode()
}
if (a?.data != null) {
// To be supported
data<!UNSAFE_CALL!>.<!>hashCode()
<!DEBUG_INFO_SMARTCAST!>a<!>.hashCode()
<!DEBUG_INFO_SMARTCAST!>a<!>.data.hashCode()
}
if (a?.data is String) {
// To be supported
a<!UNSAFE_CALL!>.<!>data.<!UNRESOLVED_REFERENCE!>length<!>
data.<!UNRESOLVED_REFERENCE!>length<!>
}
}
fun kt4565_2(a: SomeClass?) {
// To be supported
if (a as? SubClass != null) {
a.<!UNRESOLVED_REFERENCE!>extra<!>.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>hashCode<!>()
}
val extra = (a as? SubClass)?.extra
if (extra != null) {
a.<!UNRESOLVED_REFERENCE!>extra<!>.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>hashCode<!>()
}
}
class A(val y: Int)
fun kt7491_1() {
val x: A? = A(42)
val <!UNUSED_VARIABLE!>z<!> = x?.y ?: return
<!DEBUG_INFO_SMARTCAST!>x<!>.y
}
fun getA(): A? = null
fun useA(a: A): Int = a.hashCode()
fun kt7491_2() {
val a = getA()
(a?.let { useA(<!DEBUG_INFO_SMARTCAST!>a<!>) } ?: a<!UNSAFE_CALL!>.<!>y ).toString()
}
fun String.correct() = true
fun kt8492(s: String?) {
if (s?.correct() ?: false) {
// To be supported
s<!UNSAFE_CALL!>.<!>length
}
}
fun kt11085(prop: String?) {
when (prop?.hashCode()) {
1 -> <!DEBUG_INFO_SMARTCAST!>prop<!>.length
}
}
class HttpExchange(val code: String)
fun kt11313(arg: HttpExchange?) {
when (arg?.code) {
"GET" -> handleGet(<!DEBUG_INFO_SMARTCAST!>arg<!>)
"POST" -> handlePost(<!DEBUG_INFO_SMARTCAST!>arg<!>)
}
}
fun handleGet(arg: HttpExchange) = arg
fun handlePost(arg: HttpExchange) = arg
class Wrapper {
fun unwrap(): String? = "Something not consistent"
}
fun falsePositive(w: Wrapper) {
if (w.unwrap() != null) {
// Here we should NOT have smart cast
<!SMARTCAST_IMPOSSIBLE!>w.unwrap()<!>.length
}
}
@@ -0,0 +1,61 @@
package
public fun falsePositive(/*0*/ w: Wrapper): kotlin.Unit
public fun getA(): A?
public fun handleGet(/*0*/ arg: HttpExchange): HttpExchange
public fun handlePost(/*0*/ arg: HttpExchange): HttpExchange
public fun kt11085(/*0*/ prop: kotlin.String?): kotlin.Unit
public fun kt11313(/*0*/ arg: HttpExchange?): kotlin.Unit
public fun kt1635(/*0*/ s: kotlin.String?): kotlin.Unit
public fun kt2127(): kotlin.Unit
public fun kt3356(/*0*/ s: kotlin.String?): kotlin.Int
public fun kt4565_1(/*0*/ a: SomeClass?): kotlin.Unit
public fun kt4565_2(/*0*/ a: SomeClass?): kotlin.Unit
public fun kt6840_1(/*0*/ s: kotlin.String?): kotlin.Unit
public fun kt6840_2(/*0*/ s: kotlin.String?): kotlin.Unit
public fun kt7491_1(): kotlin.Unit
public fun kt7491_2(): kotlin.Unit
public fun kt8492(/*0*/ s: kotlin.String?): kotlin.Unit
public fun useA(/*0*/ a: A): kotlin.Int
public fun kotlin.String.correct(): kotlin.Boolean
public final class A {
public constructor A(/*0*/ y: kotlin.Int)
public final val y: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class HttpExchange {
public constructor HttpExchange(/*0*/ code: kotlin.String)
public final val code: kotlin.String
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class SomeClass {
public constructor SomeClass(/*0*/ data: kotlin.Any)
public final val data: kotlin.Any
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class SubClass : SomeClass {
public constructor SubClass(/*0*/ extra: kotlin.Any, /*1*/ data: kotlin.Any)
public final override /*1*/ /*fake_override*/ val data: kotlin.Any
public final val extra: kotlin.Any
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Wrapper {
public constructor Wrapper()
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final fun unwrap(): kotlin.String?
}