JVM IR: adjust generation of linenumber for try-finally

Do not generate linenumber for the start of the finally block, because
that is usually where the only word 'finally' is located. Instead,
generate linenumber for the first expression inside the finally block.

Not generating this linenumber fixes an issue in code coverage tools
which would consider such finally uncovered. Although this might be
technically considered as designed, it makes more sense to NOT detect it
as uncovered because semantics of the finally block shouldn't really
differ whether it's executed normally or because an exception happened.
It's also beneficial for the tool support to behave like javac, which
doesn't generate the linenumber either.

 #KT-50973 Fixed
This commit is contained in:
Alexander Udalov
2022-02-03 02:34:50 +01:00
parent 838743bf07
commit c53d91bae1
9 changed files with 34 additions and 8 deletions
@@ -4526,6 +4526,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/lineNumbers/tryCatch.kt");
}
@Test
@TestMetadata("tryFinally.kt")
public void testTryFinally() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/lineNumbers/tryFinally.kt");
}
@Test
@TestMetadata("when.kt")
public void testWhen() throws Exception {
@@ -1204,10 +1204,9 @@ class ExpressionCodegen(
// Generate `try { ... } catch (e: Any?) { <finally>; throw e }` around every part of
// the try-catch that is not a copy-pasted `finally` block.
val defaultCatchStart = markNewLabel()
// Make sure the ASTORE generated below has the line number of the
// finally block and does not take over the line number of whatever
// was generated before.
tryInfo.onExit.markLineNumber(true)
// Make sure the ASTORE generated below has the line number of the first expression of the finally block
// and does not take over the line number of whatever was generated before.
tryInfo.onExit.firstChild().markLineNumber(true)
// While keeping this value on the stack should be enough, the bytecode validator will
// complain if a catch block does not start with ASTORE.
val savedException = frameMap.enterTemp(AsmTypes.JAVA_THROWABLE_TYPE)
@@ -1245,6 +1244,9 @@ class ExpressionCodegen(
}
}
private fun IrExpression.firstChild(): IrElement =
if (this is IrContainerExpression) statements.firstOrNull() ?: this else this
private fun genTryCatchCover(catchStart: Label, tryStart: Label, tryEnd: Label, tryGaps: List<Pair<Label, Label>>, type: String?) {
val lastRegionStart = tryGaps.fold(tryStart) { regionStart, (gapStart, gapEnd) ->
mv.visitTryCatchBlock(regionStart, gapStart, catchStart, type)
@@ -0,0 +1,10 @@
fun foo() {
try {
System.out.println("A")
} finally {
System.out.println("B")
}
}
// 0 LINENUMBER 4
// 2 LINENUMBER 5
@@ -34,5 +34,4 @@ fun box(): String {
// test.kt:14 box: i:int=0:int, e:java.lang.Exception=java.lang.RuntimeException, y:java.lang.String="y":java.lang.String
// test.kt:15 box: i:int=0:int, e:java.lang.Exception=java.lang.RuntimeException, y:java.lang.String="y":java.lang.String, z:java.lang.String="z":java.lang.String
// test.kt:17 box: i:int=0:int
// test.kt:20 box:
// test.kt:21 box:
@@ -34,5 +34,4 @@ fun box(): String {
// test.kt:14 box: i:int=0:int, e:java.lang.Exception=java.lang.RuntimeException, y:java.lang.String="y":java.lang.String
// test.kt:15 box: i:int=0:int, e:java.lang.Exception=java.lang.RuntimeException, y:java.lang.String="y":java.lang.String, z:java.lang.String="z":java.lang.String
// test.kt:17 box: i:int=0:int
// test.kt:20 box:
// test.kt:21 box:
@@ -18,5 +18,4 @@ fun box(): String {
// test.kt:8 box:
// test.kt:9 box:
// test.kt:10 box: x:java.lang.String="x":java.lang.String
// test.kt:11 box:
// test.kt:12 box:
-1
View File
@@ -73,5 +73,4 @@ fun box() {
// test.kt:14 foo
// test.kt:10 foo
// EXPECTATIONS JVM_IR
// test.kt:12 foo
// test.kt:13 foo
@@ -4256,6 +4256,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/lineNumbers/tryCatch.kt");
}
@Test
@TestMetadata("tryFinally.kt")
public void testTryFinally() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/lineNumbers/tryFinally.kt");
}
@Test
@TestMetadata("when.kt")
public void testWhen() throws Exception {
@@ -4526,6 +4526,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/lineNumbers/tryCatch.kt");
}
@Test
@TestMetadata("tryFinally.kt")
public void testTryFinally() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/lineNumbers/tryFinally.kt");
}
@Test
@TestMetadata("when.kt")
public void testWhen() throws Exception {