FIR checker: differentiate UNSAFE_CALL from INAPPLICABLE_CANDIDATE
To do so, inside the root cause of inapplicable candidate errors, we will record expected/actual type of receiver, if any. That will help identifying inapplicable calls on nullable receiver.
This commit is contained in:
committed by
Mikhail Glukhikh
parent
4b823eca21
commit
e72ddbcbfe
@@ -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.<!INAPPLICABLE_CANDIDATE!>size<!>
|
||||
return x.<!UNSAFE_CALL!>size<!>
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fun calc(x: List<String>?): Int {
|
||||
// x is not-null only inside subList
|
||||
x?.subList(0, x.size - 1).<!INAPPLICABLE_CANDIDATE!>get<!>(x.<!INAPPLICABLE_CANDIDATE!>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.<!INAPPLICABLE_CANDIDATE!>size<!>
|
||||
return x.<!UNSAFE_CALL!>size<!>
|
||||
}
|
||||
|
||||
+1
-1
@@ -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.<!INAPPLICABLE_CANDIDATE!>length<!>
|
||||
return y.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
|
||||
+4
-4
@@ -10,14 +10,14 @@ fun foo() {
|
||||
} else {
|
||||
s?.length
|
||||
}
|
||||
ss.<!INAPPLICABLE_CANDIDATE!>hashCode<!>() // Smart-cast to Int, should be unsafe call
|
||||
ss.<!UNSAFE_CALL!>hashCode<!>() // Smart-cast to Int, should be unsafe call
|
||||
val sss = if (true) {
|
||||
s?.copy
|
||||
}
|
||||
else {
|
||||
s?.copy
|
||||
}
|
||||
sss.<!INAPPLICABLE_CANDIDATE!>length<!>
|
||||
sss.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
|
||||
class My {
|
||||
@@ -31,13 +31,13 @@ class My {
|
||||
} else {
|
||||
s?.length
|
||||
}
|
||||
ss.<!INAPPLICABLE_CANDIDATE!>hashCode<!>()
|
||||
ss.<!UNSAFE_CALL!>hashCode<!>()
|
||||
val sss = if (true) {
|
||||
s?.copy2
|
||||
}
|
||||
else {
|
||||
s?.copy2
|
||||
}
|
||||
sss.<!INAPPLICABLE_CANDIDATE!>length<!>
|
||||
sss.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -4,9 +4,9 @@ class Foo(val bar: String)
|
||||
fun test(foo: Foo?) {
|
||||
foo?.bar.let {
|
||||
// Error, foo?.bar is nullable
|
||||
it.<!INAPPLICABLE_CANDIDATE!>length<!>
|
||||
it.<!UNSAFE_CALL!>length<!>
|
||||
// Error, foo is nullable
|
||||
foo.<!INAPPLICABLE_CANDIDATE!>bar<!>.length
|
||||
foo.<!UNSAFE_CALL!>bar<!>.length
|
||||
// Correct
|
||||
foo?.bar?.length
|
||||
}
|
||||
|
||||
Vendored
+6
-6
@@ -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.<!INAPPLICABLE_CANDIDATE!>length<!>
|
||||
it.<!UNSAFE_CALL!>length<!>
|
||||
// Error, foo is nullable
|
||||
foo.<!INAPPLICABLE_CANDIDATE!>bar<!>.gav.length
|
||||
foo.<!UNSAFE_CALL!>bar<!>.gav.length
|
||||
// Correct
|
||||
foo?.bar?.gav?.length
|
||||
}
|
||||
foo?.bar?.gav.call { it }?.notNullLet {
|
||||
foo.<!INAPPLICABLE_CANDIDATE!>hashCode<!>()
|
||||
foo.<!INAPPLICABLE_CANDIDATE!>bar<!>.hashCode()
|
||||
foo.<!UNSAFE_CALL!>hashCode<!>()
|
||||
foo.<!UNSAFE_CALL!>bar<!>.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
fun testNotNull(foo: Foo) {
|
||||
val s: String? = ""
|
||||
foo.baz(s!!)?.gav.let {
|
||||
it.<!INAPPLICABLE_CANDIDATE!>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.<!INAPPLICABLE_CANDIDATE!>length<!>
|
||||
it.<!UNSAFE_CALL!>length<!>
|
||||
// Ok because of foo?.
|
||||
s?.length?.hashCode()
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -16,7 +16,7 @@ fun test() {
|
||||
val foo = Foo.create(null)
|
||||
foo?.bar.let {
|
||||
// Error, foo?.bar is nullable
|
||||
it.<!INAPPLICABLE_CANDIDATE!>length<!>
|
||||
it.<!UNSAFE_CALL!>length<!>
|
||||
// Foo is nullable but flexible, so call is considered safe here
|
||||
foo.bar.length
|
||||
// Correct
|
||||
|
||||
+4
-4
@@ -18,7 +18,7 @@ fun kt6840_2(s: String?) {
|
||||
|
||||
fun kt1635(s: String?) {
|
||||
s?.hashCode()!!
|
||||
s.<!INAPPLICABLE_CANDIDATE!>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.<!INAPPLICABLE_CANDIDATE!>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.<!INAPPLICABLE_CANDIDATE!>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().<!INAPPLICABLE_CANDIDATE!>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.<!INAPPLICABLE_CANDIDATE!>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.<!INAPPLICABLE_CANDIDATE!>size<!>
|
||||
return x.<!UNSAFE_CALL!>size<!>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user