diff --git a/compiler/testData/checkLocalVariablesTable/catchClause.kt b/compiler/testData/checkLocalVariablesTable/catchClause.kt deleted file mode 100644 index 66901447d3e..00000000000 --- a/compiler/testData/checkLocalVariablesTable/catchClause.kt +++ /dev/null @@ -1,16 +0,0 @@ -class A { - fun foo() { - try { - var a = 1 - a++ - } - catch(e : Throwable) { - e.printStackTrace() - } - } -} - -// METHOD : A.foo()V -// VARIABLE : NAME=a TYPE=I INDEX=1 -// VARIABLE : NAME=e TYPE=Ljava/lang/Throwable; INDEX=1 -// VARIABLE : NAME=this TYPE=LA; INDEX=0 diff --git a/compiler/testData/debug/localVariables/catchClause.kt b/compiler/testData/debug/localVariables/catchClause.kt new file mode 100644 index 00000000000..5ca09e84bd9 --- /dev/null +++ b/compiler/testData/debug/localVariables/catchClause.kt @@ -0,0 +1,19 @@ +// FILE: test.kt +fun box() { + try { + var a = 1 + a -- + a /= a + } catch(e : Throwable) { + e.printStackTrace() + } +} + +// LOCAL VARIABLES +// TestKt:3: +// TestKt:4: +// TestKt:5: a:int=1:int +// TestKt:6: a:int=0:int +// TestKt:7: +// TestKt:8: e:java.lang.Throwable=java.lang.ArithmeticException +// TestKt:10: diff --git a/compiler/testData/debug/localVariables/copyFunction.kt b/compiler/testData/debug/localVariables/copyFunction.kt index 3ec0742aaab..76184a8121d 100644 --- a/compiler/testData/debug/localVariables/copyFunction.kt +++ b/compiler/testData/debug/localVariables/copyFunction.kt @@ -9,11 +9,11 @@ fun box() { // LOCAL VARIABLES // TestKt:6: -// someClass:3: a:double, b:double +// someClass:3: a:double=1.0:double, b:double=2.0:double // TestKt:6: -// TestKt:7: a:someClass -// someClass:3: a:double, b:double -// someClass.copy(double, double)+9: a:double, b:double +// TestKt:7: a:someClass=someClass +// someClass:3: a:double=1.0:double, b:double=3.0:double +// someClass.copy(double, double)+9: a:double=1.0:double, b:double=3.0:double // someClass.copy$default(someClass, double, double, int, java.lang.Object)+30: -// TestKt:7: a:someClass -// TestKt:8: a:someClass, b:someClass \ No newline at end of file +// TestKt:7: a:someClass=someClass +// TestKt:8: a:someClass=someClass, b:someClass=someClass \ No newline at end of file diff --git a/compiler/testData/debug/localVariables/destructuringInFor.kt b/compiler/testData/debug/localVariables/destructuringInFor.kt index 85e091411b9..ed6bdaefe7a 100644 --- a/compiler/testData/debug/localVariables/destructuringInFor.kt +++ b/compiler/testData/debug/localVariables/destructuringInFor.kt @@ -12,8 +12,8 @@ fun box() { // IGNORE_BACKEND: JVM_IR // LOCAL VARIABLES // TestKt:6: -// TestKt:8: map:java.util.Collections$SingletonMap -// TestKt:7: map:java.util.Collections$SingletonMap -// TestKt:9: map:java.util.Collections$SingletonMap, a:java.lang.String, b:java.lang.String -// TestKt:7: map:java.util.Collections$SingletonMap -// TestKt:11: map:java.util.Collections$SingletonMap +// TestKt:8: map:java.util.Map=java.util.Collections$SingletonMap +// TestKt:7: map:java.util.Map=java.util.Collections$SingletonMap +// TestKt:9: map:java.util.Map=java.util.Collections$SingletonMap, a:java.lang.String="1":java.lang.String, b:java.lang.String="23":java.lang.String +// TestKt:7: map:java.util.Map=java.util.Collections$SingletonMap +// TestKt:11: map:java.util.Map=java.util.Collections$SingletonMap \ No newline at end of file diff --git a/compiler/testData/debug/localVariables/destructuringInLambdas.kt b/compiler/testData/debug/localVariables/destructuringInLambdas.kt index 16a619004d7..6d680bf8def 100644 --- a/compiler/testData/debug/localVariables/destructuringInLambdas.kt +++ b/compiler/testData/debug/localVariables/destructuringInLambdas.kt @@ -10,11 +10,11 @@ fun box() { // IGNORE_BACKEND: JVM_IR // LOCAL VARIABLES // TestKt:8: -// A:3: x:java.lang.String, y:int +// A:3: x:java.lang.String="O":java.lang.String, y:int=123:int // TestKt:8: -// TestKt:5: a:A, block:TestKt$box$1 -// TestKt$box$1:8: $dstr$x$y:A +// TestKt:5: a:A=A, block:kotlin.jvm.functions.Function1=TestKt$box$1 +// TestKt$box$1:8: $dstr$x$y:A=A // TestKt$box$1.invoke(java.lang.Object)+8: -// TestKt:5: a:A, block:TestKt$box$1 +// TestKt:5: a:A=A, block:kotlin.jvm.functions.Function1=TestKt$box$1 // TestKt:8: // TestKt:9: \ No newline at end of file diff --git a/compiler/testData/debug/localVariables/localFun.kt b/compiler/testData/debug/localVariables/localFun.kt index 2e8c7ba7997..7cdccc8a8db 100644 --- a/compiler/testData/debug/localVariables/localFun.kt +++ b/compiler/testData/debug/localVariables/localFun.kt @@ -12,5 +12,5 @@ fun box() { // LOCAL VARIABLES // TestKt:9: // TestKt:4: -// TestKt:6: $fun$bar$1:TestKt$foo$1 +// TestKt:6: $fun$bar$1:TestKt$foo$1=TestKt$foo$1 // TestKt:10: \ No newline at end of file diff --git a/compiler/testData/debug/localVariables/underscoreNames.kt b/compiler/testData/debug/localVariables/underscoreNames.kt index 95853ee7baf..9dce211a2d1 100644 --- a/compiler/testData/debug/localVariables/underscoreNames.kt +++ b/compiler/testData/debug/localVariables/underscoreNames.kt @@ -25,25 +25,25 @@ fun box() { // LOCAL VARIABLES // TestKt:11: // A:3: -// A:3: x:double, y:java.lang.String, z:char +// A:3: x:double=1.0:double, y:java.lang.String="":java.lang.String, z:char=0:char // A:3: // TestKt:11: -// TestKt:5: a:A, block:TestKt$box$1 -// TestKt$box$1:14: $dstr$x$_u24__u24$y:A, $noName_1:java.lang.String, w:int +// TestKt:5: a:A=A, block:kotlin.jvm.functions.Function3=TestKt$box$1 +// TestKt$box$1:14: $dstr$x$_u24__u24$y:A=A, $noName_1:java.lang.String="":java.lang.String, w:int=1:int // A:3: -// A:3: x:double, y:java.lang.String, z:char +// A:3: x:double=1.0:double, y:java.lang.String="":java.lang.String, z:char=0:char // A:3: -// TestKt$box$1:14: $dstr$x$_u24__u24$y:A, $noName_1:java.lang.String, w:int, x:double, y:char -// TestKt$box$1:15: $dstr$x$_u24__u24$y:A, $noName_1:java.lang.String, w:int, x:double, y:char, a:double, c:char +// TestKt$box$1:14: $dstr$x$_u24__u24$y:A=A, $noName_1:java.lang.String="":java.lang.String, w:int=1:int, x:double=1.0:double, y:char=0:char +// TestKt$box$1:15: $dstr$x$_u24__u24$y:A=A, $noName_1:java.lang.String="":java.lang.String, w:int=1:int, x:double=1.0:double, y:char=0:char, a:double=1.0:double, c:char=0:char // A:3: -// A:3: x:double, y:java.lang.String, z:char +// A:3: x:double=1.0:double, y:java.lang.String="":java.lang.String, z:char=0:char // A:3: -// TestKt$box$1:15: $dstr$x$_u24__u24$y:A, $noName_1:java.lang.String, w:int, x:double, y:char, a:double, c:char -// TestKt$box$1:17: $dstr$x$_u24__u24$y:A, $noName_1:java.lang.String, w:int, x:double, y:char, a:double, c:char, _:java.lang.String, d:char +// TestKt$box$1:15: $dstr$x$_u24__u24$y:A=A, $noName_1:java.lang.String="":java.lang.String, w:int=1:int, x:double=1.0:double, y:char=0:char, a:double=1.0:double, c:char=0:char +// TestKt$box$1:17: $dstr$x$_u24__u24$y:A=A, $noName_1:java.lang.String="":java.lang.String, w:int=1:int, x:double=1.0:double, y:char=0:char, a:double=1.0:double, c:char=0:char, _:java.lang.String="":java.lang.String, d:char=0:char // TestKt:7: -// TestKt$box$1:17: $dstr$x$_u24__u24$y:A, $noName_1:java.lang.String, w:int, x:double, y:char, a:double, c:char, _:java.lang.String, d:char -// TestKt$box$1:21: $dstr$x$_u24__u24$y:A, $noName_1:java.lang.String, w:int, x:double, y:char, a:double, c:char, _:java.lang.String, d:char +// TestKt$box$1:17: $dstr$x$_u24__u24$y:A=A, $noName_1:java.lang.String="":java.lang.String, w:int=1:int, x:double=1.0:double, y:char=0:char, a:double=1.0:double, c:char=0:char, _:java.lang.String="":java.lang.String, d:char=0:char +// TestKt$box$1:21: $dstr$x$_u24__u24$y:A=A, $noName_1:java.lang.String="":java.lang.String, w:int=1:int, x:double=1.0:double, y:char=0:char, a:double=1.0:double, c:char=0:char, _:java.lang.String="":java.lang.String, d:char=0:char // TestKt$box$1.invoke(java.lang.Object, java.lang.Object, java.lang.Object)+19: -// TestKt:5: a:A, block:TestKt$box$1 +// TestKt:5: a:A=A, block:kotlin.jvm.functions.Function3=TestKt$box$1 // TestKt:11: // TestKt:23: \ No newline at end of file diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/debugInformation/AbstractDebugTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/debugInformation/AbstractDebugTest.kt index 5fef33f3a81..0a086afbe79 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/debugInformation/AbstractDebugTest.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/debugInformation/AbstractDebugTest.kt @@ -171,6 +171,9 @@ abstract class AbstractDebugTest : CodegenTestCase() { val classLoader = createGeneratedClassLoader(classesDir) val aClass = getGeneratedClass(classLoader, TEST_CLASS) + assert(aClass.declaredMethods.any { it.name == BOX_METHOD }) { + "Test method $BOX_METHOD not present on test class $TEST_CLASS" + } if (virtualMachine.allThreads().any { it.isSuspended }) { virtualMachine.resume() } diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/debugInformation/AbstractLocalVariableTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/debugInformation/AbstractLocalVariableTest.kt index ec6e5704545..52c90fd2d19 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/debugInformation/AbstractLocalVariableTest.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/debugInformation/AbstractLocalVariableTest.kt @@ -1,11 +1,10 @@ package org.jetbrains.kotlin.codegen.debugInformation -import com.sun.jdi.LocalVariable -import com.sun.jdi.StackFrame -import com.sun.jdi.VirtualMachine +import com.sun.jdi.* import com.sun.jdi.event.Event import com.sun.jdi.event.LocatableEvent import junit.framework.TestCase +import org.jetbrains.kotlin.test.TargetBackend import org.junit.AfterClass import org.junit.BeforeClass import java.io.File @@ -15,7 +14,41 @@ abstract class AbstractLocalVariableTest : AbstractDebugTest() { override val virtualMachine: VirtualMachine = Companion.virtualMachine override val proxyPort: Int = Companion.proxyPort + interface LocalValue + + class LocalPrimitive(val value: String, val valueType: String) : LocalValue { + override fun toString(): String { + return "$value:$valueType" + } + } + + class LocalReference(val id: String, val referenceType: String) : LocalValue { + override fun toString(): String { + return "$referenceType" + } + } + + class LocalNullValue : LocalValue { + override fun toString(): String { + return "null" + } + } + + class LocalVariableRecord( + val variable: String, + val variableType: String, + val value: LocalValue + ) { + override fun toString(): String { + return "$variable:$variableType=$value" + } + } + companion object { + const val LOCAL_VARIABLES_MARKER = "// LOCAL VARIABLES" + const val JVM_LOCAL_VARIABLES_MARKER = "$LOCAL_VARIABLES_MARKER JVM" + const val JVM_IR_LOCAL_VARIABLES_MARKER = "$LOCAL_VARIABLES_MARKER JVM_IR" + const val LOCAL_VARIABLES = "// LOCAL VARIABLES" var proxyPort = 0 lateinit var process: Process @@ -41,29 +74,60 @@ abstract class AbstractLocalVariableTest : AbstractDebugTest() { override fun storeStep(loggedItems: ArrayList, event: Event) { waitUntil { (event as LocatableEvent).thread().isSuspended } - val visibleVars = (event as LocatableEvent) - .thread() - .frame(0) - .visibleVariables() - .map { variable -> toRecord(event.thread().frame(0), variable) } - .joinToString(", ") - loggedItems.add("${event.location()}: $visibleVars".trim()) + val frame = (event as LocatableEvent).thread().frame(0) + try { + val visibleVars = frame + .visibleVariables() + .map { variable -> toRecord(frame, variable) } + .joinToString(", ") + loggedItems.add("${event.location()}: $visibleVars".trim()) + } catch (e: AbsentInformationException) { + // LVT Completely absent - not distinguished from an empty table + loggedItems.add("${event.location()}:".trim()) + } } override fun checkResult(wholeFile: File, loggedItems: List) { - val expectedLocalVariables = wholeFile - .readLines() - .dropWhile { !it.startsWith(LOCAL_VARIABLES) } - .drop(1) - .map { it.drop(3) } - .joinToString("\n") + val lines = wholeFile.readLines() + + val expectedLocalVariables = mutableListOf() + val lineIterator = lines.iterator() + for (line in lineIterator) { + if (line.startsWith(LOCAL_VARIABLES_MARKER)) break + } + + var currentBackend = TargetBackend.ANY + for (line in lineIterator) { + if (line.trim() == "") continue + if (line.startsWith(LOCAL_VARIABLES_MARKER)) { + currentBackend = when (line) { + LOCAL_VARIABLES_MARKER -> TargetBackend.ANY + JVM_LOCAL_VARIABLES_MARKER -> TargetBackend.JVM + JVM_IR_LOCAL_VARIABLES_MARKER -> TargetBackend.JVM_IR + else -> error("Expected JVM backend: $line") + } + continue + } + if (currentBackend == TargetBackend.ANY || currentBackend == backend) { + expectedLocalVariables.add(line.drop(3)) + } + } + val actualLocalVariables = loggedItems.joinToString("\n") - TestCase.assertEquals(expectedLocalVariables, actualLocalVariables) + TestCase.assertEquals(expectedLocalVariables.joinToString("\n"), actualLocalVariables) } - private fun toRecord(frame: StackFrame, variable: LocalVariable): String { - return "${variable.name()}:${frame.getValue(variable)?.type()?.name() ?: "null"}" + private fun toRecord(frame: StackFrame, variable: LocalVariable): LocalVariableRecord { + val value = frame.getValue(variable) + val valueRecord = if (value == null) { + LocalNullValue() + } else if (value is ObjectReference && value.referenceType().name() != "java.lang.String") { + LocalReference(value.uniqueID().toString(), value.referenceType().name()) + } else { + LocalPrimitive(value.toString(), value.type().name()) + } + return LocalVariableRecord(variable.name(), variable.typeName(), valueRecord) } private fun waitUntil(condition: () -> Boolean) { diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CheckLocalVariablesTableTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CheckLocalVariablesTableTestGenerated.java index 60a5b764022..397fab7b8b7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CheckLocalVariablesTableTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CheckLocalVariablesTableTestGenerated.java @@ -29,11 +29,6 @@ public class CheckLocalVariablesTableTestGenerated extends AbstractCheckLocalVar KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/checkLocalVariablesTable"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } - @TestMetadata("catchClause.kt") - public void testCatchClause() throws Exception { - runTest("compiler/testData/checkLocalVariablesTable/catchClause.kt"); - } - @TestMetadata("copyFunction.kt") public void testCopyFunction() throws Exception { runTest("compiler/testData/checkLocalVariablesTable/copyFunction.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/IrLocalVariableTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/IrLocalVariableTestGenerated.java index 40e14135ed1..bc52c5cb9f9 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/IrLocalVariableTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/IrLocalVariableTestGenerated.java @@ -31,6 +31,12 @@ public class IrLocalVariableTestGenerated extends AbstractIrLocalVariableTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/debug/localVariables"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("catchClause.kt") + public void testCatchClause() throws Exception { + runTest("compiler/testData/debug/localVariables/catchClause.kt"); + } + @Test @TestMetadata("copyFunction.kt") public void testCopyFunction() throws Exception { diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/LocalVariableTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/LocalVariableTestGenerated.java index d9d9e7f011b..bdef17af544 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/LocalVariableTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/LocalVariableTestGenerated.java @@ -31,6 +31,12 @@ public class LocalVariableTestGenerated extends AbstractLocalVariableTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/debug/localVariables"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @Test + @TestMetadata("catchClause.kt") + public void testCatchClause() throws Exception { + runTest("compiler/testData/debug/localVariables/catchClause.kt"); + } + @Test @TestMetadata("copyFunction.kt") public void testCopyFunction() throws Exception { diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCheckLocalVariablesTableTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCheckLocalVariablesTableTestGenerated.java index 5fe679c7190..9919c31b77c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCheckLocalVariablesTableTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCheckLocalVariablesTableTestGenerated.java @@ -29,11 +29,6 @@ public class IrCheckLocalVariablesTableTestGenerated extends AbstractIrCheckLoca KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/checkLocalVariablesTable"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } - @TestMetadata("catchClause.kt") - public void testCatchClause() throws Exception { - runTest("compiler/testData/checkLocalVariablesTable/catchClause.kt"); - } - @TestMetadata("copyFunction.kt") public void testCopyFunction() throws Exception { runTest("compiler/testData/checkLocalVariablesTable/copyFunction.kt");