From cce22c0df9215776e5bd7a2312d960e5f8f776d1 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Tue, 21 Oct 2014 15:31:30 +0400 Subject: [PATCH] Debugger: implement getSourcePosition for fields --- ...otlinClassWithDelegatedPropertyRenderer.kt | 12 +-- .../debugger/render/KotlinObjectRenderer.kt | 87 +++++++++++++++++-- .../tinyApp/outs/delegatedPropertyInClass.out | 10 +-- .../tinyApp/outs/frameAnonymousObject.out | 6 +- .../tinyApp/outs/frameExtFunExtFun.out | 20 ++--- .../tinyApp/outs/frameExtensionFun.out | 2 +- .../debugger/tinyApp/outs/frameInnerClass.out | 6 +- .../tinyApp/outs/frameInnerLambda.out | 6 +- .../debugger/tinyApp/outs/frameLambda.out | 2 +- .../debugger/tinyApp/outs/frameSharedVar.out | 4 +- .../tinyApp/outs/frameSharedVarLocalVar.out | 2 +- .../debugger/tinyApp/outs/frameSimple.out | 10 +-- .../debugger/tinyApp/outs/frameThis0.out | 6 +- .../debugger/tinyApp/outs/frameThis0Ext.out | 10 +-- .../debugger/tinyApp/outs/frameThis0This0.out | 10 +-- .../plugin/debugger/KotlinDebuggerTestBase.kt | 37 ++++---- .../AbstractKotlinEvaluateExpressionTest.kt | 20 ++++- 17 files changed, 167 insertions(+), 83 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/render/KotlinClassWithDelegatedPropertyRenderer.kt b/idea/src/org/jetbrains/jet/plugin/debugger/render/KotlinClassWithDelegatedPropertyRenderer.kt index 65780593e61..981142f8c57 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/render/KotlinClassWithDelegatedPropertyRenderer.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/render/KotlinClassWithDelegatedPropertyRenderer.kt @@ -16,7 +16,6 @@ package org.jetbrains.jet.plugin.debugger.render -import com.intellij.debugger.ui.tree.render.ClassRenderer import com.sun.jdi.Type as JdiType import com.sun.jdi.Value import com.intellij.debugger.ui.tree.render.ChildrenBuilder @@ -24,7 +23,6 @@ import com.intellij.debugger.engine.evaluation.EvaluationContext import com.intellij.debugger.ui.tree.DebuggerTreeNode import org.jetbrains.org.objectweb.asm.Type as AsmType import com.intellij.debugger.engine.DebuggerManagerThreadImpl -import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl import com.sun.jdi.ObjectReference import com.intellij.xdebugger.settings.XDebuggerSettingsManager import com.intellij.debugger.ui.impl.watch.NodeManagerImpl @@ -32,20 +30,18 @@ import com.intellij.debugger.ui.impl.watch.MessageDescriptor import java.util.ArrayList import org.jetbrains.jet.lang.resolve.java.JvmAbi import com.sun.jdi.Field -import com.intellij.debugger.engine.DebuggerUtils -import com.intellij.debugger.ui.impl.watch.FieldDescriptorImpl -import com.intellij.debugger.engine.evaluation.EvaluateException import com.sun.jdi.ReferenceType import com.sun.jdi.Type import com.sun.jdi.InvocationException import com.sun.jdi.Method import org.jetbrains.jet.codegen.PropertyCodegen import org.jetbrains.jet.lang.resolve.name.Name +import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl -public class KotlinClassWithDelegatedPropertyRenderer : ClassRenderer() { +public class KotlinClassWithDelegatedPropertyRenderer : KotlinObjectRenderer() { override fun isApplicable(jdiType: Type?): Boolean { - if (!super.isApplicable(jdiType)) return false + if (!super.isApplicable(jdiType)) return false if (jdiType !is ReferenceType) return false @@ -72,7 +68,7 @@ public class KotlinClassWithDelegatedPropertyRenderer : ClassRenderer() { continue } - val fieldDescriptor = nodeDescriptorFactory.getFieldDescriptor(builder.getParentDescriptor(), value, field) + val fieldDescriptor = createFieldDescriptor(builder.getParentDescriptor() as ValueDescriptorImpl, nodeDescriptorFactory, value, field, context) children.add(nodeManager.createNode(fieldDescriptor, context)) if (field.name().endsWith(JvmAbi.DELEGATED_PROPERTY_NAME_SUFFIX)) { diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/render/KotlinObjectRenderer.kt b/idea/src/org/jetbrains/jet/plugin/debugger/render/KotlinObjectRenderer.kt index fc217efe79c..ee1c4a83d82 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/render/KotlinObjectRenderer.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/render/KotlinObjectRenderer.kt @@ -32,8 +32,22 @@ import org.jetbrains.jet.lang.resolve.java.JvmAbi import com.intellij.debugger.ui.tree.ValueDescriptor import com.intellij.debugger.ui.tree.render.DescriptorLabelListener import com.intellij.debugger.settings.NodeRendererSettings +import com.intellij.psi.PsiClass +import com.intellij.psi.JavaPsiFacade +import com.intellij.debugger.SourcePosition +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.debugger.impl.DebuggerContextUtil +import com.intellij.psi.search.GlobalSearchScope +import com.sun.jdi.AbsentInformationException +import com.sun.jdi.ClassNotPreparedException +import com.intellij.psi.PsiElement +import org.jetbrains.jet.lang.psi.JetClass +import org.jetbrains.jet.lang.resolve.java.JvmClassName +import com.sun.jdi.ReferenceType +import org.jetbrains.jet.codegen.AsmUtil +import org.jetbrains.jet.lang.psi.JetClassOrObject -public class KotlinObjectRenderer : ClassRenderer() { +public open class KotlinObjectRenderer : ClassRenderer() { override fun isApplicable(jdiType: Type?): Boolean { if (!super.isApplicable(jdiType)) return false @@ -65,18 +79,75 @@ public class KotlinObjectRenderer : ClassRenderer() { } return super.calcLabel(descriptor, evaluationContext, labelListener) } - - private fun Type?.isKotlinClass(): Boolean { - return this is ClassType && this.allInterfaces().any { it.name() == JvmAbi.K_OBJECT.asString() } - } } public class KotlinObjectFieldDescriptor( project: Project?, objRef: ObjectReference?, field: Field? -): FieldDescriptorImpl(project, objRef, field) { - override fun getSourcePosition(project: Project?, context: DebuggerContextImpl?) = null - override fun getSourcePosition(project: Project?, context: DebuggerContextImpl?, nearest: Boolean) = null +) : FieldDescriptorImpl(project, objRef, field) { + override fun getSourcePosition(project: Project?, context: DebuggerContextImpl?, nearest: Boolean): SourcePosition? { + if (context == null || context.getFrameProxy() == null) return null + + val fieldName = getField().name() + if (fieldName == AsmUtil.CAPTURED_THIS_FIELD || fieldName == AsmUtil.CAPTURED_RECEIVER_FIELD) { + return null + } + + val type = getField().declaringType() + val myClass = findClassByType(type, context)?.getNavigationElement() + if (myClass !is JetClassOrObject) { + return null + } + + val field = myClass.getDeclarations().firstOrNull { fieldName == it.getName() } + if (field == null) return null + + if (nearest) { + return DebuggerContextUtil.findNearest(context, field, myClass.getContainingFile()) + } + return SourcePosition.createFromOffset(field.getContainingFile(), field.getTextOffset()) + } + + private fun findClassByType(type: ReferenceType, context: DebuggerContextImpl): PsiElement? { + val session = context.getDebuggerSession() + val scope = if (session != null) session.getSearchScope() else GlobalSearchScope.allScope(myProject) + val className = JvmClassName.byInternalName(type.name()).getFqNameForClassNameWithoutDollars().asString() + + val myClass = JavaPsiFacade.getInstance(myProject).findClass(className, scope) + if (myClass != null) return myClass + + val position = getLastSourcePosition(type, context) + if (position != null) { + val element = position.getElementAt() + if (element != null) { + return PsiTreeUtil.getParentOfType(element, javaClass()) + } + } + return null + } + + + private fun getLastSourcePosition(type: ReferenceType, context: DebuggerContextImpl): SourcePosition? { + val debugProcess = context.getDebugProcess() + if (debugProcess != null) { + try { + val locations = type.allLineLocations() + if (!locations.isEmpty()) { + val lastLocation = locations.get(locations.size() - 1) + return debugProcess.getPositionManager().getSourcePosition(lastLocation) + } + } + catch (ignored: AbsentInformationException) { + } + catch (ignored: ClassNotPreparedException) { + } + } + return null + } +} + +private fun Type?.isKotlinClass(): Boolean { + return this is ClassType && this.allInterfaces().any { it.name() == JvmAbi.K_OBJECT.asString() } } diff --git a/idea/testData/debugger/tinyApp/outs/delegatedPropertyInClass.out b/idea/testData/debugger/tinyApp/outs/delegatedPropertyInClass.out index 74fb8cbfec3..447f9c40a3f 100644 --- a/idea/testData/debugger/tinyApp/outs/delegatedPropertyInClass.out +++ b/idea/testData/debugger/tinyApp/outs/delegatedPropertyInClass.out @@ -30,13 +30,13 @@ class MyDelegateThrowsException { static = static = delegatedPropertyInClass.DelegatedPropertyInClassPackage$@packagePartHASH local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} local = a: delegatedPropertyInClass.A = {delegatedPropertyInClass.A@uniqueID} - field = prop$delegate: delegatedPropertyInClass.MyDelegate = {delegatedPropertyInClass.MyDelegate@uniqueID} + field = prop$delegate: delegatedPropertyInClass.MyDelegate = {delegatedPropertyInClass.MyDelegate@uniqueID} (sp = null) field = prop: int = 1 - field = propEx$delegate: delegatedPropertyInClass.MyDelegateThrowsException = {delegatedPropertyInClass.MyDelegateThrowsException@uniqueID} + field = propEx$delegate: delegatedPropertyInClass.MyDelegateThrowsException = {delegatedPropertyInClass.MyDelegateThrowsException@uniqueID} (sp = null) field = propEx: java.lang.IllegalStateException = {java.lang.IllegalStateException@uniqueID}java.lang.IllegalStateException - field = detailMessage: java.lang.String = null - field = cause: java.lang.Throwable = {java.lang.IllegalStateException@uniqueID}java.lang.IllegalStateException - field = stackTrace: java.lang.StackTraceElement[] = null + field = detailMessage: java.lang.String = null (sp = Throwable.!EXT!) + field = cause: java.lang.Throwable = {java.lang.IllegalStateException@uniqueID}java.lang.IllegalStateException (sp = Throwable.!EXT!) + field = stackTrace: java.lang.StackTraceElement[] = null (sp = Throwable.!EXT!) 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/outs/frameAnonymousObject.out b/idea/testData/debugger/tinyApp/outs/frameAnonymousObject.out index 7c919496be2..a3bd0fcf3f3 100644 --- a/idea/testData/debugger/tinyApp/outs/frameAnonymousObject.out +++ b/idea/testData/debugger/tinyApp/outs/frameAnonymousObject.out @@ -27,9 +27,9 @@ fun foo(f: () -> Unit) { // PRINT_FRAME frame = invoke():11, FrameAnonymousObjectPackage$@packagePartHASH$main$o$1$run$1 {frameAnonymousObject} this = this = {frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1$run$1@uniqueID}kotlin.Function0 - field = this$0: frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1 = {frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1@uniqueID} - field = obProp: int = 1 - field = $val1: int = 1 + field = this$0: frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1 = {frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1@uniqueID} (sp = null) + field = obProp: int = 1 (sp = frameAnonymousObject.kt, 5) + field = $val1: int = 1 (sp = null) 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/outs/frameExtFunExtFun.out b/idea/testData/debugger/tinyApp/outs/frameExtFunExtFun.out index 8a04aae47cc..49b4739293e 100644 --- a/idea/testData/debugger/tinyApp/outs/frameExtFunExtFun.out +++ b/idea/testData/debugger/tinyApp/outs/frameExtFunExtFun.out @@ -70,16 +70,16 @@ fun lambda(f: () -> Unit) { // RESULT: 1: I frame = invoke():22, Outer$foo$LocalClass$test$1 {frameExtFunExtFun} this = this = {frameExtFunExtFun.Outer$foo$LocalClass$test$1@uniqueID}kotlin.Function0 - field = this$0: frameExtFunExtFun.Outer$foo$LocalClass = {frameExtFunExtFun.Outer$foo$LocalClass@uniqueID} - field = lcProp: int = 1 - field = this$0: frameExtFunExtFun.Outer = {frameExtFunExtFun.Outer@uniqueID} - field = outerProp: int = 1 - field = receiver$0: frameExtFunExtFun.A = {frameExtFunExtFun.A@uniqueID} - field = aProp: int = 1 - field = $valFoo: int = 1 - field = receiver$0: frameExtFunExtFun.B = {frameExtFunExtFun.B@uniqueID} - field = bProp: int = 1 - field = $valTest: int = 1 + field = this$0: frameExtFunExtFun.Outer$foo$LocalClass = {frameExtFunExtFun.Outer$foo$LocalClass@uniqueID} (sp = null) + field = lcProp: int = 1 (sp = frameExtFunExtFun.kt, 16) + field = this$0: frameExtFunExtFun.Outer = {frameExtFunExtFun.Outer@uniqueID} (sp = null) + field = outerProp: int = 1 (sp = frameExtFunExtFun.kt, 11) + field = receiver$0: frameExtFunExtFun.A = {frameExtFunExtFun.A@uniqueID} (sp = null) + field = aProp: int = 1 (sp = frameExtFunExtFun.kt, 7) + field = $valFoo: int = 1 (sp = null) + field = receiver$0: frameExtFunExtFun.B = {frameExtFunExtFun.B@uniqueID} (sp = null) + field = bProp: int = 1 (sp = frameExtFunExtFun.kt, 38) + field = $valTest: int = 1 (sp = null) 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/outs/frameExtensionFun.out b/idea/testData/debugger/tinyApp/outs/frameExtensionFun.out index 8b9514ba5e3..a991a076b7b 100644 --- a/idea/testData/debugger/tinyApp/outs/frameExtensionFun.out +++ b/idea/testData/debugger/tinyApp/outs/frameExtensionFun.out @@ -25,7 +25,7 @@ fun A.foo() { frame = foo():13, FrameExtensionFunPackage$@packagePartHASH {frameExtensionFun} static = static = frameExtensionFun.FrameExtensionFunPackage$@packagePartHASH local = $receiver: frameExtensionFun.A = {frameExtensionFun.A@uniqueID} - field = prop: int = 1 + field = prop: int = 1 (sp = frameExtensionFun.kt, 7) 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/outs/frameInnerClass.out b/idea/testData/debugger/tinyApp/outs/frameInnerClass.out index 09b2940bc5d..4e805ac7b57 100644 --- a/idea/testData/debugger/tinyApp/outs/frameInnerClass.out +++ b/idea/testData/debugger/tinyApp/outs/frameInnerClass.out @@ -32,9 +32,9 @@ class A { // RESULT: 1: I frame = test():15, A$Inner {frameInnerClass} this = this = {frameInnerClass.A$Inner@uniqueID} - field = prop2: int = 1 - field = this$0: frameInnerClass.A = {frameInnerClass.A@uniqueID} - field = prop1: int = 1 + field = prop2: int = 1 (sp = frameInnerClass.kt, 10) + field = this$0: frameInnerClass.A = {frameInnerClass.A@uniqueID} (sp = null) + field = prop1: int = 1 (sp = frameInnerClass.kt, 7) 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/outs/frameInnerLambda.out b/idea/testData/debugger/tinyApp/outs/frameInnerLambda.out index 7d2943e8d25..d8be7f51a30 100644 --- a/idea/testData/debugger/tinyApp/outs/frameInnerLambda.out +++ b/idea/testData/debugger/tinyApp/outs/frameInnerLambda.out @@ -34,9 +34,9 @@ fun foo(f: () -> Unit) { // RESULT: 2: I frame = invoke():9, FrameInnerLambdaPackage$@packagePartHASH$main$1$1 {frameInnerLambda} this = this = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1$1@uniqueID}kotlin.Function0 - field = this$0: frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1 = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0 - field = $val1: int = 1 - field = $val2: int = 1 + field = this$0: frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1 = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0 (sp = null) + field = $val1: int = 1 (sp = null) + field = $val2: int = 1 (sp = null) 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/outs/frameLambda.out b/idea/testData/debugger/tinyApp/outs/frameLambda.out index 9c05801b552..9cb1d75f1c2 100644 --- a/idea/testData/debugger/tinyApp/outs/frameLambda.out +++ b/idea/testData/debugger/tinyApp/outs/frameLambda.out @@ -23,7 +23,7 @@ fun foo(f: () -> Unit) { // RESULT: 1: I frame = invoke():7, FrameLambdaPackage$@packagePartHASH$main$1 {frameLambda} this = this = {frameLambda.FrameLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0 - field = $val1: int = 1 + field = $val1: int = 1 (sp = null) 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/outs/frameSharedVar.out b/idea/testData/debugger/tinyApp/outs/frameSharedVar.out index 980d9fad51c..1e006bc9f57 100644 --- a/idea/testData/debugger/tinyApp/outs/frameSharedVar.out +++ b/idea/testData/debugger/tinyApp/outs/frameSharedVar.out @@ -23,8 +23,8 @@ fun foo(f: () -> Unit) { // RESULT: 1: I frame = invoke():7, FrameSharedVarPackage$@packagePartHASH$main$1 {frameSharedVar} this = this = {frameSharedVar.FrameSharedVarPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0 - field = $var1: kotlin.jvm.internal.Ref$IntRef = {kotlin.jvm.internal.Ref$IntRef@uniqueID}1 - field = element: int = 1 + field = $var1: kotlin.jvm.internal.Ref$IntRef = {kotlin.jvm.internal.Ref$IntRef@uniqueID}1 (sp = null) + field = element: int = 1 (sp = Ref.!EXT!) 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/outs/frameSharedVarLocalVar.out b/idea/testData/debugger/tinyApp/outs/frameSharedVarLocalVar.out index bd9f545a74a..db8d43902dd 100644 --- a/idea/testData/debugger/tinyApp/outs/frameSharedVarLocalVar.out +++ b/idea/testData/debugger/tinyApp/outs/frameSharedVarLocalVar.out @@ -25,7 +25,7 @@ inline fun foo(f: () -> Unit) { static = static = frameSharedVarLocalVar.FrameSharedVarLocalVarPackage$@packagePartHASH local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} local = var1: kotlin.jvm.internal.Ref$IntRef = {kotlin.jvm.internal.Ref$IntRef@uniqueID}1 - field = element: int = 1 + field = element: int = 1 (sp = Ref.!EXT!) 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/outs/frameSimple.out b/idea/testData/debugger/tinyApp/outs/frameSimple.out index 4c83e7468d5..8459b23a7a4 100644 --- a/idea/testData/debugger/tinyApp/outs/frameSimple.out +++ b/idea/testData/debugger/tinyApp/outs/frameSimple.out @@ -32,17 +32,17 @@ fun main(args: Array) { // RESULT: 2: I frame = main():9, FrameSimplePackage$@packagePartHASH {frameSimple} static = static = frameSimple.FrameSimplePackage$@packagePartHASH - field = topVal1: int = 1 + field = topVal1: int = 1 (sp = null) local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} local = val1: int = 1 local = val2: java.lang.String = {@uniqueID}str - field = value: char[] = {char[3]@uniqueID} + field = value: char[] = {char[3]@uniqueID} (sp = String.!EXT!) unknown = [0] = 's' 115 unknown = [1] = 't' 116 unknown = [2] = 'r' 114 - field = offset: int = 0 - field = count: int = 3 - field = hash: int = 0 + field = offset: int = 0 (sp = String.!EXT!) + field = count: int = 3 (sp = String.!EXT!) + field = hash: int = 0 (sp = String.!EXT!) 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/outs/frameThis0.out b/idea/testData/debugger/tinyApp/outs/frameThis0.out index 9c6a2d62e38..f3dfddcb743 100644 --- a/idea/testData/debugger/tinyApp/outs/frameThis0.out +++ b/idea/testData/debugger/tinyApp/outs/frameThis0.out @@ -44,9 +44,9 @@ fun foo(f: () -> Unit) { // RESULT: 3: I frame = invoke():15, A$test$1 {frameThis0} this = this = {frameThis0.A$test$1@uniqueID}kotlin.Function0 - field = this$0: frameThis0.A = {frameThis0.A@uniqueID} - field = prop1: int = 1 - field = $val1: int = 1 + field = this$0: frameThis0.A = {frameThis0.A@uniqueID} (sp = null) + field = prop1: int = 1 (sp = frameThis0.kt, 7) + field = $val1: int = 1 (sp = null) local = val2: int = 1 Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' diff --git a/idea/testData/debugger/tinyApp/outs/frameThis0Ext.out b/idea/testData/debugger/tinyApp/outs/frameThis0Ext.out index ba826f9a3e9..68212210229 100644 --- a/idea/testData/debugger/tinyApp/outs/frameThis0Ext.out +++ b/idea/testData/debugger/tinyApp/outs/frameThis0Ext.out @@ -55,11 +55,11 @@ fun foo(f: () -> Unit) { // RESULT: 2: I frame = invoke():14, A$testExt$1 {frameThis0Ext} this = this = {frameThis0Ext.A$testExt$1@uniqueID}kotlin.Function0 - field = this$0: frameThis0Ext.A = {frameThis0Ext.A@uniqueID} - field = prop1: int = 1 - field = receiver$0: frameThis0Ext.AExt = {frameThis0Ext.AExt@uniqueID} - field = prop2: int = 1 - field = $val1: int = 1 + field = this$0: frameThis0Ext.A = {frameThis0Ext.A@uniqueID} (sp = null) + field = prop1: int = 1 (sp = frameThis0Ext.kt, 7) + field = receiver$0: frameThis0Ext.AExt = {frameThis0Ext.AExt@uniqueID} (sp = null) + field = prop2: int = 1 (sp = frameThis0Ext.kt, 23) + field = $val1: int = 1 (sp = null) 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/outs/frameThis0This0.out b/idea/testData/debugger/tinyApp/outs/frameThis0This0.out index 8b0aef3cedf..edf873c7bd9 100644 --- a/idea/testData/debugger/tinyApp/outs/frameThis0This0.out +++ b/idea/testData/debugger/tinyApp/outs/frameThis0This0.out @@ -46,11 +46,11 @@ fun foo(f: () -> Unit) { // RESULT: 3: I frame = invoke():16, A$test$1$1 {frameThis0This0} this = this = {frameThis0This0.A$test$1$1@uniqueID}kotlin.Function0 - field = this$0: frameThis0This0.A$test$1 = {frameThis0This0.A$test$1@uniqueID}kotlin.Function0 - field = this$0: frameThis0This0.A = {frameThis0This0.A@uniqueID} - field = prop1: int = 1 - field = $val1: int = 1 - field = $val2: int = 1 + field = this$0: frameThis0This0.A$test$1 = {frameThis0This0.A$test$1@uniqueID}kotlin.Function0 (sp = null) + field = this$0: frameThis0This0.A = {frameThis0This0.A@uniqueID} (sp = null) + field = prop1: int = 1 (sp = frameThis0This0.kt, 7) + field = $val1: int = 1 (sp = null) + field = $val2: int = 1 (sp = null) Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/tests/org/jetbrains/jet/plugin/debugger/KotlinDebuggerTestBase.kt b/idea/tests/org/jetbrains/jet/plugin/debugger/KotlinDebuggerTestBase.kt index b6fa82d54ac..2f953921f9f 100644 --- a/idea/tests/org/jetbrains/jet/plugin/debugger/KotlinDebuggerTestBase.kt +++ b/idea/tests/org/jetbrains/jet/plugin/debugger/KotlinDebuggerTestBase.kt @@ -26,6 +26,7 @@ import com.intellij.openapi.roots.libraries.LibraryUtil import org.jetbrains.jet.plugin.JetJdkAndLibraryProjectDescriptor import com.intellij.openapi.roots.JdkOrderEntry import com.intellij.openapi.util.io.FileUtil +import com.intellij.debugger.SourcePosition abstract class KotlinDebuggerTestBase : KotlinDebuggerTestCase() { @@ -54,25 +55,29 @@ abstract class KotlinDebuggerTestBase : KotlinDebuggerTestCase() { } val sourcePosition = PositionUtil.getSourcePosition(this) - if (sourcePosition == null) { - return@runReadAction println("SourcePosition is null", ProcessOutputTypes.SYSTEM) - } - - val virtualFile = sourcePosition.getFile().getVirtualFile() - if (virtualFile == null) { - return@runReadAction println("VirtualFile for position is null", ProcessOutputTypes.SYSTEM) - } - - val libraryEntry = LibraryUtil.findLibraryEntry(virtualFile, getProject()) - if (libraryEntry != null && (libraryEntry is JdkOrderEntry || - libraryEntry.getPresentableName() == JetJdkAndLibraryProjectDescriptor.LIBRARY_NAME)) { - return@runReadAction println(FileUtil.getNameWithoutExtension(virtualFile.getName()) + ".!EXT!", ProcessOutputTypes.SYSTEM) - } - - println(virtualFile.getName() + ":" + sourcePosition.getLine(), ProcessOutputTypes.SYSTEM) + println(renderSourcePosition(sourcePosition), ProcessOutputTypes.SYSTEM) } } + protected fun renderSourcePosition(sourcePosition: SourcePosition?): String { + if (sourcePosition == null) { + return "null" + } + + val virtualFile = sourcePosition.getFile().getVirtualFile() + if (virtualFile == null) { + return "VirtualFile for position is null" + } + + val libraryEntry = LibraryUtil.findLibraryEntry(virtualFile, getProject()) + if (libraryEntry != null && (libraryEntry is JdkOrderEntry || + libraryEntry.getPresentableName() == JetJdkAndLibraryProjectDescriptor.LIBRARY_NAME)) { + return FileUtil.getNameWithoutExtension(virtualFile.getName()) + ".!EXT!" + } + + return virtualFile.getName() + ":" + sourcePosition.getLine() + } + protected fun finish() { onBreakpoint { resume(this) diff --git a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt index 72fcaba10a2..862a8a32cb1 100644 --- a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt +++ b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt @@ -58,8 +58,10 @@ import com.intellij.psi.PsiManager import com.intellij.debugger.DebuggerManagerEx import com.intellij.psi.PsiDocumentManager import com.intellij.openapi.application.ModalityState -import com.intellij.debugger.ui.tree.render.ClassRenderer import com.intellij.debugger.settings.NodeRendererSettings +import com.intellij.debugger.ui.impl.watch.FieldDescriptorImpl +import com.intellij.debugger.impl.DebuggerContextImpl +import com.intellij.debugger.SourcePosition public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() { private val logger = Logger.getLogger(javaClass())!! @@ -221,13 +223,17 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB invokeRatherLater(this) { tree.rebuild(debuggerContext) expandAll(tree, Runnable { - PRINTER.printTree(tree) - resume(this@printFrame) + try { + Printer(debuggerContext).printTree(tree) + } + finally { + resume(this@printFrame) + } }) } } - private val PRINTER = object { + private inner class Printer(val debuggerContext: DebuggerContextImpl) { fun printTree(tree: DebuggerTree) { val root = tree.getMutableModel()!!.getRoot() as DebuggerTreeNodeImpl printNode(root, 0) @@ -246,6 +252,8 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB is LocalVariableDescriptor -> logDescriptor(descriptor, "$curIndent local = $label\n") is StaticDescriptor -> logDescriptor(descriptor, "$curIndent static = $label\n") is ThisDescriptorImpl -> logDescriptor(descriptor, "$curIndent this = $label\n") + is FieldDescriptorImpl -> logDescriptor(descriptor, "$curIndent field = $label" + + " (sp = ${render(descriptor.getSourcePosition(myProject, debuggerContext))})\n") is FieldDescriptor -> logDescriptor(descriptor, "$curIndent field = $label\n") else -> logDescriptor(descriptor, "$curIndent unknown = $label\n") } @@ -259,6 +267,10 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB printNode(e.nextElement() as DebuggerTreeNodeImpl, indent) } } + + private fun render(sp: SourcePosition?): String { + return renderSourcePosition(sp).replace(":", ", ") + } } private fun checkExceptions(exceptions: MutableMap) {