Control flow graph for safe calls corrected #KT-10913 Fixed

Also #KT-10186 Fixed
Also #KT-5198 Fixed
This commit is contained in:
Mikhail Glukhikh
2016-02-02 16:17:02 +03:00
committed by Mikhail Glukhikh
parent 5ae394fec0
commit a08b8f43b2
15 changed files with 660 additions and 2 deletions
@@ -947,10 +947,19 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
mark(expression)
val selectorExpression = expression.selectorExpression
val receiverExpression = expression.receiverExpression
val safe = expression is KtSafeQualifiedExpression
// todo: replace with selectorExpresion != null after parser is fixed
if (selectorExpression is KtCallExpression || selectorExpression is KtSimpleNameExpression) {
generateInstructions(selectorExpression)
if (!safe) {
generateInstructions(selectorExpression)
}
else {
val resultLabel = builder.createUnboundLabel("result of call")
builder.jumpOnFalse(resultLabel, expression, null)
generateInstructions(selectorExpression)
builder.bindLabel(resultLabel)
}
copyValue(selectorExpression, expression)
}
else {
@@ -0,0 +1,206 @@
== doCall ==
inline fun doCall(f: () -> Unit) = f()
---------------------
L0:
1 <START>
v(f: () -> Unit)
magic[FAKE_INITIALIZER](f: () -> Unit) -> <v0>
w(f|<v0>)
r(f) -> <v1>
mark(f())
call(f(), invoke|<v1>) -> <v2>
ret(*|<v2>) L1
L1:
<END> NEXT:[<SINK>]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
== test1 ==
fun test1(nonLocal: String): String {
val localResult = doCall {
return nonLocal //unreachable
}
return "NON_LOCAL_FAILED $localResult" //unreachable
}
---------------------
L0:
1 <START>
v(nonLocal: String)
magic[FAKE_INITIALIZER](nonLocal: String) -> <v0>
w(nonLocal|<v0>)
2 mark({ val localResult = doCall { return nonLocal //unreachable } return "NON_LOCAL_FAILED $localResult" //unreachable })
v(val localResult = doCall { return nonLocal //unreachable })
mark({ return nonLocal //unreachable })
jmp?(L2) NEXT:[r({ return nonLocal //unreachable }) -> <v1>, d({ return nonLocal //unreachable })]
d({ return nonLocal //unreachable }) NEXT:[<SINK>]
L2 [after local declaration]:
r({ return nonLocal //unreachable }) -> <v1> PREV:[jmp?(L2)]
mark(doCall { return nonLocal //unreachable })
call(doCall { return nonLocal //unreachable }, doCall|<v1>) -> <v2>
w(localResult|<v2>)
mark("NON_LOCAL_FAILED $localResult")
r(localResult) -> <v3>
magic[STRING_TEMPLATE]("NON_LOCAL_FAILED $localResult"|<v3>) -> <v4>
ret(*|<v4>) L1
L1:
1 <END> NEXT:[<SINK>] PREV:[ret(*|<v0>) L1, ret(*|<v4>) L1]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>, d({ return nonLocal //unreachable })]
=====================
== anonymous_0 ==
{
return nonLocal //unreachable
}
---------------------
L3:
3 <START>
4 mark(return nonLocal)
r(nonLocal) -> <v0>
ret(*|<v0>) L1 NEXT:[<END>]
L4:
3 <END> NEXT:[<SINK>] PREV:[]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
== doSomething ==
fun doSomething() {}
---------------------
L0:
1 <START>
2 mark({})
read (Unit)
L1:
1 <END> NEXT:[<SINK>]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
== test2 ==
fun test2() {
fun f(x: Any?) = x
f(null?.let { return })
// false unreachable here
doSomething()
}
---------------------
L0:
1 <START>
2 mark({ fun f(x: Any?) = x f(null?.let { return }) // false unreachable here doSomething() })
jmp?(L2) NEXT:[mark(null?.let { return }), d(fun f(x: Any?) = x)]
d(fun f(x: Any?) = x) NEXT:[<SINK>]
L2 [after local declaration]:
mark(null?.let { return }) PREV:[jmp?(L2)]
jf(L5) NEXT:[mark(f(null?.let { return })), mark({ return })]
mark({ return })
jmp?(L6) NEXT:[r({ return }) -> <v0>, d({ return })]
d({ return }) NEXT:[<SINK>]
L6 [after local declaration]:
r({ return }) -> <v0> PREV:[jmp?(L6)]
r(null) -> <v1>
mark(let { return })
magic[UNRESOLVED_CALL](let { return }|<v0>, !<v2>, <v1>) -> <v3>
L5 [result of call]:
mark(f(null?.let { return })) PREV:[jf(L5), magic[UNRESOLVED_CALL](let { return }|<v0>, !<v2>, <v1>) -> <v3>]
call(f(null?.let { return }), f|<v3>) -> <v4>
mark(doSomething())
call(doSomething(), doSomething) -> <v5>
L1:
1 <END> NEXT:[<SINK>] PREV:[ret L1, call(doSomething(), doSomething) -> <v5>]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>, d(fun f(x: Any?) = x), d({ return })]
=====================
== f ==
fun f(x: Any?) = x
---------------------
L3:
3 <START>
v(x: Any?)
magic[FAKE_INITIALIZER](x: Any?) -> <v0>
w(x|<v0>)
r(x) -> <v1>
ret(*|<v1>) L4
L4:
<END> NEXT:[<SINK>]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
== anonymous_1 ==
{ return }
---------------------
L7:
3 <START>
4 mark(return)
ret L1 NEXT:[<END>]
- 3 ret(*|!<v0>) L8 PREV:[]
L8:
<END> NEXT:[<SINK>] PREV:[]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
== test3 ==
fun test3(x: Any?): Boolean =
x?.let {
return true
} ?: false
---------------------
L0:
1 <START>
v(x: Any?)
magic[FAKE_INITIALIZER](x: Any?) -> <v0>
w(x|<v0>)
mark(x?.let { return true })
jf(L2) NEXT:[mark(x?.let { return true } ?: false), mark({ return true })]
mark({ return true })
jmp?(L3) NEXT:[r({ return true }) -> <v1>, d({ return true })]
d({ return true }) NEXT:[<SINK>]
L3 [after local declaration]:
r({ return true }) -> <v1> PREV:[jmp?(L3)]
r(x) -> <v2>
mark(let { return true })
magic[UNRESOLVED_CALL](let { return true }|<v1>, !<v3>, <v2>) -> <v4>
L2 [result of call]:
mark(x?.let { return true } ?: false) PREV:[jf(L2), magic[UNRESOLVED_CALL](let { return true }|<v1>, !<v3>, <v2>) -> <v4>]
jt(L6|<v4>) NEXT:[r(false) -> <v5>, merge(x?.let { return true } ?: false|<v4>, <v5>) -> <v6>]
r(false) -> <v5>
L6 [after elvis operator]:
merge(x?.let { return true } ?: false|<v4>, <v5>) -> <v6> PREV:[jt(L6|<v4>), r(false) -> <v5>]
ret(*|<v6>) L1
L1:
<END> NEXT:[<SINK>] PREV:[ret(*|<v0>) L1, ret(*|<v6>) L1]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>, d({ return true })]
=====================
== anonymous_2 ==
{
return true
}
---------------------
L4:
2 <START>
3 mark(return true)
r(true) -> <v0>
ret(*|<v0>) L1 NEXT:[<END>]
- 2 ret(*|!<v1>) L5 PREV:[]
L5:
<END> NEXT:[<SINK>] PREV:[]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
+25
View File
@@ -0,0 +1,25 @@
// See also KT-5198 / KT-10186
inline fun doCall(f: () -> Unit) = f()
fun test1(nonLocal: String): String {
val localResult = doCall {
return nonLocal //unreachable
}
return "NON_LOCAL_FAILED $localResult" //unreachable
}
fun doSomething() {}
fun test2() {
fun f(x: Any?) = x
f(null?.let { return })
// false unreachable here
doSomething()
}
fun test3(x: Any?): Boolean =
x?.let {
return true
} ?: false
+90
View File
@@ -0,0 +1,90 @@
== doCall ==
inline fun doCall(f: () -> Unit) = f()
---------------------
<v0>: {<: () -> Unit} NEW: magic[FAKE_INITIALIZER](f: () -> Unit) -> <v0>
f <v1>: {<: () -> Unit} NEW: r(f) -> <v1>
f() <v2>: Unit NEW: call(f(), invoke|<v1>) -> <v2>
=====================
== test1 ==
fun test1(nonLocal: String): String {
val localResult = doCall {
return nonLocal //unreachable
}
return "NON_LOCAL_FAILED $localResult" //unreachable
}
---------------------
<v0>: String NEW: magic[FAKE_INITIALIZER](nonLocal: String) -> <v0>
{ return nonLocal //unreachable } <v1>: {<: () -> Unit} NEW: r({ return nonLocal //unreachable }) -> <v1>
doCall { return nonLocal //unreachable } <v2>: Unit NEW: call(doCall { return nonLocal //unreachable }, doCall|<v1>) -> <v2>
localResult <v3>: * NEW: r(localResult) -> <v3>
"NON_LOCAL_FAILED $localResult" <v4>: String NEW: magic[STRING_TEMPLATE]("NON_LOCAL_FAILED $localResult"|<v3>) -> <v4>
return "NON_LOCAL_FAILED $localResult" !<v5>: *
{ val localResult = doCall { return nonLocal //unreachable } return "NON_LOCAL_FAILED $localResult" //unreachable } !<v5>: * COPY
=====================
== anonymous_0 ==
{
return nonLocal //unreachable
}
---------------------
nonLocal <v0>: String NEW: r(nonLocal) -> <v0>
return nonLocal !<v1>: *
return nonLocal !<v1>: * COPY
=====================
== doSomething ==
fun doSomething() {}
---------------------
=====================
== test2 ==
fun test2() {
fun f(x: Any?) = x
f(null?.let { return })
// false unreachable here
doSomething()
}
---------------------
null <v1>: * NEW: r(null) -> <v1>
let !<v2>: *
{ return } <v0>: * NEW: r({ return }) -> <v0>
let { return } <v3>: * NEW: magic[UNRESOLVED_CALL](let { return }|<v0>, !<v2>, <v1>) -> <v3>
null?.let { return } <v3>: * COPY
f(null?.let { return }) <v4>: * NEW: call(f(null?.let { return }), f|<v3>) -> <v4>
doSomething() <v5>: * NEW: call(doSomething(), doSomething) -> <v5>
{ fun f(x: Any?) = x f(null?.let { return }) // false unreachable here doSomething() } <v5>: * COPY
=====================
== f ==
fun f(x: Any?) = x
---------------------
<v0>: * NEW: magic[FAKE_INITIALIZER](x: Any?) -> <v0>
x <v1>: * NEW: r(x) -> <v1>
=====================
== anonymous_1 ==
{ return }
---------------------
return !<v0>: *
return !<v0>: * COPY
=====================
== test3 ==
fun test3(x: Any?): Boolean =
x?.let {
return true
} ?: false
---------------------
<v0>: * NEW: magic[FAKE_INITIALIZER](x: Any?) -> <v0>
x <v2>: * NEW: r(x) -> <v2>
let !<v3>: *
{ return true } <v1>: * NEW: r({ return true }) -> <v1>
let { return true } <v4>: Boolean NEW: magic[UNRESOLVED_CALL](let { return true }|<v1>, !<v3>, <v2>) -> <v4>
x?.let { return true } <v4>: Boolean COPY
false <v5>: Boolean NEW: r(false) -> <v5>
x?.let { return true } ?: false <v6>: Boolean NEW: merge(x?.let { return true } ?: false|<v4>, <v5>) -> <v6>
=====================
== anonymous_2 ==
{
return true
}
---------------------
true <v0>: Boolean NEW: r(true) -> <v0>
return true !<v1>: *
return true !<v1>: * COPY
=====================
@@ -0,0 +1,160 @@
== fn ==
fun fn() : String? = null
---------------------
L0:
1 <START>
r(null) -> <v0>
ret(*|<v0>) L1
L1:
<END> NEXT:[<SINK>]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
== let ==
inline fun <T, R> T.let(f: (T) -> R): R = f(this)
---------------------
L0:
1 <START>
v(f: (T) -> R)
magic[FAKE_INITIALIZER](f: (T) -> R) -> <v0>
w(f|<v0>)
r(f) -> <v1>
r(this, <this>) -> <v2>
mark(f(this))
call(f(this), invoke|<v1>, <v2>) -> <v3>
ret(*|<v3>) L1
L1:
<END> NEXT:[<SINK>]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
== foo ==
fun foo(): String {
val x = fn()?.let { throw Exception() } ?: "unreachable?"
return x
}
---------------------
L0:
1 <START>
2 mark({ val x = fn()?.let { throw Exception() } ?: "unreachable?" return x })
v(val x = fn()?.let { throw Exception() } ?: "unreachable?")
mark(fn()?.let { throw Exception() })
jf(L2) NEXT:[mark(fn()?.let { throw Exception() } ?: "unreachable?"), mark(fn())]
mark(fn())
call(fn(), fn) -> <v0>
mark({ throw Exception() })
jmp?(L3) NEXT:[r({ throw Exception() }) -> <v1>, d({ throw Exception() })]
d({ throw Exception() }) NEXT:[<SINK>]
L3 [after local declaration]:
r({ throw Exception() }) -> <v1> PREV:[jmp?(L3)]
mark(let { throw Exception() })
call(let { throw Exception() }, let|<v0>, <v1>)
jmp(error) NEXT:[<ERROR>]
L2 [result of call]:
mark(fn()?.let { throw Exception() } ?: "unreachable?") PREV:[jf(L2)]
jt(L6|!<v2>) NEXT:[mark("unreachable?"), merge(fn()?.let { throw Exception() } ?: "unreachable?"|!<v2>, <v3>) -> <v4>]
mark("unreachable?")
r("unreachable?") -> <v3>
L6 [after elvis operator]:
merge(fn()?.let { throw Exception() } ?: "unreachable?"|!<v2>, <v3>) -> <v4> PREV:[jt(L6|!<v2>), r("unreachable?") -> <v3>]
w(x|<v4>)
r(x) -> <v5>
ret(*|<v5>) L1
L1:
1 <END> NEXT:[<SINK>]
error:
<ERROR> PREV:[jmp(error)]
sink:
<SINK> PREV:[<ERROR>, <END>, d({ throw Exception() })]
=====================
== anonymous_0 ==
{ throw Exception() }
---------------------
L4:
3 <START>
4 mark(throw Exception())
mark(throw Exception())
mark(Exception())
call(Exception(), <init>) -> <v0>
throw (throw Exception()|<v0>) NEXT:[<ERROR>]
- 3 ret(*|!<v1>) L5 PREV:[]
L5:
<END> NEXT:[<SINK>] PREV:[]
error:
<ERROR> PREV:[throw (throw Exception()|<v0>)]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
== bar ==
fun bar(): String {
val x = fn() ?: return ""
val y = x?.let { throw Exception() } ?: "unreachable"
return y
}
---------------------
L0:
1 <START>
2 mark({ val x = fn() ?: return "" val y = x?.let { throw Exception() } ?: "unreachable" return y })
v(val x = fn() ?: return "")
mark(fn())
call(fn(), fn) -> <v0>
mark(fn() ?: return "")
jt(L2|<v0>) NEXT:[mark(""), merge(fn() ?: return ""|<v0>, !<v2>) -> <v3>]
mark("")
r("") -> <v1>
ret(*|<v1>) L1 NEXT:[<END>]
L2 [after elvis operator]:
merge(fn() ?: return ""|<v0>, !<v2>) -> <v3> PREV:[jt(L2|<v0>)]
w(x|<v3>)
v(val y = x?.let { throw Exception() } ?: "unreachable")
mark(x?.let { throw Exception() })
jf(L3) NEXT:[jmp(error), r(x) -> <v4>]
r(x) -> <v4>
mark({ throw Exception() })
jmp?(L4) NEXT:[r({ throw Exception() }) -> <v5>, d({ throw Exception() })]
d({ throw Exception() }) NEXT:[<SINK>]
L4 [after local declaration]:
r({ throw Exception() }) -> <v5> PREV:[jmp?(L4)]
mark(let { throw Exception() })
call(let { throw Exception() }, let|<v4>, <v5>)
jmp(error) NEXT:[<ERROR>]
L3 [result of call]:
jmp(error) NEXT:[<ERROR>] PREV:[jf(L3)]
- mark(x?.let { throw Exception() } ?: "unreachable") PREV:[]
- jt(L7|!<v6>) NEXT:[mark("unreachable"), merge(x?.let { throw Exception() } ?: "unreachable"|!<v6>, <v7>) -> <v8>] PREV:[]
- mark("unreachable") PREV:[]
- r("unreachable") -> <v7> PREV:[]
L7 [after elvis operator]:
- merge(x?.let { throw Exception() } ?: "unreachable"|!<v6>, <v7>) -> <v8> PREV:[]
- w(y|<v8>) PREV:[]
- r(y) -> <v9> PREV:[]
- ret(*|<v9>) L1 PREV:[]
L1:
1 <END> NEXT:[<SINK>] PREV:[ret(*|<v1>) L1]
error:
<ERROR> PREV:[jmp(error), jmp(error)]
sink:
<SINK> PREV:[<ERROR>, <END>, d({ throw Exception() })]
=====================
== anonymous_1 ==
{ throw Exception() }
---------------------
L5:
3 <START>
4 mark(throw Exception())
mark(throw Exception())
mark(Exception())
call(Exception(), <init>) -> <v0>
throw (throw Exception()|<v0>) NEXT:[<ERROR>]
- 3 ret(*|!<v1>) L6 PREV:[]
L6:
<END> NEXT:[<SINK>] PREV:[]
error:
<ERROR> PREV:[throw (throw Exception()|<v0>)]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
+16
View File
@@ -0,0 +1,16 @@
// See KT-10913 Bogus unreachable code warning
fun fn() : String? = null
inline fun <T, R> T.let(f: (T) -> R): R = f(this)
fun foo(): String {
val x = fn()?.let { throw Exception() } ?: "unreachable?"
return x
}
fun bar(): String {
val x = fn() ?: return ""
val y = x?.let { throw Exception() } ?: "unreachable"
return y
}
+65
View File
@@ -0,0 +1,65 @@
== fn ==
fun fn() : String? = null
---------------------
null <v0>: {<: String?} NEW: r(null) -> <v0>
=====================
== let ==
inline fun <T, R> T.let(f: (T) -> R): R = f(this)
---------------------
<v0>: {<: (T) -> R} NEW: magic[FAKE_INITIALIZER](f: (T) -> R) -> <v0>
f <v1>: {<: (T) -> R} NEW: r(f) -> <v1>
this <v2>: {<: T} COPY
this <v2>: {<: T} NEW: r(this, <this>) -> <v2>
f(this) <v3>: {<: R} NEW: call(f(this), invoke|<v1>, <v2>) -> <v3>
=====================
== foo ==
fun foo(): String {
val x = fn()?.let { throw Exception() } ?: "unreachable?"
return x
}
---------------------
fn() <v0>: String NEW: call(fn(), fn) -> <v0>
{ throw Exception() } <v1>: {<: (String) -> Nothing} NEW: r({ throw Exception() }) -> <v1>
let { throw Exception() } !<v2>: *
fn()?.let { throw Exception() } !<v2>: * COPY
"unreachable?" <v3>: String NEW: r("unreachable?") -> <v3>
fn()?.let { throw Exception() } ?: "unreachable?" <v4>: String NEW: merge(fn()?.let { throw Exception() } ?: "unreachable?"|!<v2>, <v3>) -> <v4>
x <v5>: String NEW: r(x) -> <v5>
return x !<v6>: *
{ val x = fn()?.let { throw Exception() } ?: "unreachable?" return x } !<v6>: * COPY
=====================
== anonymous_0 ==
{ throw Exception() }
---------------------
Exception() <v0>: {<: Throwable} NEW: call(Exception(), <init>) -> <v0>
throw Exception() !<v1>: *
throw Exception() !<v1>: * COPY
=====================
== bar ==
fun bar(): String {
val x = fn() ?: return ""
val y = x?.let { throw Exception() } ?: "unreachable"
return y
}
---------------------
fn() <v0>: AND{Boolean, String} NEW: call(fn(), fn) -> <v0>
"" <v1>: String NEW: r("") -> <v1>
return "" !<v2>: *
fn() ?: return "" <v3>: String NEW: merge(fn() ?: return ""|<v0>, !<v2>) -> <v3>
x <v4>: String NEW: r(x) -> <v4>
{ throw Exception() } <v5>: {<: (String) -> Nothing} NEW: r({ throw Exception() }) -> <v5>
let { throw Exception() } !<v6>: *
x?.let { throw Exception() } !<v6>: * COPY
"unreachable" <v7>: String NEW: r("unreachable") -> <v7>
x?.let { throw Exception() } ?: "unreachable" <v8>: String NEW: merge(x?.let { throw Exception() } ?: "unreachable"|!<v6>, <v7>) -> <v8>
y <v9>: String NEW: r(y) -> <v9>
return y !<v10>: *
{ val x = fn() ?: return "" val y = x?.let { throw Exception() } ?: "unreachable" return y } !<v10>: * COPY
=====================
== anonymous_1 ==
{ throw Exception() }
---------------------
Exception() <v0>: {<: Throwable} NEW: call(Exception(), <init>) -> <v0>
throw Exception() !<v1>: *
throw Exception() !<v1>: * COPY
=====================
@@ -10,10 +10,12 @@ L0:
w(s|<v0>)
2 mark({ s?.first })
mark(s?.first)
jf(L2) NEXT:[<END>, r(s) -> <v1>]
r(s) -> <v1>
r(first|<v1>) -> <v2>
L1:
1 <END> NEXT:[<SINK>]
L2 [result of call]:
1 <END> NEXT:[<SINK>] PREV:[jf(L2), r(first|<v1>) -> <v2>]
error:
<ERROR> PREV:[]
sink:
@@ -0,0 +1,25 @@
// See also KT-5198 / KT-10186
inline fun doCall(f: () -> Unit) = f()
fun test1(nonLocal: String): String {
val localResult = doCall {
return nonLocal //unreachable
}
return "NON_LOCAL_FAILED $localResult" //unreachable
}
fun doSomething() {}
fun test2() {
fun f(x: Any?) = x
f(null?.let { return })
// false unreachable here
doSomething()
}
fun test3(x: Any?): Boolean =
x?.let {
return true
} ?: false
@@ -0,0 +1,7 @@
package
public inline fun doCall(/*0*/ f: () -> kotlin.Unit): kotlin.Unit
public fun doSomething(): kotlin.Unit
public fun test1(/*0*/ nonLocal: kotlin.String): kotlin.String
public fun test2(): kotlin.Unit
public fun test3(/*0*/ x: kotlin.Any?): kotlin.Boolean
@@ -0,0 +1,12 @@
// See KT-10913 Bogus unreachable code warning
fun fn() : String? = null
fun foo(): String {
val x = fn()?.let { throw Exception() } ?: "unreachable?"
return x
}
fun bar(): String {
val x = fn() ?: return ""
<!UNREACHABLE_CODE!>val <!UNUSED_VARIABLE!>y<!> =<!> x<!UNNECESSARY_SAFE_CALL!>?.<!>let { throw Exception() } <!USELESS_ELVIS, UNREACHABLE_CODE!>?: "unreachable"<!>
<!UNREACHABLE_CODE!>return y<!>
}
@@ -0,0 +1,5 @@
package
public fun bar(): kotlin.String
public fun fn(): kotlin.String?
public fun foo(): kotlin.String
@@ -322,6 +322,12 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
doTest(fileName);
}
@TestMetadata("notLocalReturn.kt")
public void testNotLocalReturn() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/deadCode/notLocalReturn.kt");
doTest(fileName);
}
@TestMetadata("returnInElvis.kt")
public void testReturnInElvis() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/deadCode/returnInElvis.kt");
@@ -333,6 +339,12 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/deadCode/stringTemplate.kt");
doTest(fileName);
}
@TestMetadata("throwInLambda.kt")
public void testThrowInLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/deadCode/throwInLambda.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/cfg/declarations")
@@ -324,6 +324,12 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest {
doTest(fileName);
}
@TestMetadata("notLocalReturn.kt")
public void testNotLocalReturn() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/deadCode/notLocalReturn.kt");
doTest(fileName);
}
@TestMetadata("returnInElvis.kt")
public void testReturnInElvis() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/deadCode/returnInElvis.kt");
@@ -335,6 +341,12 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/deadCode/stringTemplate.kt");
doTest(fileName);
}
@TestMetadata("throwInLambda.kt")
public void testThrowInLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/deadCode/throwInLambda.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/cfg/declarations")
@@ -3069,6 +3069,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("nonLocalReturnUnreachable.kt")
public void testNonLocalReturnUnreachable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/nonLocalReturnUnreachable.kt");
doTest(fileName);
}
@TestMetadata("propertiesInitWithOtherInstance.kt")
public void testPropertiesInitWithOtherInstance() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/propertiesInitWithOtherInstance.kt");
@@ -3111,6 +3117,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("throwInLambda.kt")
public void testThrowInLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/throwInLambda.kt");
doTest(fileName);
}
@TestMetadata("uninitializedInLocalDeclarations.kt")
public void testUninitializedInLocalDeclarations() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedInLocalDeclarations.kt");