From 3ab7c6c8e9cd3757bdbcd20208774ec3a487bd05 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Tue, 2 Dec 2014 15:28:19 +0300 Subject: [PATCH] Evaluate Expression: fix for anonymous objects - expressions where anonymous type can be replaced with super type can be evaluated --- .../evaluate/KotlinEvaluationBuilder.kt | 21 +++++++++++++++++++ .../tinyApp/outs/anonymousObjects.out | 9 ++++++++ .../singleBreakpoint/anonymousObjects.kt | 19 +++++++++++++++++ ...KotlinEvaluateExpressionTestGenerated.java | 6 ++++++ 4 files changed, 55 insertions(+) create mode 100644 idea/testData/debugger/tinyApp/outs/anonymousObjects.out create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/anonymousObjects.kt diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt index 6dc29824a41..e808cdb8bf5 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -76,6 +76,7 @@ import org.jetbrains.jet.lang.psi.JetElement import org.jetbrains.jet.plugin.util.attachment.attachmentByPsiFile import com.intellij.openapi.diagnostic.Attachment import org.jetbrains.jet.plugin.util.attachment.mergeAttachments +import com.sun.jdi.ClassType private val RECEIVER_NAME = "\$receiver" private val THIS_NAME = "this" @@ -346,6 +347,22 @@ private fun SuspendContext.getInvokePolicy(): Int { return if (getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD) ObjectReference.INVOKE_SINGLE_THREADED else 0 } +private fun com.sun.jdi.Type?.isSubclass(superClassName: String): Boolean { + if (this !is ClassType) return false + if (allInterfaces().any { it.name() == superClassName }) { + return true + } + + var superClass = this.superclass() + while (superClass != null) { + if (superClass.name() == superClassName) { + return true + } + superClass = superClass.superclass() + } + return false +} + fun EvaluationContextImpl.findLocalVariable(name: String, asmType: Type?, checkType: Boolean, failIfNotFound: Boolean): Value? { val project = getDebugProcess().getProject() val frame = getFrameProxy()?.getStackFrame() @@ -355,6 +372,10 @@ fun EvaluationContextImpl.findLocalVariable(name: String, asmType: Type?, checkT if (!shouldCheckType || asmType == null || value.asmType == asmType) return true if (project == null) return false + if ((value.obj() as? com.sun.jdi.ObjectReference)?.referenceType().isSubclass(asmType.getClassName())) { + return true + } + val thisDesc = value.asmType.getClassDescriptor(project) val expDesc = asmType.getClassDescriptor(project) return thisDesc != null && expDesc != null && runReadAction { DescriptorUtils.isSubclass(thisDesc, expDesc) } diff --git a/idea/testData/debugger/tinyApp/outs/anonymousObjects.out b/idea/testData/debugger/tinyApp/outs/anonymousObjects.out new file mode 100644 index 00000000000..5361e73095e --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/anonymousObjects.out @@ -0,0 +1,9 @@ +LineBreakpoint created at anonymousObjects.kt:11 +!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! anonymousObjects.AnonymousObjectsPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +anonymousObjects.kt:11 +Compile bytecode for test(2) +Compile bytecode for i +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/anonymousObjects.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/anonymousObjects.kt new file mode 100644 index 00000000000..a16f4edfcbc --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/anonymousObjects.kt @@ -0,0 +1,19 @@ +package anonymousObjects + +fun main(args: Array) { + val a = object: AbstractClass(1) {} + a.test(1) +} + +abstract class AbstractClass(val i: Int) { + fun test(i: Int): Int { + //Breakpoint! + return i + } +} + +// EXPRESSION: test(2) +// RESULT: 2: I + +// EXPRESSION: i +// RESULT: 1: I \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index ad785c793d5..5ac1a4e0b45 100644 --- a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -46,6 +46,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("anonymousObjects.kt") + public void testAnonymousObjects() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/anonymousObjects.kt"); + doSingleBreakpointTest(fileName); + } + @TestMetadata("arrays.kt") public void testArrays() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/arrays.kt");