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
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<ClassRenderer>.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)) {
@@ -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<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
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
@@ -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<kotlin.Unit>
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
@@ -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<kotlin.Unit>
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
@@ -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
@@ -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
@@ -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<kotlin.Unit>
field = this$0: frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1 = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit>
field = $val1: int = 1
field = $val2: int = 1
field = this$0: frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1 = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit> (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
@@ -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<kotlin.Unit>
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
@@ -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<kotlin.Unit>
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
@@ -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
@@ -32,17 +32,17 @@ fun main(args: Array<String>) {
// 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
@@ -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<kotlin.Unit>
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'
@@ -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<kotlin.Unit>
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
@@ -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<kotlin.Unit>
field = this$0: frameThis0This0.A$test$1 = {frameThis0This0.A$test$1@uniqueID}kotlin.Function0<kotlin.Unit>
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<kotlin.Unit> (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
@@ -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)
@@ -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<KotlinEvaluateExpressionCache>())!!
@@ -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<String, Throwable>) {