[FIR] UNREACHABLE_CODE diagnostic (wip)

Implementation for PSI only
This commit is contained in:
Andrey Zinovyev
2021-07-29 12:39:47 +03:00
committed by TeamCityServer
parent dcd61c292d
commit ec4cbfef59
47 changed files with 348 additions and 220 deletions
@@ -1,12 +0,0 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun testCommasAndWhitespaces() {
fun bar(i: Int, s: String, x: Any) {}
bar( 1 , todo() , "" )
}
fun todo(): Nothing = throw Exception()
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun testCommasAndWhitespaces() {
@@ -1,18 +1,18 @@
package a
fun test1() {
bar(
<!UNREACHABLE_CODE!>bar(<!>
11,
todo(),//comment1
""//comment2
)
<!UNREACHABLE_CODE!>""//comment2
)<!>
}
fun test2() {
bar(11, todo()/*comment1*/, ""/*comment2*/)
<!UNREACHABLE_CODE!>bar(<!>11, todo()/*comment1*/, <!UNREACHABLE_CODE!>""/*comment2*/)<!>
}
fun test3() {
bar(11, l@(todo()/*comment*/), "")
<!UNREACHABLE_CODE!>bar(<!>11, <!UNREACHABLE_CODE!>l@(<!>todo()/*comment*/<!UNREACHABLE_CODE!>), "")<!>
}
fun todo(): Nothing = throw Exception()
@@ -1,11 +1,11 @@
fun testInvoke() {
operator fun Nothing.invoke(): Nothing = this
todo()()
todo()<!UNREACHABLE_CODE!>()<!>
}
fun testInvokeWithLambda() {
operator fun Nothing.invoke(i: Int, f: () -> Int) = f
todo()(1){ 42 }
todo()<!UNREACHABLE_CODE!>(1){ 42 }<!>
}
fun todo(): Nothing = throw Exception()
fun todo(): Nothing = throw Exception()
@@ -1,11 +1,11 @@
fun test11() {
fun Any.bar(i: Int) {}
todo().bar(1)
todo()<!UNREACHABLE_CODE!>.bar(1)<!>
}
fun test12() {
fun Any.bar(i: Int) {}
todo()<!UNNECESSARY_SAFE_CALL!>?.<!>bar(1)
todo()<!UNREACHABLE_CODE!><!UNNECESSARY_SAFE_CALL!>?.<!>bar(1)<!>
}
fun todo(): Nothing = throw Exception()
@@ -3,80 +3,80 @@
fun t1() : Int{
return 0
1
<!UNREACHABLE_CODE!>1<!>
}
fun t1a() : Int {
<!RETURN_TYPE_MISMATCH!>return<!>
return 1
1
<!UNREACHABLE_CODE!>return 1<!>
<!UNREACHABLE_CODE!>1<!>
}
fun t1b() : Int {
return 1
return 1
1
<!UNREACHABLE_CODE!>return 1<!>
<!UNREACHABLE_CODE!>1<!>
}
fun t1c() : Int {
return 1
<!RETURN_TYPE_MISMATCH!>return<!>
1
<!RETURN_TYPE_MISMATCH, UNREACHABLE_CODE!>return<!>
<!UNREACHABLE_CODE!>1<!>
}
fun t2() : Int {
if (1 > 2)
return 1
else return 1
1
<!UNREACHABLE_CODE!>1<!>
}
fun t2a() : Int {
if (1 > 2) {
return 1
1
<!UNREACHABLE_CODE!>1<!>
} else { return 1
2
<!UNREACHABLE_CODE!>2<!>
}
1
<!UNREACHABLE_CODE!>1<!>
}
fun t3() : Any {
if (1 > 2)
return 2
else return ""
1
<!UNREACHABLE_CODE!>1<!>
}
fun t4(a : Boolean) : Int {
do {
return 1
}
while (a)
1
while (<!UNREACHABLE_CODE!>a<!>)
<!UNREACHABLE_CODE!>1<!>
}
fun t4break(a : Boolean) : Int {
do {
break
}
while (a)
while (<!UNREACHABLE_CODE!>a<!>)
return 1
}
fun t5() : Int {
do {
return 1
2
<!UNREACHABLE_CODE!>2<!>
}
while (1 > 2)
return 1
while (<!UNREACHABLE_CODE!>1 > 2<!>)
<!UNREACHABLE_CODE!>return 1<!>
}
fun t6() : Int {
while (1 > 2) {
return 1
2
<!UNREACHABLE_CODE!>2<!>
}
return 1
}
@@ -84,7 +84,7 @@ fun t6() : Int {
fun t6break() : Int {
while (1 > 2) {
break
2
<!UNREACHABLE_CODE!>2<!>
}
return 1
}
@@ -92,7 +92,7 @@ fun t6break() : Int {
fun t7(b : Int) : Int {
for (i in 1..b) {
return 1
2
<!UNREACHABLE_CODE!>2<!>
}
return 1
}
@@ -100,7 +100,7 @@ fun t7(b : Int) : Int {
fun t7break(b : Int) : Int {
for (i in 1..b) {
return 1
2
<!UNREACHABLE_CODE!>2<!>
}
return 1
}
@@ -108,54 +108,54 @@ fun t7break(b : Int) : Int {
fun t7() : Int {
try {
return 1
2
<!UNREACHABLE_CODE!>2<!>
}
catch (<!THROWABLE_TYPE_MISMATCH!>e : Any<!>) {
2
}
return 1 // this is OK, like in Java
<!UNREACHABLE_CODE!>return 1<!> // this is OK, like in Java
}
fun t8() : Int {
try {
return 1
2
<!UNREACHABLE_CODE!>2<!>
}
catch (<!THROWABLE_TYPE_MISMATCH!>e : Any<!>) {
return 1
2
}
return 1
<!UNREACHABLE_CODE!>return 1<!>
}
fun blockAndAndMismatch() : Boolean {
(return true) || (return false)
return true
(return true) || (<!UNREACHABLE_CODE!>return false<!>)
<!UNREACHABLE_CODE!>return true<!>
}
fun tf() : Int {
try {return 1} finally{return 1}
return 1
<!UNREACHABLE_CODE!>return 1<!>
}
fun failtest(a : Int) : Int {
if (fail() || true) {
if (fail() || <!UNREACHABLE_CODE!>true<!>) {
}
return 1
<!UNREACHABLE_CODE!>return 1<!>
}
fun foo(a : Nothing) : Unit {
fun foo(a : Nothing) : <!REDUNDANT_RETURN_UNIT_TYPE!>Unit<!> {
1
a
2
<!UNREACHABLE_CODE!>2<!>
}
fun fail() : Nothing {
throw java.lang.RuntimeException()
}
fun nullIsNotNothing() : Unit {
fun nullIsNotNothing() : <!REDUNDANT_RETURN_UNIT_TYPE!>Unit<!> {
val x : Int? = 1
if (x != null) {
return
@@ -165,5 +165,5 @@ fun nullIsNotNothing() : Unit {
fun returnInWhile(a: Int) {
do {return}
while (1 > a)
while (<!UNREACHABLE_CODE!>1 > a<!>)
}
@@ -1,17 +1,17 @@
package c
fun test1() {
val r: Nothing = null!!
<!UNREACHABLE_CODE!>val <!UNUSED_VARIABLE!>r<!>: Nothing =<!> null!!
}
fun test2(a: A) {
a + a
bar()
<!UNREACHABLE_CODE!>bar()<!>
}
fun test3() {
null!!
bar()
<!UNREACHABLE_CODE!>bar()<!>
}
fun throwNPE(): Nothing = null!!
@@ -1,40 +1,40 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun testArrayAccess1(array: Array<Any>) {
array[todo()]
array<!UNREACHABLE_CODE!>[<!>todo()<!UNREACHABLE_CODE!>]<!>
}
fun testArrayAccess2() {
operator fun Nothing.get(i: Int, s: String) {}
todo()[1, ""]
todo()<!UNREACHABLE_CODE!>[1, ""]<!>
}
fun testAraryAccess3() {
operator fun Nothing.get(n: Nothing) {}
todo()[todo()]
todo()<!UNREACHABLE_CODE!>[todo()]<!>
}
fun testArrayAssignment1(array: Array<Any>) {
array[todo()] = 11
array<!UNREACHABLE_CODE!>[<!>todo()<!UNREACHABLE_CODE!>] = 11<!>
}
fun testArrayAssignment2(array: Array<Any>) {
array[1] = todo()
array<!UNREACHABLE_CODE!>[<!>1<!UNREACHABLE_CODE!>] =<!> todo()
}
fun testArrayAssignment3(n: Nothing) {
operator fun Nothing.set(i: Int, j: Int) {}
n[1] = 2
n<!UNREACHABLE_CODE!>[1] = 2<!>
}
fun testArrayAssignment4(n: Nothing) {
operator fun Nothing.set(i: Int, a: Any) {}
n[1] = todo()
n<!UNREACHABLE_CODE!>[1] = todo()<!>
}
fun testArrayPlusAssign(array: Array<Any>) {
operator fun Any.plusAssign(a: Any) {}
array[1] += todo()
array<!UNREACHABLE_CODE!>[<!>1<!UNREACHABLE_CODE!>] +=<!> todo()
}
fun todo(): Nothing = throw Exception()
fun todo(): Nothing = throw Exception()
@@ -1,18 +1,18 @@
fun testAssignment() {
var a = 1
a = todo()
var <!UNUSED_VARIABLE!>a<!> = 1
<!UNREACHABLE_CODE!><!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> =<!> todo()
}
fun testVariableDeclaration() {
val a = todo()
<!UNREACHABLE_CODE!>val <!UNUSED_VARIABLE!>a<!> =<!> todo()
}
fun testPlusAssign() {
operator fun Int.plusAssign(i: Int) {}
var a = 1
a += todo()
<!CAN_BE_VAL!>var<!> a = 1
a <!UNREACHABLE_CODE!>+=<!> todo()
}
fun todo(): Nothing = throw Exception()
fun todo(): Nothing = throw Exception()
@@ -1,14 +1,14 @@
fun testBinary1() {
operator fun Int.times(s: String) {}
todo() * ""
todo() <!UNREACHABLE_CODE!>* ""<!>
}
fun testBinary2() {
"1" + todo()
"1" <!UNREACHABLE_CODE!>+<!> todo()
}
fun testElvis1() {
todo() <!USELESS_ELVIS!>?: ""<!>
todo() <!UNREACHABLE_CODE, USELESS_ELVIS!>?: ""<!>
}
fun testElvis2(s: String?) {
@@ -24,15 +24,15 @@ fun testAnd1(b: Boolean) {
}
fun testAnd2(b: Boolean) {
todo() && b
todo() && <!UNREACHABLE_CODE!>b<!>
}
fun returnInBinary1(): Boolean {
(return true) && (return false)
(return true) && (<!UNREACHABLE_CODE!>return false<!>)
}
fun returnInBinary2(): Boolean {
(return true) || (return false)
(return true) || (<!UNREACHABLE_CODE!>return false<!>)
}
fun todo(): Nothing = throw Exception()
@@ -3,11 +3,11 @@
fun testArgumentInCall() {
fun bar(i: Int, s: String, x: Any) {}
bar(1, todo(), "")
<!UNREACHABLE_CODE!>bar(<!>1, todo(), <!UNREACHABLE_CODE!>"")<!>
}
fun testArgumentInVariableAsFunctionCall(f: (Any) -> Unit) {
f(todo())
<!UNREACHABLE_CODE!>f(<!>todo()<!UNREACHABLE_CODE!>)<!>
}
fun todo(): Nothing = throw Exception()
fun todo(): Nothing = throw Exception()
@@ -2,22 +2,22 @@
fun unreachable0() {
return
return todo()
<!UNREACHABLE_CODE!>return todo()<!>
}
fun unreachable2() {
return
val a = todo()
<!UNREACHABLE_CODE!>val <!UNUSED_VARIABLE!>a<!> = todo()<!>
}
fun unreachable3() {
return
bar(todo())
<!UNREACHABLE_CODE!>bar(todo())<!>
}
fun unreachable4(array: Array<Any>) {
return
array[todo()]
<!UNREACHABLE_CODE!>array[todo()]<!>
}
fun bar(a: Any) {}
@@ -1,5 +1,5 @@
fun testIf() {
if (todo()) 1 else 2
if (todo()) <!UNREACHABLE_CODE!>1<!> else <!UNREACHABLE_CODE!>2<!>
}
fun testIf1(b: Boolean) {
@@ -1,13 +0,0 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun testCompound() {
operator fun Nothing.get(i: Int) {}
todo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>[12]
}
fun testCompound1() {
operator fun Int.times(s: String): Array<String> = throw Exception()
(todo() * "")[1]
}
fun todo(): Nothing = throw Exception()
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun testCompound() {
@@ -1,13 +1,13 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun testObject() {
object : Foo(todo()) {
object : <!UNREACHABLE_CODE!>Foo(<!>todo()<!UNREACHABLE_CODE!>)<!> {
fun foo() = 1
}
}
fun testObjectExpression() {
val a = object : Foo(todo()) {
val <!UNUSED_VARIABLE!>a<!> = object : <!UNREACHABLE_CODE!>Foo(<!>todo()<!UNREACHABLE_CODE!>)<!> {
fun foo() = 1
}
}
@@ -15,13 +15,13 @@ fun testObjectExpression() {
fun testObjectExpression1() {
fun bar(i: Int, x: Any) {}
bar(1, object : Foo(todo()) {
bar(1, object : <!UNREACHABLE_CODE!>Foo(<!>todo()<!UNREACHABLE_CODE!>)<!> {
fun foo() = 1
})
}
fun testClassDeclaration() {
class C : Foo(todo()) {}
class C : <!UNREACHABLE_CODE!>Foo(<!>todo()<!UNREACHABLE_CODE!>)<!> {}
bar()
}
@@ -33,4 +33,4 @@ fun testFunctionDefaultArgument() {
open class Foo(i: Int) {}
fun todo(): Nothing = throw Exception()
fun bar() {}
fun bar() {}
@@ -1,21 +0,0 @@
fun testFor() {
operator fun Nothing.iterator() = (0..1).iterator()
for (i in todo()) {}
}
fun testWhile() {
while (todo()) {
}
}
fun testDoWhile() {
do {
} while(todo())
bar()
}
fun todo(): Nothing = throw Exception()
fun bar() {}
@@ -1,3 +1,5 @@
// FIR_IDENTICAL
fun testFor() {
operator fun Nothing.iterator() = (0..1).iterator()
@@ -1,5 +0,0 @@
fun testReturn() {
return todo()
}
fun todo(): Nothing = throw Exception()
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
fun testReturn() {
<!UNREACHABLE_CODE!>return<!> todo()
}
@@ -1,15 +1,15 @@
fun testPrefix() {
operator fun Any.not() {}
!todo()
<!UNREACHABLE_CODE!>!<!>todo()
}
fun testPostfixWithCall(n: Nothing) {
operator fun Nothing.inc(): Nothing = this
<!VAL_REASSIGNMENT!>n<!>++
<!VAL_REASSIGNMENT!>n<!><!UNREACHABLE_CODE!>++<!>
}
fun testPostfixSpecial() {
todo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
todo()<!UNNECESSARY_NOT_NULL_ASSERTION, UNREACHABLE_CODE!>!!<!>
}
fun todo(): Nothing = throw Exception()
@@ -3,36 +3,36 @@ fun bar(a: Any, b: Any) {}
fun test(arr: Array<Int>) {
while (true) {
foo(break)
<!UNREACHABLE_CODE!>foo(<!>break<!UNREACHABLE_CODE!>)<!>
}
while (true) {
bar(arr, break)
<!UNREACHABLE_CODE!>bar(<!>arr, break<!UNREACHABLE_CODE!>)<!>
}
while (true) {
arr[break]
arr<!UNREACHABLE_CODE!>[<!>break<!UNREACHABLE_CODE!>]<!>
}
while (true) {
arr[1] = break
arr<!UNREACHABLE_CODE!>[<!>1<!UNREACHABLE_CODE!>] =<!> break
}
while (true) {
break
foo(1)
<!UNREACHABLE_CODE!>foo(1)<!>
}
while (true) {
var x = 1
var <!UNUSED_VARIABLE!>x<!> = 1
break
x = 2
<!UNREACHABLE_CODE!><!ASSIGNED_VALUE_IS_NEVER_READ!>x<!> = 2<!>
}
while (true) {
var x = 1
x = break
var <!UNUSED_VARIABLE!>x<!> = 1
<!UNREACHABLE_CODE!><!ASSIGNED_VALUE_IS_NEVER_READ!>x<!> =<!> break
}
// TODO: bug, should be fixed in CFA
@@ -50,6 +50,6 @@ fun test(arr: Array<Int>) {
}
while (true) {
break <!USELESS_ELVIS!>?: null<!>
break <!UNREACHABLE_CODE, USELESS_ELVIS!>?: null<!>
}
}
@@ -1,12 +0,0 @@
//KT-3162 More precise try-finally error marking
fun foo(x: String) : String {
val a = try {
x
} finally {
try {
} catch (e: Exception) {
}
return x
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
//KT-3162 More precise try-finally error marking
fun foo(x: String) : String {
@@ -1,25 +0,0 @@
//KT-5200 Mark unreachable code in lambdas
fun test1(): String {
doCall local@ {
throw NullPointerException()
"b3" //unmarked
}
return "OK"
}
fun test2(nonLocal: String, b: Boolean): String {
doCall local@ {
if (b) {
return@local "b1"
} else {
return@local "b2"
}
"b3" //unmarked
}
return nonLocal
}
inline fun doCall(block: ()-> String) = block()
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
//KT-5200 Mark unreachable code in lambdas
fun test1(): String {
@@ -2,10 +2,10 @@
inline fun myRun(b: () -> Unit) = b()
fun foo() {
var a: Int
<!CAN_BE_VAL!>var<!> <!UNUSED_VARIABLE!>a<!>: Int
return
myRun {
<!UNREACHABLE_CODE!>myRun {
return
}
}<!>
}