FIR: report UNSAFE_CALL on dot when possible

This commit is contained in:
Mikhail Glukhikh
2021-01-29 10:25:59 +03:00
parent 0ee4f1f393
commit 7d4eaefd36
249 changed files with 1208 additions and 1649 deletions
@@ -2,5 +2,5 @@ fun calc(x: List<String>?): Int {
// After KT-5840 fix !! assertion should become unnecessary here
x?.get(x!!.size - 1)
// x?. or x!! above should not provide smart cast here
return x.<!UNSAFE_CALL!>size<!>
return x<!UNSAFE_CALL!>.<!>size
}
@@ -1,5 +1,5 @@
fun calc(x: List<String>?): Int {
// x is not-null only inside subList
x?.subList(0, x.size - 1).<!UNSAFE_CALL!>get<!>(x.<!UNSAFE_CALL!>size<!>)
x?.subList(0, x.size - 1)<!UNSAFE_CALL!>.<!>get(x<!UNSAFE_CALL!>.<!>size)
return x!!.size
}
@@ -2,5 +2,5 @@ fun calc(x: List<String>?): Int {
// x should be non-null in arguments list, including inner call
x?.get(x.get(x.size - 1).length)
// but not also here!
return x.<!UNSAFE_CALL!>size<!>
return x<!UNSAFE_CALL!>.<!>size
}
@@ -4,5 +4,5 @@ fun calc(x: String?, y: String?): Int {
// Smart cast because of y!! in receiver
x?.subSequence(y!!.subSequence(0, 1).length, y.length)
// No smart cast possible
return y.<!UNSAFE_CALL!>length<!>
return y<!UNSAFE_CALL!>.<!>length
}
@@ -1,43 +0,0 @@
// See KT-11007: Wrong smart cast to not-null type after safe calls in if / when expression
val String.copy: String
get() = this
fun foo() {
val s: String? = null
val ss = if (true) {
s?.length
} else {
s?.length
}
ss.<!UNSAFE_CALL!>hashCode<!>() // Smart-cast to Int, should be unsafe call
val sss = if (true) {
s?.copy
}
else {
s?.copy
}
sss.<!UNSAFE_CALL!>length<!>
}
class My {
val String.copy2: String
get() = this
fun foo() {
val s: String? = null
val ss = if (true) {
s?.length
} else {
s?.length
}
ss.<!UNSAFE_CALL!>hashCode<!>()
val sss = if (true) {
s?.copy2
}
else {
s?.copy2
}
sss.<!UNSAFE_CALL!>length<!>
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// See KT-11007: Wrong smart cast to not-null type after safe calls in if / when expression
val String.copy: String
@@ -1,13 +0,0 @@
// See KT-10056
class Foo(val bar: String)
fun test(foo: Foo?) {
foo?.bar.let {
// Error, foo?.bar is nullable
it.<!UNSAFE_CALL!>length<!>
// Error, foo is nullable
foo.<!UNSAFE_CALL!>bar<!>.length
// Correct
foo?.bar?.length
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// See KT-10056
class Foo(val bar: String)
@@ -11,22 +11,22 @@ fun String.notNullLet(f: (String) -> Unit) = f(this)
fun test(foo: Foo?) {
foo?.bar?.gav.let {
// Error, foo?.bar?.gav is nullable
it.<!UNSAFE_CALL!>length<!>
it<!UNSAFE_CALL!>.<!>length
// Error, foo is nullable
foo.<!UNSAFE_CALL!>bar<!>.gav.length
foo<!UNSAFE_CALL!>.<!>bar.gav.length
// Correct
foo?.bar?.gav?.length
}
foo?.bar?.gav.call { it }?.notNullLet {
foo.<!UNSAFE_CALL!>hashCode<!>()
foo.<!UNSAFE_CALL!>bar<!>.hashCode()
foo<!UNSAFE_CALL!>.<!>hashCode()
foo<!UNSAFE_CALL!>.<!>bar.hashCode()
}
}
fun testNotNull(foo: Foo) {
val s: String? = ""
foo.baz(s!!)?.gav.let {
it.<!UNSAFE_CALL!>length<!>
it<!UNSAFE_CALL!>.<!>length
// Ok because of foo.
s.length.hashCode()
}
@@ -35,7 +35,7 @@ fun testNotNull(foo: Foo) {
fun testNullable(foo: Foo?) {
val s: String? = ""
foo?.baz(s!!)?.gav.let {
it.<!UNSAFE_CALL!>length<!>
it<!UNSAFE_CALL!>.<!>length
// Ok because of foo?.
s?.length?.hashCode()
}
@@ -1,25 +0,0 @@
// FILE: Foo.java
public class Foo {
public String bar;
private Foo(String bar) {
this.bar = bar;
}
public static Foo create(String bar) {
return new Foo(bar);
}
}
// FILE: Test.kt
fun test() {
val foo = Foo.create(null)
foo?.bar.let {
// Error, foo?.bar is nullable
it.<!UNSAFE_CALL!>length<!>
// Foo is nullable but flexible, so call is considered safe here
foo.bar.length
// Correct
foo?.bar?.length
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// FILE: Foo.java
public class Foo {
public String bar;
@@ -18,7 +18,7 @@ fun kt6840_2(s: String?) {
fun kt1635(s: String?) {
s?.hashCode()!!
s.<!UNSAFE_CALL!>hashCode<!>()
s<!UNSAFE_CALL!>.<!>hashCode()
}
fun kt2127() {
@@ -80,7 +80,7 @@ fun useA(a: A): Int = a.hashCode()
fun kt7491_2() {
val a = getA()
(a?.let { useA(a) } ?: a.<!UNSAFE_CALL!>y<!> ).toString()
(a?.let { useA(a) } ?: a<!UNSAFE_CALL!>.<!>y ).toString()
}
fun String.correct() = true
@@ -88,7 +88,7 @@ fun String.correct() = true
fun kt8492(s: String?) {
if (s?.correct() ?: false) {
// To be supported
s.<!UNSAFE_CALL!>length<!>
s<!UNSAFE_CALL!>.<!>length
}
}
@@ -118,7 +118,7 @@ class Wrapper {
fun falsePositive(w: Wrapper) {
if (w.unwrap() != null) {
// Here we should NOT have smart cast
w.unwrap().<!UNSAFE_CALL!>length<!>
w.unwrap()<!UNSAFE_CALL!>.<!>length
}
}
@@ -2,5 +2,5 @@ fun calc(x: List<String>?): Int {
// x should be non-null in arguments list
x?.get(x.size - 1)
// but not also here!
return x.<!UNSAFE_CALL!>size<!>
return x<!UNSAFE_CALL!>.<!>size
}
@@ -2,5 +2,5 @@ fun calc(x: List<String>?): Int {
// x should be non-null in arguments list
x?.subList(x.size - 1, x.size)
// but not also here!
return x.<!UNSAFE_CALL!>size<!>
return x<!UNSAFE_CALL!>.<!>size
}