From 43b61a618d47d1c25c1b4f6ca66495ac02f62254 Mon Sep 17 00:00:00 2001 From: Kristoffer Andersen Date: Wed, 9 Dec 2020 17:15:46 +0100 Subject: [PATCH] [IR+Tests] Improve Local Function Debugging Experience This change improves the debugging experience around local functions on the IR backend. The changes include moving old checkLocalVariablesTable (cLVT) tests to the new stepping/local variable infrastructure in order to refine the tests and further define the behavior of the two JVM backends, and their differences. The primary ported test case is cLVT/localFun.kt that documents the discrepancy in implementation strategy for local functions on the two backends. The old backend implements local functions as lambdas assigned to a local variable while the IR backend lifts them out as static funtions on the surrounding class. The discrepancies and their consequences are documented in bytecodeListing, idea-stepping, localVariableTable and debugStepping tests. The only _code change_ is disabling the captured variable name mangling for captured variables on the IR backend. Captured variables are passed as arguments to the static function, so in the debugger, they really just are local variables. For them to show properly in the debugger and be detectable by evaluate expression, they simply need no mangling. Finally, this change cleans 3 redundant cLVT tests, copyFunction.kt and destructuringInlineLambda.kt and destructuringInFor.kt, that are all covered in the new suite. The stepping behavior needs to be made precise around for loops, but that is an entirely seperate issue. --- .../common/lower/LocalDeclarationsLowering.kt | 27 ++++++---- .../checkLocalVariablesTable/copyFunction.kt | 6 --- .../destructuringInFor.kt | 14 ------ .../destructuringInlineLambda.kt | 22 -------- .../checkLocalVariablesTable/localFun.kt | 18 ------- .../codegen/bytecodeListing/localFunction.kt | 5 ++ .../codegen/bytecodeListing/localFunction.txt | 18 +++++++ .../bytecodeListing/localFunction_ir.txt | 6 +++ .../localVariables/destructuringInFor.kt | 21 ++++---- .../testData/debug/localVariables/emptyFun.kt | 13 +++++ .../testData/debug/localVariables/localFun.kt | 50 ++++++++++++++++--- .../debug/localVariables/localFunUnused.kt | 31 ++++++++++++ .../localFunctionWIthOnelineExpressionBody.kt | 25 ++++++++++ .../codegen/BytecodeListingTestGenerated.java | 5 ++ ...CheckLocalVariablesTableTestGenerated.java | 20 -------- .../IrLocalVariableTestGenerated.java | 12 +++++ .../IrSteppingTestGenerated.java | 6 +++ .../LocalVariableTestGenerated.java | 12 +++++ .../SteppingTestGenerated.java | 6 +++ .../ir/IrBytecodeListingTestGenerated.java | 5 ++ ...CheckLocalVariablesTableTestGenerated.java | 20 -------- ...KotlinEvaluateExpressionTestGenerated.java | 5 ++ .../test/IrKotlinSteppingTestGenerated.java | 10 ++++ ...KotlinEvaluateExpressionTestGenerated.java | 5 ++ .../test/KotlinSteppingTestGenerated.java | 10 ++++ .../localFunctionCapturedLocalVariable.kt | 13 +++++ .../localFunctionCapturedLocalVariable.out | 8 +++ .../stepping/stepOver/localFunction.ir.out | 6 +++ .../stepping/stepOver/localFunction.kt | 12 +++++ .../stepping/stepOver/localFunction.out | 8 +++ ...unctionWithSingleLineExpressionBody.ir.out | 9 ++++ ...calFunctionWithSingleLineExpressionBody.kt | 13 +++++ ...alFunctionWithSingleLineExpressionBody.out | 10 ++++ 33 files changed, 324 insertions(+), 127 deletions(-) delete mode 100644 compiler/testData/checkLocalVariablesTable/copyFunction.kt delete mode 100644 compiler/testData/checkLocalVariablesTable/destructuringInFor.kt delete mode 100644 compiler/testData/checkLocalVariablesTable/destructuringInlineLambda.kt delete mode 100644 compiler/testData/checkLocalVariablesTable/localFun.kt create mode 100644 compiler/testData/codegen/bytecodeListing/localFunction.kt create mode 100644 compiler/testData/codegen/bytecodeListing/localFunction.txt create mode 100644 compiler/testData/codegen/bytecodeListing/localFunction_ir.txt create mode 100644 compiler/testData/debug/localVariables/emptyFun.kt create mode 100644 compiler/testData/debug/localVariables/localFunUnused.kt create mode 100644 compiler/testData/debug/stepping/localFunctionWIthOnelineExpressionBody.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionCapturedLocalVariable.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionCapturedLocalVariable.out create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.ir.out create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.out create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.ir.out create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.out diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt index aa4ad74b6a0..df578217bcc 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.backend.common.CommonBackendContext -import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName import org.jetbrains.kotlin.backend.common.descriptors.synthesizedString import org.jetbrains.kotlin.backend.common.ir.* import org.jetbrains.kotlin.backend.common.runOnFilePostfix @@ -633,7 +632,7 @@ class LocalDeclarationsLowering( newDeclaration.copyAttributes(oldDeclaration) newDeclaration.valueParameters += createTransformedValueParameters( - capturedValues, localFunctionContext, oldDeclaration, newDeclaration + capturedValues, localFunctionContext, oldDeclaration, newDeclaration, isExplicitLocalFunction = oldDeclaration.origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA ) newDeclaration.recordTransformedValueParameters(localFunctionContext) @@ -646,7 +645,8 @@ class LocalDeclarationsLowering( capturedValues: List, localFunctionContext: LocalContext, oldDeclaration: IrFunction, - newDeclaration: IrFunction + newDeclaration: IrFunction, + isExplicitLocalFunction: Boolean = false ) = ArrayList(capturedValues.size + oldDeclaration.valueParameters.size).apply { val generatedNames = mutableSetOf() capturedValues.mapIndexedTo(this) { i, capturedValue -> @@ -657,7 +657,7 @@ class LocalDeclarationsLowering( origin = if (p is IrValueParameter && p.index < 0 && newDeclaration is IrConstructor) BOUND_RECEIVER_PARAMETER else BOUND_VALUE_PARAMETER - name = suggestNameForCapturedValue(p, generatedNames) + name = suggestNameForCapturedValue(p, generatedNames, isExplicitLocalFunction = isExplicitLocalFunction) index = i type = localFunctionContext.remapType(p.type) isCrossInline = (capturedValue as? IrValueParameterSymbol)?.owner?.isCrossinline == true @@ -786,7 +786,7 @@ class LocalDeclarationsLowering( private fun Name.stripSpecialMarkers(): String = if (isSpecial) asString().substring(1, asString().length - 1) else asString() - private fun suggestNameForCapturedValue(declaration: IrValueDeclaration, usedNames: MutableSet): Name { + private fun suggestNameForCapturedValue(declaration: IrValueDeclaration, usedNames: MutableSet, isExplicitLocalFunction: Boolean = false): Name { if (declaration is IrValueParameter) { if (declaration.name.asString() == "" && declaration.isDispatchReceiver()) { return findFirstUnusedName("this\$0", usedNames) { @@ -804,12 +804,21 @@ class LocalDeclarationsLowering( } } } - val base = if (declaration.name.isSpecial) + + val base = if (declaration.name.isSpecial) { declaration.name.stripSpecialMarkers() - else + } else { declaration.name.asString() - return findFirstUnusedName(base.synthesizedString, usedNames) { - "$base$$it".synthesizedString + } + + return if (isExplicitLocalFunction && declaration is IrVariable) { + findFirstUnusedName(base, usedNames) { + "$base$$it" + } + } else { + findFirstUnusedName(base.synthesizedString, usedNames) { + "$base$$it".synthesizedString + } } } diff --git a/compiler/testData/checkLocalVariablesTable/copyFunction.kt b/compiler/testData/checkLocalVariablesTable/copyFunction.kt deleted file mode 100644 index 667a6cafbbf..00000000000 --- a/compiler/testData/checkLocalVariablesTable/copyFunction.kt +++ /dev/null @@ -1,6 +0,0 @@ -data class someClass(val a: Double, val b: Double) - -// METHOD : someClass.copy(DD)LsomeClass; -// VARIABLE : NAME=this TYPE=LsomeClass; INDEX=0 -// VARIABLE : NAME=a TYPE=D INDEX=1 -// VARIABLE : NAME=b TYPE=D INDEX=3 \ No newline at end of file diff --git a/compiler/testData/checkLocalVariablesTable/destructuringInFor.kt b/compiler/testData/checkLocalVariablesTable/destructuringInFor.kt deleted file mode 100644 index c68ccef4d3f..00000000000 --- a/compiler/testData/checkLocalVariablesTable/destructuringInFor.kt +++ /dev/null @@ -1,14 +0,0 @@ -// WITH_RUNTIME - -fun box() { - val map: Map = mapOf() - for ((a, b) in map) { - a + b - } -} - -// METHOD : DestructuringInForKt.box()V - -// VARIABLE : NAME=b TYPE=Ljava/lang/String; INDEX=4 -// VARIABLE : NAME=a TYPE=Ljava/lang/String; INDEX=3 -// VARIABLE : NAME=map TYPE=Ljava/util/Map; INDEX=0 \ No newline at end of file diff --git a/compiler/testData/checkLocalVariablesTable/destructuringInlineLambda.kt b/compiler/testData/checkLocalVariablesTable/destructuringInlineLambda.kt deleted file mode 100644 index 2026e03abc0..00000000000 --- a/compiler/testData/checkLocalVariablesTable/destructuringInlineLambda.kt +++ /dev/null @@ -1,22 +0,0 @@ -inline fun foo(x: (Int, Station) -> Unit) { - x(1, Station(null, "", 1)) -} - -data class Station( - val id: String?, - val name: String, - val distance: Int) - -fun box(): String { - foo { i, (a1, a2, a3) -> i + a3 } - return "OK" -} - -// METHOD : DestructuringInlineLambdaKt.box()Ljava/lang/String; -// VARIABLE : NAME=a1 TYPE=Ljava/lang/String; INDEX=4 -// VARIABLE : NAME=a2 TYPE=Ljava/lang/String; INDEX=5 -// VARIABLE : NAME=a3 TYPE=I INDEX=6 -// VARIABLE : NAME=i TYPE=I INDEX=2 -// VARIABLE : NAME=$dstr$a1$a2$a3 TYPE=LStation; INDEX=1 -// VARIABLE : NAME=$i$a$-foo-DestructuringInlineLambdaKt$box$1 TYPE=I INDEX=3 -// VARIABLE : NAME=$i$f$foo TYPE=I INDEX=0 diff --git a/compiler/testData/checkLocalVariablesTable/localFun.kt b/compiler/testData/checkLocalVariablesTable/localFun.kt deleted file mode 100644 index b69677cfe1e..00000000000 --- a/compiler/testData/checkLocalVariablesTable/localFun.kt +++ /dev/null @@ -1,18 +0,0 @@ -fun foo() { - val x = 1 - fun bar() { - val y = x - } -} - -// Local function bodies are in a separate class (implementing FunctionN) for non-IR, and are static methods in the enclosing class for IR. - -// JVM_TEMPLATES -// METHOD : LocalFunKt$foo$1.invoke()V -// VARIABLE : NAME=y TYPE=I INDEX=1 -// VARIABLE : NAME=this TYPE=LLocalFunKt$foo$1; INDEX=0 - -// JVM_IR_TEMPLATES -// METHOD : LocalFunKt.foo$bar(I)V -// VARIABLE : NAME=y TYPE=I INDEX=1 -// VARIABLE : NAME=$x TYPE=I INDEX=0 diff --git a/compiler/testData/codegen/bytecodeListing/localFunction.kt b/compiler/testData/codegen/bytecodeListing/localFunction.kt new file mode 100644 index 00000000000..1be855eee20 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/localFunction.kt @@ -0,0 +1,5 @@ +fun foo() { + fun bar() { + + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/localFunction.txt b/compiler/testData/codegen/bytecodeListing/localFunction.txt new file mode 100644 index 00000000000..a071f7b3a38 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/localFunction.txt @@ -0,0 +1,18 @@ +@kotlin.Metadata +final class LocalFunctionKt$foo$1 { + // source: 'localFunction.kt' + enclosing method LocalFunctionKt.foo()V + public final static field INSTANCE: LocalFunctionKt$foo$1 + inner (anonymous) class LocalFunctionKt$foo$1 + static method (): void + method (): void + public synthetic bridge method invoke(): java.lang.Object + public final method invoke(): void +} + +@kotlin.Metadata +public final class LocalFunctionKt { + // source: 'localFunction.kt' + inner (anonymous) class LocalFunctionKt$foo$1 + public final static method foo(): void +} diff --git a/compiler/testData/codegen/bytecodeListing/localFunction_ir.txt b/compiler/testData/codegen/bytecodeListing/localFunction_ir.txt new file mode 100644 index 00000000000..0cc950fc7a1 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/localFunction_ir.txt @@ -0,0 +1,6 @@ +@kotlin.Metadata +public final class LocalFunctionKt { + // source: 'localFunction.kt' + private final static method foo$bar(): void + public final static method foo(): void +} diff --git a/compiler/testData/debug/localVariables/destructuringInFor.kt b/compiler/testData/debug/localVariables/destructuringInFor.kt index 4d690efa9b4..82e63627456 100644 --- a/compiler/testData/debug/localVariables/destructuringInFor.kt +++ b/compiler/testData/debug/localVariables/destructuringInFor.kt @@ -1,19 +1,16 @@ + + //FILE: test.kt - -// WITH_RUNTIME - fun box() { val map: Map = mapOf("1" to "23") - for ((a, b) - in map) { + for ((a, b) in map) { a + b } } -// IGNORE_BACKEND: JVM_IR + // LOCAL VARIABLES -// test.kt:6 box: -// test.kt:8 box: map:java.util.Map=java.util.Collections$SingletonMap -// test.kt:7 box: map:java.util.Map=java.util.Collections$SingletonMap -// test.kt:9 box: map:java.util.Map=java.util.Collections$SingletonMap, a:java.lang.String="1":java.lang.String, b:java.lang.String="23":java.lang.String -// test.kt:7 box: map:java.util.Map=java.util.Collections$SingletonMap -// test.kt:11 box: map:java.util.Map=java.util.Collections$SingletonMap \ No newline at end of file +// test.kt:5 box: +// test.kt:6 box: map:java.util.Map=java.util.Collections$SingletonMap +// test.kt:7 box: map:java.util.Map=java.util.Collections$SingletonMap, a:java.lang.String="1":java.lang.String, b:java.lang.String="23":java.lang.String +// test.kt:6 box: map:java.util.Map=java.util.Collections$SingletonMap +// test.kt:9 box: map:java.util.Map=java.util.Collections$SingletonMap \ No newline at end of file diff --git a/compiler/testData/debug/localVariables/emptyFun.kt b/compiler/testData/debug/localVariables/emptyFun.kt new file mode 100644 index 00000000000..96113cacffa --- /dev/null +++ b/compiler/testData/debug/localVariables/emptyFun.kt @@ -0,0 +1,13 @@ + + +// FILE: test.kt +fun foo() {} + +fun box() { + foo() +} + +// LOCAL VARIABLES +// test.kt:7 box: +// test.kt:4 foo: +// test.kt:8 box: \ No newline at end of file diff --git a/compiler/testData/debug/localVariables/localFun.kt b/compiler/testData/debug/localVariables/localFun.kt index c925105848f..12816a47206 100644 --- a/compiler/testData/debug/localVariables/localFun.kt +++ b/compiler/testData/debug/localVariables/localFun.kt @@ -1,16 +1,54 @@ -//FILE: test.kt + +//FILE: test.kt fun foo() { + val x = 1 fun bar() { + val y = x } + bar() } fun box() { foo() } -// IGNORE_BACKEND: JVM_IR + +// Local functions are compiled to private static functions on the class +// containing the local funtion. This has a number of consequences observable +// from a debugging perspective, for this test specifically: +// - local functions do not figure in the LVT of the outer function, as they +// are not instantiated. +// - the _declaration_ of the local function does not figure in the byte code +// of the outer function and hence, has no line number +// - captures are treated differently, according to the implementation +// strategy: on the IR, captures are passed as arguments to the static +// function, on the old backend, they are added to fields on the lambda +// object. Hence, for debugging purposes, captures are "just" +// variables local to the function, and hence need no name mangling to +// properly figure in the debugger. + // LOCAL VARIABLES -// test.kt:9 box: -// test.kt:4 foo: -// test.kt:6 foo: $fun$bar$1:TestKt$foo$1=TestKt$foo$1 -// test.kt:10 box: \ No newline at end of file +// test.kt:13 box: +// test.kt:5 foo: + +// LOCAL VARIABLES JVM +// test.kt:6 foo: x:int=1:int + +// LOCAL VARIABLES JVM +// test.kt:9 foo: x:int=1:int, $fun$bar$1:TestKt$foo$1=TestKt$foo$1 +// LOCAL VARIABLES JVM_IR +// test.kt:9 foo: x:int=1:int + +// LOCAL VARIABLES JVM +// test.kt:7 invoke: +// test.kt:8 invoke: y:int=1:int +// LOCAL VARIABLES JVM_IR +// test.kt:7 foo$bar: x:int=1:int +// test.kt:8 foo$bar: x:int=1:int, y:int=1:int + +// LOCAL VARIABLES JVM +// test.kt:10 foo: x:int=1:int, $fun$bar$1:TestKt$foo$1=TestKt$foo$1 +// test.kt:14 box: +// LOCAL VARIABLES JVM_IR +// test.kt:10 foo: x:int=1:int +// test.kt:14 box: \ No newline at end of file diff --git a/compiler/testData/debug/localVariables/localFunUnused.kt b/compiler/testData/debug/localVariables/localFunUnused.kt new file mode 100644 index 00000000000..594a4695a32 --- /dev/null +++ b/compiler/testData/debug/localVariables/localFunUnused.kt @@ -0,0 +1,31 @@ + + +//FILE: test.kt +fun foo() { + fun bar() { + } +} + +fun box() { + foo() +} + +// Local functions are compiled to private static functions on the class +// containing the local funtion. This has a number of consequences observable +// from a debugging perspective, for this test specically: +// - local functions do not figure in the LVT of the outer function, as they +// are not instantiated. +// - the _declaration_ of the local function does not figure in the byte code +// of the outer function and hence, has no line number + +// LOCAL VARIABLES +// LOCAL VARIABLES JVM +// test.kt:10 box: +// test.kt:5 foo: +// test.kt:7 foo: $fun$bar$1:TestKt$foo$1=TestKt$foo$1 +// test.kt:11 box: + +// LOCAL VARIABLES JVM_IR +// test.kt:10 box: +// test.kt:7 foo: +// test.kt:11 box: \ No newline at end of file diff --git a/compiler/testData/debug/stepping/localFunctionWIthOnelineExpressionBody.kt b/compiler/testData/debug/stepping/localFunctionWIthOnelineExpressionBody.kt new file mode 100644 index 00000000000..3d06594087a --- /dev/null +++ b/compiler/testData/debug/stepping/localFunctionWIthOnelineExpressionBody.kt @@ -0,0 +1,25 @@ +// FILE: test.kt + +fun box() { + "OK" + fun bar() = "OK" + "OK" + bar() + "OK" +} + +// LINENUMBERS +// test.kt:4 box +// LINENUMBERS JVM +// test.kt:5 box +// LINENUMBERS +// test.kt:6 box +// test.kt:7 box +// LINENUMBERS JVM +// test.kt:5 invoke +// LINENUMBERS JVM_IR +// test.kt:5 box$bar +// LINENUMBERS +// test.kt:7 box +// test.kt:8 box +// test.kt:9 box \ No newline at end of file diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index d54049b27e8..382d70c5f14 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -155,6 +155,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { runTest("compiler/testData/codegen/bytecodeListing/kt43519.kt"); } + @TestMetadata("localFunction.kt") + public void testLocalFunction() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/localFunction.kt"); + } + @TestMetadata("localFunctionInInitBlock.kt") public void testLocalFunctionInInitBlock() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/localFunctionInInitBlock.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/CheckLocalVariablesTableTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/CheckLocalVariablesTableTestGenerated.java index 267f391e8fd..9c0bc844e66 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/CheckLocalVariablesTableTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/CheckLocalVariablesTableTestGenerated.java @@ -30,26 +30,11 @@ public class CheckLocalVariablesTableTestGenerated extends AbstractCheckLocalVar KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/checkLocalVariablesTable"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } - @TestMetadata("copyFunction.kt") - public void testCopyFunction() throws Exception { - runTest("compiler/testData/checkLocalVariablesTable/copyFunction.kt"); - } - - @TestMetadata("destructuringInFor.kt") - public void testDestructuringInFor() throws Exception { - runTest("compiler/testData/checkLocalVariablesTable/destructuringInFor.kt"); - } - @TestMetadata("destructuringInLambdas.kt") public void testDestructuringInLambdas() throws Exception { runTest("compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt"); } - @TestMetadata("destructuringInlineLambda.kt") - public void testDestructuringInlineLambda() throws Exception { - runTest("compiler/testData/checkLocalVariablesTable/destructuringInlineLambda.kt"); - } - @TestMetadata("inlineLambdaWithItParam.kt") public void testInlineLambdaWithItParam() throws Exception { runTest("compiler/testData/checkLocalVariablesTable/inlineLambdaWithItParam.kt"); @@ -90,11 +75,6 @@ public class CheckLocalVariablesTableTestGenerated extends AbstractCheckLocalVar runTest("compiler/testData/checkLocalVariablesTable/lambdaAsVar.kt"); } - @TestMetadata("localFun.kt") - public void testLocalFun() throws Exception { - runTest("compiler/testData/checkLocalVariablesTable/localFun.kt"); - } - @TestMetadata("objectInLocalPropertyDelegate.kt") public void testObjectInLocalPropertyDelegate() throws Exception { runTest("compiler/testData/checkLocalVariablesTable/objectInLocalPropertyDelegate.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/IrLocalVariableTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/IrLocalVariableTestGenerated.java index 4094a1216a5..127b565293f 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/IrLocalVariableTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/IrLocalVariableTestGenerated.java @@ -56,6 +56,12 @@ public class IrLocalVariableTestGenerated extends AbstractIrLocalVariableTest { runTest("compiler/testData/debug/localVariables/destructuringInLambdas.kt"); } + @Test + @TestMetadata("emptyFun.kt") + public void testEmptyFun() throws Exception { + runTest("compiler/testData/debug/localVariables/emptyFun.kt"); + } + @Test @TestMetadata("inlineProperty.kt") public void testInlineProperty() throws Exception { @@ -74,6 +80,12 @@ public class IrLocalVariableTestGenerated extends AbstractIrLocalVariableTest { runTest("compiler/testData/debug/localVariables/localFun.kt"); } + @Test + @TestMetadata("localFunUnused.kt") + public void testLocalFunUnused() throws Exception { + runTest("compiler/testData/debug/localVariables/localFunUnused.kt"); + } + @Test @TestMetadata("underscoreNames.kt") public void testUnderscoreNames() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/IrSteppingTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/IrSteppingTestGenerated.java index 26c4c084cf6..3f4c484da59 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/IrSteppingTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/IrSteppingTestGenerated.java @@ -266,6 +266,12 @@ public class IrSteppingTestGenerated extends AbstractIrSteppingTest { runTest("compiler/testData/debug/stepping/localFunction.kt"); } + @Test + @TestMetadata("localFunctionWIthOnelineExpressionBody.kt") + public void testLocalFunctionWIthOnelineExpressionBody() throws Exception { + runTest("compiler/testData/debug/stepping/localFunctionWIthOnelineExpressionBody.kt"); + } + @Test @TestMetadata("multilineFunctionCall.kt") public void testMultilineFunctionCall() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/LocalVariableTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/LocalVariableTestGenerated.java index f2d72bf62ae..dc9082c975d 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/LocalVariableTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/LocalVariableTestGenerated.java @@ -56,6 +56,12 @@ public class LocalVariableTestGenerated extends AbstractLocalVariableTest { runTest("compiler/testData/debug/localVariables/destructuringInLambdas.kt"); } + @Test + @TestMetadata("emptyFun.kt") + public void testEmptyFun() throws Exception { + runTest("compiler/testData/debug/localVariables/emptyFun.kt"); + } + @Test @TestMetadata("inlineProperty.kt") public void testInlineProperty() throws Exception { @@ -74,6 +80,12 @@ public class LocalVariableTestGenerated extends AbstractLocalVariableTest { runTest("compiler/testData/debug/localVariables/localFun.kt"); } + @Test + @TestMetadata("localFunUnused.kt") + public void testLocalFunUnused() throws Exception { + runTest("compiler/testData/debug/localVariables/localFunUnused.kt"); + } + @Test @TestMetadata("underscoreNames.kt") public void testUnderscoreNames() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/SteppingTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/SteppingTestGenerated.java index 648c92c215e..eacf41515d0 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/SteppingTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/debugInformation/SteppingTestGenerated.java @@ -266,6 +266,12 @@ public class SteppingTestGenerated extends AbstractSteppingTest { runTest("compiler/testData/debug/stepping/localFunction.kt"); } + @Test + @TestMetadata("localFunctionWIthOnelineExpressionBody.kt") + public void testLocalFunctionWIthOnelineExpressionBody() throws Exception { + runTest("compiler/testData/debug/stepping/localFunctionWIthOnelineExpressionBody.kt"); + } + @Test @TestMetadata("multilineFunctionCall.kt") public void testMultilineFunctionCall() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java index e1e072ffb74..d9e1a3e75aa 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java @@ -155,6 +155,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes runTest("compiler/testData/codegen/bytecodeListing/kt43519.kt"); } + @TestMetadata("localFunction.kt") + public void testLocalFunction() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/localFunction.kt"); + } + @TestMetadata("localFunctionInInitBlock.kt") public void testLocalFunctionInInitBlock() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/localFunctionInInitBlock.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrCheckLocalVariablesTableTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrCheckLocalVariablesTableTestGenerated.java index d26c883b88e..dca584a14d3 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrCheckLocalVariablesTableTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrCheckLocalVariablesTableTestGenerated.java @@ -30,26 +30,11 @@ public class IrCheckLocalVariablesTableTestGenerated extends AbstractIrCheckLoca KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/checkLocalVariablesTable"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } - @TestMetadata("copyFunction.kt") - public void testCopyFunction() throws Exception { - runTest("compiler/testData/checkLocalVariablesTable/copyFunction.kt"); - } - - @TestMetadata("destructuringInFor.kt") - public void testDestructuringInFor() throws Exception { - runTest("compiler/testData/checkLocalVariablesTable/destructuringInFor.kt"); - } - @TestMetadata("destructuringInLambdas.kt") public void testDestructuringInLambdas() throws Exception { runTest("compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt"); } - @TestMetadata("destructuringInlineLambda.kt") - public void testDestructuringInlineLambda() throws Exception { - runTest("compiler/testData/checkLocalVariablesTable/destructuringInlineLambda.kt"); - } - @TestMetadata("inlineLambdaWithItParam.kt") public void testInlineLambdaWithItParam() throws Exception { runTest("compiler/testData/checkLocalVariablesTable/inlineLambdaWithItParam.kt"); @@ -90,11 +75,6 @@ public class IrCheckLocalVariablesTableTestGenerated extends AbstractIrCheckLoca runTest("compiler/testData/checkLocalVariablesTable/lambdaAsVar.kt"); } - @TestMetadata("localFun.kt") - public void testLocalFun() throws Exception { - runTest("compiler/testData/checkLocalVariablesTable/localFun.kt"); - } - @TestMetadata("objectInLocalPropertyDelegate.kt") public void testObjectInLocalPropertyDelegate() throws Exception { runTest("compiler/testData/checkLocalVariablesTable/objectInLocalPropertyDelegate.kt"); diff --git a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/IrKotlinEvaluateExpressionTestGenerated.java b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/IrKotlinEvaluateExpressionTestGenerated.java index 31b25014a26..6e643a5f381 100644 --- a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/IrKotlinEvaluateExpressionTestGenerated.java +++ b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/IrKotlinEvaluateExpressionTestGenerated.java @@ -337,6 +337,11 @@ public class IrKotlinEvaluateExpressionTestGenerated extends AbstractIrKotlinEva runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localClass.kt"); } + @TestMetadata("localFunctionCapturedLocalVariable.kt") + public void testLocalFunctionCapturedLocalVariable() throws Exception { + runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionCapturedLocalVariable.kt"); + } + @TestMetadata("localFunctionsWithReceivers.kt") public void testLocalFunctionsWithReceivers() throws Exception { runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionsWithReceivers.kt"); diff --git a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/IrKotlinSteppingTestGenerated.java b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/IrKotlinSteppingTestGenerated.java index 6b39eec53a2..6ac4bf55172 100644 --- a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/IrKotlinSteppingTestGenerated.java +++ b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/IrKotlinSteppingTestGenerated.java @@ -503,6 +503,16 @@ public class IrKotlinSteppingTestGenerated extends AbstractIrKotlinSteppingTest runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMapFiltersDisabled.kt"); } + @TestMetadata("localFunction.kt") + public void testLocalFunction() throws Exception { + runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.kt"); + } + + @TestMetadata("localFunctionWithSingleLineExpressionBody.kt") + public void testLocalFunctionWithSingleLineExpressionBody() throws Exception { + runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.kt"); + } + @TestMetadata("noParameterExtensionLambdaArgumentCallInInline.kt") public void testNoParameterExtensionLambdaArgumentCallInInline() throws Exception { runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/noParameterExtensionLambdaArgumentCallInInline.kt"); diff --git a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinEvaluateExpressionTestGenerated.java b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinEvaluateExpressionTestGenerated.java index a0ff77b097c..49c8b3c954b 100644 --- a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinEvaluateExpressionTestGenerated.java @@ -336,6 +336,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localClass.kt"); } + @TestMetadata("localFunctionCapturedLocalVariable.kt") + public void testLocalFunctionCapturedLocalVariable() throws Exception { + runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionCapturedLocalVariable.kt"); + } + @TestMetadata("localFunctionsWithReceivers.kt") public void testLocalFunctionsWithReceivers() throws Exception { runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionsWithReceivers.kt"); diff --git a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinSteppingTestGenerated.java b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinSteppingTestGenerated.java index 60e08be64e6..1fce43faee8 100644 --- a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinSteppingTestGenerated.java +++ b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinSteppingTestGenerated.java @@ -503,6 +503,16 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest { runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMapFiltersDisabled.kt"); } + @TestMetadata("localFunction.kt") + public void testLocalFunction() throws Exception { + runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.kt"); + } + + @TestMetadata("localFunctionWithSingleLineExpressionBody.kt") + public void testLocalFunctionWithSingleLineExpressionBody() throws Exception { + runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.kt"); + } + @TestMetadata("noParameterExtensionLambdaArgumentCallInInline.kt") public void testNoParameterExtensionLambdaArgumentCallInInline() throws Exception { runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/noParameterExtensionLambdaArgumentCallInInline.kt"); diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionCapturedLocalVariable.kt b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionCapturedLocalVariable.kt new file mode 100644 index 00000000000..a0b11dd2ddb --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionCapturedLocalVariable.kt @@ -0,0 +1,13 @@ +package localFunctionCapturedLocalVariable + +fun main(args: Array) { + val a = 1 + fun local() { + //Breakpoint! + val x = a + 2 + } + local() +} + +// EXPRESSION: a +// RESULT: 1: I diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionCapturedLocalVariable.out b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionCapturedLocalVariable.out new file mode 100644 index 00000000000..691ea28030f --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionCapturedLocalVariable.out @@ -0,0 +1,8 @@ +LineBreakpoint created at localFunctionCapturedLocalVariable.kt:7 +Run Java +Connected to the target VM +localFunctionCapturedLocalVariable.kt:7 +Compile bytecode for a +Disconnected from the target VM + +Process finished with exit code 0 diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.ir.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.ir.out new file mode 100644 index 00000000000..caafbbb6392 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.ir.out @@ -0,0 +1,6 @@ +LineBreakpoint created at localFunction.kt:5 +Run Java +Connected to the target VM +Disconnected from the target VM + +Process finished with exit code 0 diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.kt b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.kt new file mode 100644 index 00000000000..b50621e97a3 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.kt @@ -0,0 +1,12 @@ +package localFunction + +fun main() { + //Breakpoint! + fun bar() { + "OK" + } + bar() +} + +// STEP_OVER: 1 +// Code compiled on the IR cannot break on local function declarations \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.out new file mode 100644 index 00000000000..13aac9ff50a --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.out @@ -0,0 +1,8 @@ +LineBreakpoint created at localFunction.kt:5 +Run Java +Connected to the target VM +localFunction.kt:5 +localFunction.kt:8 +Disconnected from the target VM + +Process finished with exit code 0 diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.ir.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.ir.out new file mode 100644 index 00000000000..1ce6d75cc17 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.ir.out @@ -0,0 +1,9 @@ +LineBreakpoint created at localFunctionWithSingleLineExpressionBody.kt:5 +Run Java +Connected to the target VM +localFunctionWithSingleLineExpressionBody.kt:5 +localFunctionWithSingleLineExpressionBody.kt:7 +Disconnected from the target VM + +Process finished with exit code 0 + diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.kt b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.kt new file mode 100644 index 00000000000..92dd8e98f50 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.kt @@ -0,0 +1,13 @@ +package localFunctionWithSingleLineExpressionBody + +fun main() { + //Breakpoint! + fun bar() = "OK" + val x = 1 + bar() +} + +// STEP_OVER: 1 +// The behavior of the two backends is different because they stop at two different instructions. +// - The JVM backend stops on the declaration of bar on main:5, so stepping over proceeds to main:6 +// - The IR backend stops on the _body_ of bar when called from main:7, so proceeds to main:7 \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.out new file mode 100644 index 00000000000..64c08d8fe31 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.out @@ -0,0 +1,10 @@ +LineBreakpoint created at localFunctionWithSingleLineExpressionBody.kt:5 +Run Java +Connected to the target VM +localFunctionWithSingleLineExpressionBody.kt:5 +localFunctionWithSingleLineExpressionBody.kt:6 +resuming localFunctionWithSingleLineExpressionBody.kt:5 +Disconnected from the target VM + +Process finished with exit code 0 +