From c53d91bae17ab011da96f1d56441924d2fe1e56c Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 3 Feb 2022 02:34:50 +0100 Subject: [PATCH] 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 --- .../runners/codegen/FirBytecodeTextTestGenerated.java | 6 ++++++ .../kotlin/backend/jvm/codegen/ExpressionCodegen.kt | 10 ++++++---- .../codegen/bytecodeText/lineNumbers/tryFinally.kt | 10 ++++++++++ compiler/testData/debug/localVariables/tryFinally11.kt | 1 - compiler/testData/debug/localVariables/tryFinally12.kt | 1 - compiler/testData/debug/localVariables/tryFinally17.kt | 1 - compiler/testData/debug/stepping/tryFinally.kt | 1 - .../runners/codegen/BytecodeTextTestGenerated.java | 6 ++++++ .../runners/codegen/IrBytecodeTextTestGenerated.java | 6 ++++++ 9 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/codegen/bytecodeText/lineNumbers/tryFinally.kt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java index 2fc1f051761..cbf5d4082db 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java @@ -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 { diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index e896e064a91..d60edb12e56 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -1204,10 +1204,9 @@ class ExpressionCodegen( // Generate `try { ... } catch (e: Any?) { ; 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>, type: String?) { val lastRegionStart = tryGaps.fold(tryStart) { regionStart, (gapStart, gapEnd) -> mv.visitTryCatchBlock(regionStart, gapStart, catchStart, type) diff --git a/compiler/testData/codegen/bytecodeText/lineNumbers/tryFinally.kt b/compiler/testData/codegen/bytecodeText/lineNumbers/tryFinally.kt new file mode 100644 index 00000000000..a0c5cae2a18 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/lineNumbers/tryFinally.kt @@ -0,0 +1,10 @@ +fun foo() { + try { + System.out.println("A") + } finally { + System.out.println("B") + } +} + +// 0 LINENUMBER 4 +// 2 LINENUMBER 5 diff --git a/compiler/testData/debug/localVariables/tryFinally11.kt b/compiler/testData/debug/localVariables/tryFinally11.kt index ecee1fd58bb..fee1d3b019c 100644 --- a/compiler/testData/debug/localVariables/tryFinally11.kt +++ b/compiler/testData/debug/localVariables/tryFinally11.kt @@ -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: diff --git a/compiler/testData/debug/localVariables/tryFinally12.kt b/compiler/testData/debug/localVariables/tryFinally12.kt index 5d6bdccc482..98713465fa5 100644 --- a/compiler/testData/debug/localVariables/tryFinally12.kt +++ b/compiler/testData/debug/localVariables/tryFinally12.kt @@ -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: diff --git a/compiler/testData/debug/localVariables/tryFinally17.kt b/compiler/testData/debug/localVariables/tryFinally17.kt index b1e934ab58c..fd85fb0d97e 100644 --- a/compiler/testData/debug/localVariables/tryFinally17.kt +++ b/compiler/testData/debug/localVariables/tryFinally17.kt @@ -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: diff --git a/compiler/testData/debug/stepping/tryFinally.kt b/compiler/testData/debug/stepping/tryFinally.kt index 0a5b5a00e56..d1a502764d8 100644 --- a/compiler/testData/debug/stepping/tryFinally.kt +++ b/compiler/testData/debug/stepping/tryFinally.kt @@ -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 diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java index 0fadcc37e47..c11413f111a 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java @@ -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 { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java index 9cf47372f2c..04f602c506a 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java @@ -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 {