Debugger: implement getSourcePosition for fields

This commit is contained in:
Natalia Ukhorskaya
2014-10-21 15:31:30 +04:00
parent 29d73b9302
commit cce22c0df9
17 changed files with 167 additions and 83 deletions
@@ -16,7 +16,6 @@
package org.jetbrains.jet.plugin.debugger.render 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.Type as JdiType
import com.sun.jdi.Value import com.sun.jdi.Value
import com.intellij.debugger.ui.tree.render.ChildrenBuilder 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 com.intellij.debugger.ui.tree.DebuggerTreeNode
import org.jetbrains.org.objectweb.asm.Type as AsmType import org.jetbrains.org.objectweb.asm.Type as AsmType
import com.intellij.debugger.engine.DebuggerManagerThreadImpl import com.intellij.debugger.engine.DebuggerManagerThreadImpl
import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl
import com.sun.jdi.ObjectReference import com.sun.jdi.ObjectReference
import com.intellij.xdebugger.settings.XDebuggerSettingsManager import com.intellij.xdebugger.settings.XDebuggerSettingsManager
import com.intellij.debugger.ui.impl.watch.NodeManagerImpl 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 java.util.ArrayList
import org.jetbrains.jet.lang.resolve.java.JvmAbi import org.jetbrains.jet.lang.resolve.java.JvmAbi
import com.sun.jdi.Field 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.ReferenceType
import com.sun.jdi.Type import com.sun.jdi.Type
import com.sun.jdi.InvocationException import com.sun.jdi.InvocationException
import com.sun.jdi.Method import com.sun.jdi.Method
import org.jetbrains.jet.codegen.PropertyCodegen import org.jetbrains.jet.codegen.PropertyCodegen
import org.jetbrains.jet.lang.resolve.name.Name 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 { override fun isApplicable(jdiType: Type?): Boolean {
if (!super<ClassRenderer>.isApplicable(jdiType)) return false if (!super.isApplicable(jdiType)) return false
if (jdiType !is ReferenceType) return false if (jdiType !is ReferenceType) return false
@@ -72,7 +68,7 @@ public class KotlinClassWithDelegatedPropertyRenderer : ClassRenderer() {
continue 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)) children.add(nodeManager.createNode(fieldDescriptor, context))
if (field.name().endsWith(JvmAbi.DELEGATED_PROPERTY_NAME_SUFFIX)) { if (field.name().endsWith(JvmAbi.DELEGATED_PROPERTY_NAME_SUFFIX)) {
@@ -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.ValueDescriptor
import com.intellij.debugger.ui.tree.render.DescriptorLabelListener import com.intellij.debugger.ui.tree.render.DescriptorLabelListener
import com.intellij.debugger.settings.NodeRendererSettings 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 { override fun isApplicable(jdiType: Type?): Boolean {
if (!super.isApplicable(jdiType)) return false if (!super.isApplicable(jdiType)) return false
@@ -65,18 +79,75 @@ public class KotlinObjectRenderer : ClassRenderer() {
} }
return super.calcLabel(descriptor, evaluationContext, labelListener) 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( public class KotlinObjectFieldDescriptor(
project: Project?, project: Project?,
objRef: ObjectReference?, objRef: ObjectReference?,
field: Field? field: Field?
): FieldDescriptorImpl(project, objRef, field) { ) : FieldDescriptorImpl(project, objRef, field) {
override fun getSourcePosition(project: Project?, context: DebuggerContextImpl?) = null override fun getSourcePosition(project: Project?, context: DebuggerContextImpl?, nearest: Boolean): SourcePosition? {
override fun getSourcePosition(project: Project?, context: DebuggerContextImpl?, nearest: Boolean) = null 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<JetClassOrObject>())
}
}
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() }
} }
@@ -30,13 +30,13 @@ class MyDelegateThrowsException {
static = static = delegatedPropertyInClass.DelegatedPropertyInClassPackage$@packagePartHASH static = static = delegatedPropertyInClass.DelegatedPropertyInClassPackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} local = args: java.lang.String[] = {java.lang.String[0]@uniqueID}
local = a: delegatedPropertyInClass.A = {delegatedPropertyInClass.A@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 = 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 = propEx: java.lang.IllegalStateException = {java.lang.IllegalStateException@uniqueID}java.lang.IllegalStateException
field = detailMessage: java.lang.String = null field = detailMessage: java.lang.String = null (sp = Throwable.!EXT!)
field = cause: java.lang.Throwable = {java.lang.IllegalStateException@uniqueID}java.lang.IllegalStateException field = cause: java.lang.Throwable = {java.lang.IllegalStateException@uniqueID}java.lang.IllegalStateException (sp = Throwable.!EXT!)
field = stackTrace: java.lang.StackTraceElement[] = null field = stackTrace: java.lang.StackTraceElement[] = null (sp = Throwable.!EXT!)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0 Process finished with exit code 0
@@ -27,9 +27,9 @@ fun foo(f: () -> Unit) {
// PRINT_FRAME // PRINT_FRAME
frame = invoke():11, FrameAnonymousObjectPackage$@packagePartHASH$main$o$1$run$1 {frameAnonymousObject} frame = invoke():11, FrameAnonymousObjectPackage$@packagePartHASH$main$o$1$run$1 {frameAnonymousObject}
this = this = {frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1$run$1@uniqueID}kotlin.Function0<kotlin.Unit> this = this = {frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1$run$1@uniqueID}kotlin.Function0<kotlin.Unit>
field = this$0: frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1 = {frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1@uniqueID} field = this$0: frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1 = {frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1@uniqueID} (sp = null)
field = obProp: int = 1 field = obProp: int = 1 (sp = frameAnonymousObject.kt, 5)
field = $val1: int = 1 field = $val1: int = 1 (sp = null)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0 Process finished with exit code 0
@@ -70,16 +70,16 @@ fun lambda(f: () -> Unit) {
// RESULT: 1: I // RESULT: 1: I
frame = invoke():22, Outer$foo$LocalClass$test$1 {frameExtFunExtFun} frame = invoke():22, Outer$foo$LocalClass$test$1 {frameExtFunExtFun}
this = this = {frameExtFunExtFun.Outer$foo$LocalClass$test$1@uniqueID}kotlin.Function0<kotlin.Unit> this = this = {frameExtFunExtFun.Outer$foo$LocalClass$test$1@uniqueID}kotlin.Function0<kotlin.Unit>
field = this$0: frameExtFunExtFun.Outer$foo$LocalClass = {frameExtFunExtFun.Outer$foo$LocalClass@uniqueID} field = this$0: frameExtFunExtFun.Outer$foo$LocalClass = {frameExtFunExtFun.Outer$foo$LocalClass@uniqueID} (sp = null)
field = lcProp: int = 1 field = lcProp: int = 1 (sp = frameExtFunExtFun.kt, 16)
field = this$0: frameExtFunExtFun.Outer = {frameExtFunExtFun.Outer@uniqueID} field = this$0: frameExtFunExtFun.Outer = {frameExtFunExtFun.Outer@uniqueID} (sp = null)
field = outerProp: int = 1 field = outerProp: int = 1 (sp = frameExtFunExtFun.kt, 11)
field = receiver$0: frameExtFunExtFun.A = {frameExtFunExtFun.A@uniqueID} field = receiver$0: frameExtFunExtFun.A = {frameExtFunExtFun.A@uniqueID} (sp = null)
field = aProp: int = 1 field = aProp: int = 1 (sp = frameExtFunExtFun.kt, 7)
field = $valFoo: int = 1 field = $valFoo: int = 1 (sp = null)
field = receiver$0: frameExtFunExtFun.B = {frameExtFunExtFun.B@uniqueID} field = receiver$0: frameExtFunExtFun.B = {frameExtFunExtFun.B@uniqueID} (sp = null)
field = bProp: int = 1 field = bProp: int = 1 (sp = frameExtFunExtFun.kt, 38)
field = $valTest: int = 1 field = $valTest: int = 1 (sp = null)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0 Process finished with exit code 0
@@ -25,7 +25,7 @@ fun A.foo() {
frame = foo():13, FrameExtensionFunPackage$@packagePartHASH {frameExtensionFun} frame = foo():13, FrameExtensionFunPackage$@packagePartHASH {frameExtensionFun}
static = static = frameExtensionFun.FrameExtensionFunPackage$@packagePartHASH static = static = frameExtensionFun.FrameExtensionFunPackage$@packagePartHASH
local = $receiver: frameExtensionFun.A = {frameExtensionFun.A@uniqueID} 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' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0 Process finished with exit code 0
@@ -32,9 +32,9 @@ class A {
// RESULT: 1: I // RESULT: 1: I
frame = test():15, A$Inner {frameInnerClass} frame = test():15, A$Inner {frameInnerClass}
this = this = {frameInnerClass.A$Inner@uniqueID} this = this = {frameInnerClass.A$Inner@uniqueID}
field = prop2: int = 1 field = prop2: int = 1 (sp = frameInnerClass.kt, 10)
field = this$0: frameInnerClass.A = {frameInnerClass.A@uniqueID} field = this$0: frameInnerClass.A = {frameInnerClass.A@uniqueID} (sp = null)
field = prop1: int = 1 field = prop1: int = 1 (sp = frameInnerClass.kt, 7)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0 Process finished with exit code 0
@@ -34,9 +34,9 @@ fun foo(f: () -> Unit) {
// RESULT: 2: I // RESULT: 2: I
frame = invoke():9, FrameInnerLambdaPackage$@packagePartHASH$main$1$1 {frameInnerLambda} frame = invoke():9, FrameInnerLambdaPackage$@packagePartHASH$main$1$1 {frameInnerLambda}
this = this = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1$1@uniqueID}kotlin.Function0<kotlin.Unit> this = this = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1$1@uniqueID}kotlin.Function0<kotlin.Unit>
field = this$0: frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1 = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit> field = this$0: frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1 = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit> (sp = null)
field = $val1: int = 1 field = $val1: int = 1 (sp = null)
field = $val2: int = 1 field = $val2: int = 1 (sp = null)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0 Process finished with exit code 0
@@ -23,7 +23,7 @@ fun foo(f: () -> Unit) {
// RESULT: 1: I // RESULT: 1: I
frame = invoke():7, FrameLambdaPackage$@packagePartHASH$main$1 {frameLambda} frame = invoke():7, FrameLambdaPackage$@packagePartHASH$main$1 {frameLambda}
this = this = {frameLambda.FrameLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit> this = this = {frameLambda.FrameLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit>
field = $val1: int = 1 field = $val1: int = 1 (sp = null)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0 Process finished with exit code 0
@@ -23,8 +23,8 @@ fun foo(f: () -> Unit) {
// RESULT: 1: I // RESULT: 1: I
frame = invoke():7, FrameSharedVarPackage$@packagePartHASH$main$1 {frameSharedVar} frame = invoke():7, FrameSharedVarPackage$@packagePartHASH$main$1 {frameSharedVar}
this = this = {frameSharedVar.FrameSharedVarPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit> this = this = {frameSharedVar.FrameSharedVarPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit>
field = $var1: kotlin.jvm.internal.Ref$IntRef = {kotlin.jvm.internal.Ref$IntRef@uniqueID}1 field = $var1: kotlin.jvm.internal.Ref$IntRef = {kotlin.jvm.internal.Ref$IntRef@uniqueID}1 (sp = null)
field = element: int = 1 field = element: int = 1 (sp = Ref.!EXT!)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0 Process finished with exit code 0
@@ -25,7 +25,7 @@ inline fun foo(f: () -> Unit) {
static = static = frameSharedVarLocalVar.FrameSharedVarLocalVarPackage$@packagePartHASH static = static = frameSharedVarLocalVar.FrameSharedVarLocalVarPackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} local = args: java.lang.String[] = {java.lang.String[0]@uniqueID}
local = var1: kotlin.jvm.internal.Ref$IntRef = {kotlin.jvm.internal.Ref$IntRef@uniqueID}1 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' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0 Process finished with exit code 0
@@ -32,17 +32,17 @@ fun main(args: Array<String>) {
// RESULT: 2: I // RESULT: 2: I
frame = main():9, FrameSimplePackage$@packagePartHASH {frameSimple} frame = main():9, FrameSimplePackage$@packagePartHASH {frameSimple}
static = static = frameSimple.FrameSimplePackage$@packagePartHASH 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 = args: java.lang.String[] = {java.lang.String[0]@uniqueID}
local = val1: int = 1 local = val1: int = 1
local = val2: java.lang.String = {@uniqueID}str 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 = [0] = 's' 115
unknown = [1] = 't' 116 unknown = [1] = 't' 116
unknown = [2] = 'r' 114 unknown = [2] = 'r' 114
field = offset: int = 0 field = offset: int = 0 (sp = String.!EXT!)
field = count: int = 3 field = count: int = 3 (sp = String.!EXT!)
field = hash: int = 0 field = hash: int = 0 (sp = String.!EXT!)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0 Process finished with exit code 0
@@ -44,9 +44,9 @@ fun foo(f: () -> Unit) {
// RESULT: 3: I // RESULT: 3: I
frame = invoke():15, A$test$1 {frameThis0} frame = invoke():15, A$test$1 {frameThis0}
this = this = {frameThis0.A$test$1@uniqueID}kotlin.Function0<kotlin.Unit> this = this = {frameThis0.A$test$1@uniqueID}kotlin.Function0<kotlin.Unit>
field = this$0: frameThis0.A = {frameThis0.A@uniqueID} field = this$0: frameThis0.A = {frameThis0.A@uniqueID} (sp = null)
field = prop1: int = 1 field = prop1: int = 1 (sp = frameThis0.kt, 7)
field = $val1: int = 1 field = $val1: int = 1 (sp = null)
local = val2: int = 1 local = val2: int = 1
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
@@ -55,11 +55,11 @@ fun foo(f: () -> Unit) {
// RESULT: 2: I // RESULT: 2: I
frame = invoke():14, A$testExt$1 {frameThis0Ext} frame = invoke():14, A$testExt$1 {frameThis0Ext}
this = this = {frameThis0Ext.A$testExt$1@uniqueID}kotlin.Function0<kotlin.Unit> this = this = {frameThis0Ext.A$testExt$1@uniqueID}kotlin.Function0<kotlin.Unit>
field = this$0: frameThis0Ext.A = {frameThis0Ext.A@uniqueID} field = this$0: frameThis0Ext.A = {frameThis0Ext.A@uniqueID} (sp = null)
field = prop1: int = 1 field = prop1: int = 1 (sp = frameThis0Ext.kt, 7)
field = receiver$0: frameThis0Ext.AExt = {frameThis0Ext.AExt@uniqueID} field = receiver$0: frameThis0Ext.AExt = {frameThis0Ext.AExt@uniqueID} (sp = null)
field = prop2: int = 1 field = prop2: int = 1 (sp = frameThis0Ext.kt, 23)
field = $val1: int = 1 field = $val1: int = 1 (sp = null)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0 Process finished with exit code 0
@@ -46,11 +46,11 @@ fun foo(f: () -> Unit) {
// RESULT: 3: I // RESULT: 3: I
frame = invoke():16, A$test$1$1 {frameThis0This0} frame = invoke():16, A$test$1$1 {frameThis0This0}
this = this = {frameThis0This0.A$test$1$1@uniqueID}kotlin.Function0<kotlin.Unit> this = this = {frameThis0This0.A$test$1$1@uniqueID}kotlin.Function0<kotlin.Unit>
field = this$0: frameThis0This0.A$test$1 = {frameThis0This0.A$test$1@uniqueID}kotlin.Function0<kotlin.Unit> field = this$0: frameThis0This0.A$test$1 = {frameThis0This0.A$test$1@uniqueID}kotlin.Function0<kotlin.Unit> (sp = null)
field = this$0: frameThis0This0.A = {frameThis0This0.A@uniqueID} field = this$0: frameThis0This0.A = {frameThis0This0.A@uniqueID} (sp = null)
field = prop1: int = 1 field = prop1: int = 1 (sp = frameThis0This0.kt, 7)
field = $val1: int = 1 field = $val1: int = 1 (sp = null)
field = $val2: int = 1 field = $val2: int = 1 (sp = null)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0 Process finished with exit code 0
@@ -26,6 +26,7 @@ import com.intellij.openapi.roots.libraries.LibraryUtil
import org.jetbrains.jet.plugin.JetJdkAndLibraryProjectDescriptor import org.jetbrains.jet.plugin.JetJdkAndLibraryProjectDescriptor
import com.intellij.openapi.roots.JdkOrderEntry import com.intellij.openapi.roots.JdkOrderEntry
import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtil
import com.intellij.debugger.SourcePosition
abstract class KotlinDebuggerTestBase : KotlinDebuggerTestCase() { abstract class KotlinDebuggerTestBase : KotlinDebuggerTestCase() {
@@ -54,25 +55,29 @@ abstract class KotlinDebuggerTestBase : KotlinDebuggerTestCase() {
} }
val sourcePosition = PositionUtil.getSourcePosition(this) val sourcePosition = PositionUtil.getSourcePosition(this)
if (sourcePosition == null) { println(renderSourcePosition(sourcePosition), ProcessOutputTypes.SYSTEM)
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)
} }
} }
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() { protected fun finish() {
onBreakpoint { onBreakpoint {
resume(this) resume(this)
@@ -58,8 +58,10 @@ import com.intellij.psi.PsiManager
import com.intellij.debugger.DebuggerManagerEx import com.intellij.debugger.DebuggerManagerEx
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
import com.intellij.openapi.application.ModalityState import com.intellij.openapi.application.ModalityState
import com.intellij.debugger.ui.tree.render.ClassRenderer
import com.intellij.debugger.settings.NodeRendererSettings 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() { public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
private val logger = Logger.getLogger(javaClass<KotlinEvaluateExpressionCache>())!! private val logger = Logger.getLogger(javaClass<KotlinEvaluateExpressionCache>())!!
@@ -221,13 +223,17 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB
invokeRatherLater(this) { invokeRatherLater(this) {
tree.rebuild(debuggerContext) tree.rebuild(debuggerContext)
expandAll(tree, Runnable { expandAll(tree, Runnable {
PRINTER.printTree(tree) try {
resume(this@printFrame) Printer(debuggerContext).printTree(tree)
}
finally {
resume(this@printFrame)
}
}) })
} }
} }
private val PRINTER = object { private inner class Printer(val debuggerContext: DebuggerContextImpl) {
fun printTree(tree: DebuggerTree) { fun printTree(tree: DebuggerTree) {
val root = tree.getMutableModel()!!.getRoot() as DebuggerTreeNodeImpl val root = tree.getMutableModel()!!.getRoot() as DebuggerTreeNodeImpl
printNode(root, 0) printNode(root, 0)
@@ -246,6 +252,8 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB
is LocalVariableDescriptor -> logDescriptor(descriptor, "$curIndent local = $label\n") is LocalVariableDescriptor -> logDescriptor(descriptor, "$curIndent local = $label\n")
is StaticDescriptor -> logDescriptor(descriptor, "$curIndent static = $label\n") is StaticDescriptor -> logDescriptor(descriptor, "$curIndent static = $label\n")
is ThisDescriptorImpl -> logDescriptor(descriptor, "$curIndent this = $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") is FieldDescriptor -> logDescriptor(descriptor, "$curIndent field = $label\n")
else -> logDescriptor(descriptor, "$curIndent unknown = $label\n") else -> logDescriptor(descriptor, "$curIndent unknown = $label\n")
} }
@@ -259,6 +267,10 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB
printNode(e.nextElement() as DebuggerTreeNodeImpl, indent) printNode(e.nextElement() as DebuggerTreeNodeImpl, indent)
} }
} }
private fun render(sp: SourcePosition?): String {
return renderSourcePosition(sp).replace(":", ", ")
}
} }
private fun checkExceptions(exceptions: MutableMap<String, Throwable>) { private fun checkExceptions(exceptions: MutableMap<String, Throwable>) {