Support new $this_<label> field naming convention in debugger
This commit is contained in:
@@ -94,7 +94,7 @@ public class AsmUtil {
|
||||
|
||||
public static final String THIS = "this";
|
||||
|
||||
private static final String LABELED_THIS_FIELD = THIS + "_";
|
||||
public static final String LABELED_THIS_FIELD = THIS + "_";
|
||||
|
||||
public static final String CAPTURED_THIS_FIELD = "this$0";
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ internal const val DEFAULT_LAMBDA_FAKE_CALL = "$$\$DEFAULT_LAMBDA_FAKE_CALL$$$"
|
||||
internal const val CAPTURED_FIELD_FOLD_PREFIX = "$$$"
|
||||
|
||||
private const val NON_LOCAL_RETURN = "$$$$\$NON_LOCAL_RETURN$$$$$"
|
||||
private const val CAPTURED_FIELD_PREFIX = "$"
|
||||
const val CAPTURED_FIELD_PREFIX = "$"
|
||||
private const val NON_CAPTURED_FIELD_PREFIX = "$$"
|
||||
private const val INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker"
|
||||
private const val INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall"
|
||||
|
||||
+5
-1
@@ -86,7 +86,11 @@ class KotlinSourcePositionProvider: SourcePositionProvider() {
|
||||
|
||||
private fun computeSourcePosition(descriptor: FieldDescriptor, project: Project, context: DebuggerContextImpl, nearest: Boolean): SourcePosition? {
|
||||
val fieldName = descriptor.field.name()
|
||||
if (fieldName == AsmUtil.CAPTURED_THIS_FIELD || fieldName == AsmUtil.CAPTURED_RECEIVER_FIELD) {
|
||||
|
||||
if (fieldName == AsmUtil.CAPTURED_THIS_FIELD
|
||||
|| fieldName == AsmUtil.CAPTURED_RECEIVER_FIELD
|
||||
|| fieldName.startsWith(AsmUtil.LABELED_THIS_FIELD)
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -100,11 +100,11 @@ fun Location.safeMethod(): Method? {
|
||||
return DebuggerUtilsEx.getMethod(this)
|
||||
}
|
||||
|
||||
fun isInsideInlineFunctionBody(visibleVariables: List<LocalVariableProxyImpl>): Boolean {
|
||||
fun isInsideInlineFunctionBody(visibleVariables: List<LocalVariable>): Boolean {
|
||||
return visibleVariables.any { it.name().startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) }
|
||||
}
|
||||
|
||||
fun numberOfInlinedFunctions(visibleVariables: List<LocalVariableProxyImpl>): Int {
|
||||
fun numberOfInlinedFunctions(visibleVariables: List<LocalVariable>): Int {
|
||||
return visibleVariables.count { it.name().startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) }
|
||||
}
|
||||
|
||||
|
||||
@@ -19,14 +19,17 @@ package org.jetbrains.kotlin.idea.debugger.evaluate
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||
import com.intellij.openapi.diagnostic.Attachment
|
||||
import com.intellij.patterns.uast.capture
|
||||
import com.sun.jdi.ClassType
|
||||
import com.sun.jdi.InvalidStackFrameException
|
||||
import com.sun.jdi.ObjectReference
|
||||
import com.sun.jdi.StackFrame
|
||||
import org.jetbrains.eval4j.Value
|
||||
import org.jetbrains.eval4j.jdi.asJdiValue
|
||||
import org.jetbrains.eval4j.jdi.asValue
|
||||
import org.jetbrains.eval4j.obj
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.inline.CAPTURED_FIELD_PREFIX
|
||||
import org.jetbrains.kotlin.codegen.inline.INLINE_FUN_VAR_SUFFIX
|
||||
import org.jetbrains.kotlin.codegen.inline.INLINE_TRANSFORMATION_SUFFIX
|
||||
import org.jetbrains.kotlin.codegen.inline.NUMBERED_FUNCTION_PREFIX
|
||||
@@ -49,12 +52,12 @@ class FrameVisitor(val context: EvaluationContextImpl) {
|
||||
}
|
||||
|
||||
fun findValue(name: String, asmType: Type?, checkType: Boolean, failIfNotFound: Boolean): Value? {
|
||||
if (frame == null) return null
|
||||
val frame = this.frame?.stackFrame ?: return null
|
||||
|
||||
try {
|
||||
when (name) {
|
||||
THIS_NAME -> {
|
||||
val thisValue = findThis(asmType)
|
||||
val thisValue = findThis(frame, asmType)
|
||||
if (thisValue != null) {
|
||||
return thisValue
|
||||
}
|
||||
@@ -125,8 +128,8 @@ class FrameVisitor(val context: EvaluationContextImpl) {
|
||||
throw EvaluateExceptionUtil.createEvaluateException(message)
|
||||
}
|
||||
|
||||
private fun findThis(asmType: Type?): Value? {
|
||||
if (isInsideInlineFunctionBody(frame!!.visibleVariables())) {
|
||||
private fun findThis(frame: StackFrame, asmType: Type?): Value? {
|
||||
if (isInsideInlineFunctionBody(frame.visibleVariables())) {
|
||||
val number = numberOfInlinedFunctions(frame.visibleVariables())
|
||||
val inlineFunVar = findLocalVariableForInlineArgument("this_", number, asmType, true)
|
||||
if (inlineFunVar != null) {
|
||||
@@ -134,18 +137,34 @@ class FrameVisitor(val context: EvaluationContextImpl) {
|
||||
}
|
||||
}
|
||||
|
||||
// Captured labeled 'this'
|
||||
frame.visibleVariables()
|
||||
.asSequence()
|
||||
.filter { it.name().startsWith(AsmUtil.LABELED_THIS_FIELD) }
|
||||
.map { it to frame.getValue(it).asValue() }
|
||||
.filter { isValueOfCorrectType(it.second, asmType, true) }
|
||||
.maxBy { it.first }
|
||||
?.let { return frame.getValue(it.first).asValue() }
|
||||
|
||||
val thisObject = frame.thisObject()
|
||||
if (thisObject != null) {
|
||||
val eval4jValue = thisObject.asValue()
|
||||
if (isValueOfCorrectType(eval4jValue, asmType, true)) return eval4jValue
|
||||
if (isValueOfCorrectType(eval4jValue, asmType, true)) {
|
||||
return eval4jValue
|
||||
}
|
||||
|
||||
findThisInCapturedThis(thisObject, asmType)?.let { return it }
|
||||
}
|
||||
|
||||
// TODO this is probably not needed anymore (covered by 'findThisInCapturedThis')
|
||||
val receiver = findValue(RECEIVER_NAME, asmType, checkType = true, failIfNotFound = false)
|
||||
if (receiver != null) return receiver
|
||||
|
||||
// TODO this is probably not needed anymore (covered by 'findThisInCapturedThis')
|
||||
val this0 = findValue(AsmUtil.CAPTURED_THIS_FIELD, asmType, checkType = true, failIfNotFound = false)
|
||||
if (this0 != null) return this0
|
||||
|
||||
// TODO this is probably not needed anymore (used only in JS)
|
||||
val `$this` = findValue("\$this", asmType, checkType = false, failIfNotFound = false)
|
||||
if (`$this` != null) return `$this`
|
||||
|
||||
@@ -160,6 +179,32 @@ class FrameVisitor(val context: EvaluationContextImpl) {
|
||||
return findLocalVariable(name + INLINE_FUN_VAR_SUFFIX.repeat(number), asmType, checkType)
|
||||
}
|
||||
|
||||
private fun findThisInCapturedThis(capturedThis: ObjectReference, asmType: Type?): Value? {
|
||||
for (field in capturedThis.referenceType().fields()) {
|
||||
val name = field.name()
|
||||
if (name == AsmUtil.CAPTURED_THIS_FIELD) {
|
||||
val value = capturedThis.getValue(field)
|
||||
if (value is ObjectReference) {
|
||||
findThisInCapturedThis(value, asmType)?.let { return it }
|
||||
}
|
||||
}
|
||||
|
||||
if (name.startsWith(CAPTURED_FIELD_PREFIX + AsmUtil.LABELED_THIS_FIELD)
|
||||
|| name == AsmUtil.CAPTURED_RECEIVER_FIELD
|
||||
|| name == AsmUtil.CAPTURED_THIS_FIELD
|
||||
) {
|
||||
val value = capturedThis.getValue(field)
|
||||
val evalValue = value.asValue()
|
||||
|
||||
if (isValueOfCorrectType(evalValue, asmType, true)) {
|
||||
return evalValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun isFunctionType(type: Type?): Boolean {
|
||||
return type?.sort == Type.OBJECT &&
|
||||
type.internalName.startsWith(NUMBERED_FUNCTION_PREFIX)
|
||||
|
||||
+2
-2
@@ -89,10 +89,10 @@ fun lambda(f: () -> Unit) {
|
||||
field = lcProp: int = 1 (sp = frameExtFunExtFun.kt, 19)
|
||||
field = this$0: frameExtFunExtFun.Outer = {frameExtFunExtFun.Outer@uniqueID} (sp = null)
|
||||
field = outerProp: int = 1 (sp = frameExtFunExtFun.kt, 13)
|
||||
field = receiver$0: frameExtFunExtFun.A = {frameExtFunExtFun.A@uniqueID} (sp = null)
|
||||
field = $this_foo: frameExtFunExtFun.A = {frameExtFunExtFun.A@uniqueID} (sp = null)
|
||||
field = aProp: int = 1 (sp = frameExtFunExtFun.kt, 8)
|
||||
field = $valFoo: int = 1 (sp = null)
|
||||
field = receiver$0: frameExtFunExtFun.B = {frameExtFunExtFun.B@uniqueID} (sp = null)
|
||||
field = $this_test: frameExtFunExtFun.B = {frameExtFunExtFun.B@uniqueID} (sp = null)
|
||||
field = bProp: int = 1 (sp = frameExtFunExtFun.kt, 41)
|
||||
field = $valTest: int = 1 (sp = null)
|
||||
field = arity: int = 0 (sp = Lambda.!EXT!)
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ fun foo(f: () -> Unit) {
|
||||
this = this = {frameThis0Ext.A$testExt$1@uniqueID}Function0<kotlin.Unit>
|
||||
field = this$0: frameThis0Ext.A = {frameThis0Ext.A@uniqueID} (sp = null)
|
||||
field = prop1: int = 1 (sp = frameThis0Ext.kt, 8)
|
||||
field = receiver$0: frameThis0Ext.AExt = {frameThis0Ext.AExt@uniqueID} (sp = null)
|
||||
field = $this_testExt: frameThis0Ext.AExt = {frameThis0Ext.AExt@uniqueID} (sp = null)
|
||||
field = prop2: int = 1 (sp = frameThis0Ext.kt, 25)
|
||||
field = $val1: int = 1 (sp = null)
|
||||
field = arity: int = 0 (sp = Lambda.!EXT!)
|
||||
|
||||
Reference in New Issue
Block a user