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
@@ -3,7 +3,7 @@
fun testIsNullOrBlank(x: String?) {
if (x.isNullOrBlank()) {
x.<!UNSAFE_CALL!>length<!>
x<!UNSAFE_CALL!>.<!>length
}
else {
x.length
@@ -15,6 +15,6 @@ fun testIsNotNullOrBlank(x: String?) {
x.length
}
x.<!UNSAFE_CALL!>length<!>
x<!UNSAFE_CALL!>.<!>length
}
@@ -3,7 +3,7 @@
fun testIsNullOrEmpty(x: String?) {
if (x.isNullOrEmpty()) {
x.<!UNSAFE_CALL!>length<!>
x<!UNSAFE_CALL!>.<!>length
}
else {
x.length
@@ -15,6 +15,6 @@ fun testIsNotNullOrEmpty(x: String?) {
x.length
}
x.<!UNSAFE_CALL!>length<!>
x<!UNSAFE_CALL!>.<!>length
}
@@ -14,7 +14,7 @@ fun nullWhenNull(x: Int?): Int? {
fun testNullWhenNull(x: Int?) {
if (nullWhenNull(x) == null) {
x.<!UNSAFE_CALL!>dec<!>()
x<!UNSAFE_CALL!>.<!>dec()
}
else {
x.dec()
@@ -24,10 +24,10 @@ fun testNullWhenNull(x: Int?) {
x.dec()
}
else {
x.<!UNSAFE_CALL!>dec<!>()
x<!UNSAFE_CALL!>.<!>dec()
}
x.<!UNSAFE_CALL!>dec<!>()
x<!UNSAFE_CALL!>.<!>dec()
}
// NB. it is the same function as `nullWhenNull`, but annotations specifies other facet of the function behaviour
@@ -43,15 +43,15 @@ fun testNotNullWhenNotNull (x: Int?) {
x == null
}
else {
x.<!UNSAFE_CALL!>dec<!>()
x<!UNSAFE_CALL!>.<!>dec()
}
if (notNullWhenNotNull(x) != null) {
x.<!UNSAFE_CALL!>dec<!>()
x<!UNSAFE_CALL!>.<!>dec()
}
else {
x == null
}
x.<!UNSAFE_CALL!>dec<!>()
x<!UNSAFE_CALL!>.<!>dec()
}
@@ -20,28 +20,28 @@ fun myEqualsNotNull(x: Int?): Boolean {
}
fun testBasicEquals(x: Int?) {
x.<!UNSAFE_CALL!>inc<!>()
x<!UNSAFE_CALL!>.<!>inc()
if (myEqualsNull(x)) {
x.<!UNSAFE_CALL!>inc<!>()
x<!UNSAFE_CALL!>.<!>inc()
}
else {
x.inc()
}
x.<!UNSAFE_CALL!>inc<!>()
x<!UNSAFE_CALL!>.<!>inc()
}
fun testBasicNotEquals(x: Int?) {
x.<!UNSAFE_CALL!>inc<!>()
x<!UNSAFE_CALL!>.<!>inc()
if (myEqualsNotNull(x)) {
x.inc()
}
else {
x.<!UNSAFE_CALL!>inc<!>()
x<!UNSAFE_CALL!>.<!>inc()
}
x.<!UNSAFE_CALL!>inc<!>()
x<!UNSAFE_CALL!>.<!>inc()
}
@@ -14,7 +14,7 @@ fun Any?.isNull(): Boolean {
fun smartcastOnReceiver(x: Int?) {
if (x.isNull()) {
x.<!UNSAFE_CALL!>inc<!>()
x<!UNSAFE_CALL!>.<!>inc()
}
else {
x.dec()
@@ -26,10 +26,10 @@ class UnstableReceiver {
fun smartcastOnUnstableReceiver() {
if (x.isNull()) {
x.<!UNSAFE_CALL!>inc<!>()
x<!UNSAFE_CALL!>.<!>inc()
}
else {
x.<!UNSAFE_CALL!>dec<!>()
x<!UNSAFE_CALL!>.<!>dec()
}
}
}
@@ -6,6 +6,6 @@ import kotlin.contracts.*
fun f3(value: String?) {
if (!value.isNullOrEmpty() is Boolean) {
value.<!UNSAFE_CALL!>length<!>
value<!UNSAFE_CALL!>.<!>length
}
}
@@ -1,6 +0,0 @@
val foo = iterator {
yield(0)
val nullable: String? = null
nullable.<!UNSAFE_CALL!>length<!>
nullable.<!UNSAFE_CALL!>get<!>(2)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
val foo = iterator {
yield(0)
val nullable: String? = null
@@ -87,7 +87,7 @@ fun test() {
this@with.<!UNRESOLVED_REFERENCE!>yield<!>("")
yield2("")
this@with.<!UNSAFE_CALL!>yield2<!>("")
this@with<!UNSAFE_CALL!>.<!>yield2("")
}
}
}
@@ -1,7 +0,0 @@
// KT-9051: Allow smart cast for captured variables if they are not modified
fun foo(y: String?) {
var x: String? = null
y?.let { x = it }
x.<!UNSAFE_CALL!>length<!> // Smart cast is not possible
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// KT-9051: Allow smart cast for captured variables if they are not modified
fun foo(y: String?) {
@@ -5,7 +5,7 @@ fun bar(z: String?) = z
fun foo(y: String?) {
var x: String? = ""
if (x != null) {
bar(y?.let { x = null; it }).<!UNSAFE_CALL!>length<!>
bar(y?.let { x = null; it })<!UNSAFE_CALL!>.<!>length
x.length // Smart cast is not possible
}
}
@@ -2,7 +2,7 @@ fun foo(y: String?) {
var x: String? = ""
if (x != null) {
with(y?.let { x = null; it }) {
this.<!UNSAFE_CALL!>length<!>
this<!UNSAFE_CALL!>.<!>length
x.length
}
x.length
@@ -15,7 +15,7 @@ fun test2() {
catch (e: ExcB) {
10
}
s.<!UNSAFE_CALL!>length<!>
s<!UNSAFE_CALL!>.<!>length
}
fun test3() {
@@ -28,7 +28,7 @@ fun test3() {
catch (e: ExcB) {
return
}
s.<!UNSAFE_CALL!>length<!>
s<!UNSAFE_CALL!>.<!>length
}
fun test4() {
@@ -41,7 +41,7 @@ fun test4() {
finally {
""
}
s.<!UNSAFE_CALL!>length<!>
s<!UNSAFE_CALL!>.<!>length
}
fun test5() {
@@ -54,7 +54,7 @@ fun test5() {
finally {
return
}
s.<!UNSAFE_CALL!>length<!>
s<!UNSAFE_CALL!>.<!>length
}
fun test6() {
@@ -67,7 +67,7 @@ fun test6() {
catch (e: ExcB) {
return
}
s.<!UNSAFE_CALL!>length<!>
s<!UNSAFE_CALL!>.<!>length
}
fun test7() {
@@ -80,7 +80,7 @@ fun test7() {
catch (e: ExcB) {
""
}
s.<!UNSAFE_CALL!>length<!>
s<!UNSAFE_CALL!>.<!>length
}
fun test8() {
@@ -89,7 +89,7 @@ fun test8() {
} catch (e: ExcA) {
null
}
s.<!UNSAFE_CALL!>length<!>
s<!UNSAFE_CALL!>.<!>length
}
fun test9() {
@@ -13,11 +13,11 @@ fun test0(x: Int?) {
if (x != null) {
x.inc()
y.<!UNSAFE_CALL!>inc<!>()
y<!UNSAFE_CALL!>.<!>inc()
}
if (y != null) {
x.<!UNSAFE_CALL!>inc<!>()
x<!UNSAFE_CALL!>.<!>inc()
y.inc()
}
}
@@ -32,11 +32,11 @@ fun test1(x: Int?) {
if (x != null) {
x.inc()
y.<!UNSAFE_CALL!>inc<!>()
y<!UNSAFE_CALL!>.<!>inc()
}
if (y != null) {
x.<!UNSAFE_CALL!>inc<!>()
x<!UNSAFE_CALL!>.<!>inc()
y.inc()
}
}
@@ -51,11 +51,11 @@ fun test2(x: Int?) {
if (x != null) {
x.inc()
y.<!UNSAFE_CALL!>inc<!>()
y<!UNSAFE_CALL!>.<!>inc()
}
if (y != null) {
x.<!UNSAFE_CALL!>inc<!>()
x<!UNSAFE_CALL!>.<!>inc()
y.inc()
}
}
@@ -69,11 +69,11 @@ fun test3(x: Int?) {
if (x != null) {
x.inc()
y.<!UNSAFE_CALL!>inc<!>()
y<!UNSAFE_CALL!>.<!>inc()
}
if (y != null) {
x.<!UNSAFE_CALL!>inc<!>()
x<!UNSAFE_CALL!>.<!>inc()
y.inc()
}
}
@@ -91,11 +91,11 @@ fun test5(x: Int?) {
if (x != null) {
x.inc()
y.<!UNSAFE_CALL!>inc<!>()
y<!UNSAFE_CALL!>.<!>inc()
}
if (y != null) {
x.<!UNSAFE_CALL!>inc<!>()
x<!UNSAFE_CALL!>.<!>inc()
y.inc()
}
}
@@ -15,8 +15,8 @@ fun test1(s: String?) {
catch (e: Exception) {
requireNotNull(s)
}
t2.<!UNSAFE_CALL!>not<!>()
s.<!UNSAFE_CALL!>length<!>
t2<!UNSAFE_CALL!>.<!>not()
s<!UNSAFE_CALL!>.<!>length
}
}
@@ -74,7 +74,7 @@ fun test5(s: String?) {
catch (e: ExcB) {
}
s.<!UNSAFE_CALL!>length<!>
s<!UNSAFE_CALL!>.<!>length
}
fun test6(s: String?) {
@@ -16,8 +16,8 @@ fun test1(s: String?) {
catch (e: Exception) {
requireNotNull(s)
}
t2.<!UNSAFE_CALL!>not<!>()
s.<!UNSAFE_CALL!>length<!>
t2<!UNSAFE_CALL!>.<!>not()
s<!UNSAFE_CALL!>.<!>length
}
}
@@ -75,7 +75,7 @@ fun test5(s: String?) {
catch (e: ExcB) {
}
s.<!UNSAFE_CALL!>length<!>
s<!UNSAFE_CALL!>.<!>length
}
fun test6(s: String?) {
@@ -13,15 +13,15 @@ fun test1() {
try {
x = null
} catch (e: Exception) {
x.<!UNSAFE_CALL!>length<!> // smartcast shouldn't be allowed (OOME could happen after `x = null`)
x<!UNSAFE_CALL!>.<!>length // smartcast shouldn't be allowed (OOME could happen after `x = null`)
throw e
}
finally {
// smartcast shouldn't be allowed, `x = null` could've happened
x.<!UNSAFE_CALL!>length<!>
x<!UNSAFE_CALL!>.<!>length
}
// smartcast shouldn't be allowed, `x = null` could've happened
x.<!UNSAFE_CALL!>length<!>
x<!UNSAFE_CALL!>.<!>length
}
// With old DFA of try/catch info about unsound smartcasts after try
@@ -33,12 +33,12 @@ fun test2() {
try {
x = null
} catch (e: Exception) {
x.<!UNSAFE_CALL!>length<!>
x<!UNSAFE_CALL!>.<!>length
}
finally {
x.<!UNSAFE_CALL!>length<!>
x<!UNSAFE_CALL!>.<!>length
}
x.<!UNSAFE_CALL!>length<!>
x<!UNSAFE_CALL!>.<!>length
}
fun test3() {
@@ -49,7 +49,7 @@ fun test3() {
} catch (e: Exception) {
t2 = null
}
t2.<!UNSAFE_CALL!>not<!>() // wrong smartcast, NPE
t2<!UNSAFE_CALL!>.<!>not() // wrong smartcast, NPE
}
}
@@ -59,7 +59,7 @@ fun test4() {
try {
t2 = null
} finally { }
t2.<!UNSAFE_CALL!>not<!>() // wrong smartcast, NPE
t2<!UNSAFE_CALL!>.<!>not() // wrong smartcast, NPE
}
}
@@ -80,10 +80,10 @@ fun test5() {
}
finally {
s1.length
s2.<!UNSAFE_CALL!>length<!>
s2<!UNSAFE_CALL!>.<!>length
}
s1.length
s2.<!UNSAFE_CALL!>length<!>
s2<!UNSAFE_CALL!>.<!>length
}
fun test6(s1: String?, s2: String?) {
@@ -97,10 +97,10 @@ fun test6(s1: String?, s2: String?) {
return
}
finally {
s.<!UNSAFE_CALL!>length<!>
s<!UNSAFE_CALL!>.<!>length
requireNotNull(s2)
}
s.<!UNSAFE_CALL!>length<!>
s1.<!UNSAFE_CALL!>length<!>
s<!UNSAFE_CALL!>.<!>length
s1<!UNSAFE_CALL!>.<!>length
s2.length
}
}
@@ -14,15 +14,15 @@ fun test1() {
try {
x = null
} catch (e: Exception) {
x.<!UNSAFE_CALL!>length<!> // smartcast shouldn't be allowed (OOME could happen after `x = null`)
x<!UNSAFE_CALL!>.<!>length // smartcast shouldn't be allowed (OOME could happen after `x = null`)
throw e
}
finally {
// smartcast shouldn't be allowed, `x = null` could've happened
x.<!UNSAFE_CALL!>length<!>
x<!UNSAFE_CALL!>.<!>length
}
// smartcast shouldn't be allowed, `x = null` could've happened
x.<!UNSAFE_CALL!>length<!>
x<!UNSAFE_CALL!>.<!>length
}
// With old DFA of try/catch info about unsound smartcasts after try
@@ -35,12 +35,12 @@ fun test2() {
x = null
} catch (e: Exception) {
// BAD
x.<!UNSAFE_CALL!>length<!>
x<!UNSAFE_CALL!>.<!>length
}
finally {
x.<!UNSAFE_CALL!>length<!>
x<!UNSAFE_CALL!>.<!>length
}
x.<!UNSAFE_CALL!>length<!>
x<!UNSAFE_CALL!>.<!>length
}
fun test3() {
@@ -51,7 +51,7 @@ fun test3() {
} catch (e: Exception) {
t2 = null
}
t2.<!UNSAFE_CALL!>not<!>() // wrong smartcast, NPE
t2<!UNSAFE_CALL!>.<!>not() // wrong smartcast, NPE
}
}
@@ -61,7 +61,7 @@ fun test4() {
try {
t2 = null
} finally { }
t2.<!UNSAFE_CALL!>not<!>() // wrong smartcast, NPE
t2<!UNSAFE_CALL!>.<!>not() // wrong smartcast, NPE
}
}
@@ -82,10 +82,10 @@ fun test5() {
}
finally {
s1.length
s2.<!UNSAFE_CALL!>length<!>
s2<!UNSAFE_CALL!>.<!>length
}
s1.length
s2.<!UNSAFE_CALL!>length<!>
s2<!UNSAFE_CALL!>.<!>length
}
fun test6(s1: String?, s2: String?) {
@@ -99,10 +99,10 @@ fun test6(s1: String?, s2: String?) {
return
}
finally {
s.<!UNSAFE_CALL!>length<!>
s<!UNSAFE_CALL!>.<!>length
requireNotNull(s2)
}
s.<!UNSAFE_CALL!>length<!>
s1.<!UNSAFE_CALL!>length<!>
s<!UNSAFE_CALL!>.<!>length
s1<!UNSAFE_CALL!>.<!>length
s2.length
}