Further refinements in variable displaying (Kotlin mode)
- Remove synthetic outer this for lambdas - Recognize captured this for interface default methods
This commit is contained in:
@@ -30,12 +30,12 @@ import com.sun.jdi.ReferenceType
|
||||
import com.sun.jdi.Type
|
||||
import com.sun.jdi.Value
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.THIS
|
||||
import org.jetbrains.kotlin.codegen.DESTRUCTURED_LAMBDA_ARGUMENT_VARIABLE_PREFIX
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_PARAMETER_NAME
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_VARIABLE_NAME
|
||||
import org.jetbrains.kotlin.codegen.inline.INLINE_FUN_VAR_SUFFIX
|
||||
import org.jetbrains.kotlin.codegen.inline.isFakeLocalVariableForInline
|
||||
import org.jetbrains.kotlin.idea.debugger.evaluate.THIS_NAME
|
||||
import org.jetbrains.kotlin.idea.debugger.evaluate.VariableFinder
|
||||
import org.jetbrains.kotlin.idea.debugger.evaluate.variables.VariableFinder
|
||||
import org.jetbrains.kotlin.utils.getSafe
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util.*
|
||||
@@ -57,9 +57,9 @@ class KotlinStackFrame(frame: StackFrameProxyImpl) : JavaStackFrame(StackFrameDe
|
||||
}
|
||||
|
||||
val (thisReferences, otherVariables) = visibleVariables
|
||||
.partition { it.name() == AsmUtil.THIS || it is ThisLocalVariable }
|
||||
.partition { it.name() == THIS || it is ThisLocalVariable }
|
||||
|
||||
if (!removeThisObjectForContinuation(evaluationContext, children) && thisReferences.isNotEmpty()) {
|
||||
if (!removeSyntheticThisObject(evaluationContext, children) && thisReferences.isNotEmpty()) {
|
||||
val thisLabels = thisReferences.asSequence()
|
||||
.filterIsInstance<ThisLocalVariable>()
|
||||
.mapNotNullTo(hashSetOf()) { it.label }
|
||||
@@ -71,14 +71,22 @@ class KotlinStackFrame(frame: StackFrameProxyImpl) : JavaStackFrame(StackFrameDe
|
||||
otherVariables.forEach(::addItem)
|
||||
}
|
||||
|
||||
private fun removeThisObjectForContinuation(evaluationContext: EvaluationContextImpl, children: XValueChildrenList): Boolean {
|
||||
private fun removeSyntheticThisObject(evaluationContext: EvaluationContextImpl, children: XValueChildrenList): Boolean {
|
||||
val thisObject = evaluationContext.frameProxy?.thisObject() ?: return false
|
||||
if (!thisObject.type().isSubtype(VariableFinder.CONTINUATION_TYPE)) {
|
||||
return false
|
||||
|
||||
|
||||
if (thisObject.type().isSubtype(VariableFinder.CONTINUATION_TYPE)) {
|
||||
ExistingInstanceThis.find(children)?.remove()
|
||||
return true
|
||||
}
|
||||
|
||||
ExistingInstanceThis.find(children)?.remove()
|
||||
return true
|
||||
val thisObjectType = thisObject.type()
|
||||
if (thisObjectType.isSubtype(Function::class.java.name) && '$' in thisObjectType.signature()) {
|
||||
ExistingInstanceThis.find(children)?.remove()
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun remapThisObjectForOuterThis(
|
||||
@@ -190,7 +198,8 @@ class KotlinStackFrame(frame: StackFrameProxyImpl) : JavaStackFrame(StackFrameDe
|
||||
val (thisVariables, otherVariables) = allVisibleVariables.asSequence()
|
||||
.filter { !isHidden(it, inlineDepth) }
|
||||
.partition {
|
||||
it.name() == AsmUtil.THIS
|
||||
it.name() == THIS
|
||||
|| it.name() == AsmUtil.getCapturedFieldName(AsmUtil.THIS)
|
||||
|| it.name().startsWith(AsmUtil.LABELED_THIS_PARAMETER)
|
||||
|| (VariableFinder.inlinedThisRegex.matches(it.name()))
|
||||
}
|
||||
@@ -199,7 +208,7 @@ class KotlinStackFrame(frame: StackFrameProxyImpl) : JavaStackFrame(StackFrameDe
|
||||
.sortedByDescending { it.variable }
|
||||
.let { it.firstOrNull() to it.drop(1) }
|
||||
|
||||
val remappedMainThis = mainThis?.clone(AsmUtil.THIS, null)
|
||||
val remappedMainThis = mainThis?.clone(THIS, null)
|
||||
val remappedOther = (otherThis + otherVariables).map { it.remapVariableNameIfNeeded() }
|
||||
return (listOfNotNull(remappedMainThis) + remappedOther).sortedBy { it.variable }
|
||||
}
|
||||
@@ -216,12 +225,14 @@ class KotlinStackFrame(frame: StackFrameProxyImpl) : JavaStackFrame(StackFrameDe
|
||||
private fun LocalVariableProxyImpl.remapVariableNameIfNeeded(): LocalVariableProxyImpl {
|
||||
val name = this.name().dropInlineSuffix()
|
||||
|
||||
@Suppress("ConvertToStringTemplate")
|
||||
return when {
|
||||
isLabeledThisReference() -> {
|
||||
val label = name.drop(AsmUtil.LABELED_THIS_PARAMETER.length)
|
||||
clone(getThisName(label), label)
|
||||
}
|
||||
name == AsmUtil.RECEIVER_PARAMETER_NAME -> clone(AsmUtil.THIS + " (receiver)", null)
|
||||
name == AsmUtil.getCapturedFieldName(AsmUtil.THIS) -> clone(THIS + " (outer)", null)
|
||||
name == AsmUtil.RECEIVER_PARAMETER_NAME -> clone(THIS + " (receiver)", null)
|
||||
VariableFinder.inlinedThisRegex.matches(name) -> {
|
||||
val label = generateThisLabel(frame.getValue(this)?.type())
|
||||
if (label != null) {
|
||||
@@ -260,7 +271,7 @@ class KotlinStackFrame(frame: StackFrameProxyImpl) : JavaStackFrame(StackFrameDe
|
||||
}
|
||||
|
||||
private fun getThisName(label: String): String {
|
||||
return "$THIS_NAME (@$label)"
|
||||
return "$THIS (@$label)"
|
||||
}
|
||||
|
||||
private fun LocalVariableProxyImpl.clone(name: String, label: String?): LocalVariableProxyImpl {
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package defaultImplsMangling
|
||||
|
||||
interface IFoo {
|
||||
val x: Int
|
||||
|
||||
fun foo() {
|
||||
//Breakpoint!
|
||||
val a = 5
|
||||
}
|
||||
}
|
||||
|
||||
class Foo : IFoo {
|
||||
override val x: Int = 1
|
||||
}
|
||||
|
||||
fun main() {
|
||||
Foo().foo()
|
||||
}
|
||||
|
||||
// SHOW_KOTLIN_VARIABLES
|
||||
// PRINT_FRAME
|
||||
|
||||
// EXPRESSION: x
|
||||
// RESULT: 1: I
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
LineBreakpoint created at defaultImplsMangling.kt:8
|
||||
Run Java
|
||||
Connected to the target VM
|
||||
defaultImplsMangling.kt:8
|
||||
Compile bytecode for x
|
||||
frame = foo:8, IFoo$DefaultImpls {defaultImplsMangling}
|
||||
local = this: defaultImplsMangling.IFoo = {defaultImplsMangling.Foo@uniqueID} (sp = null)
|
||||
field = x: int = 1 (sp = defaultImplsMangling.kt, 13)
|
||||
Disconnected from the target VM
|
||||
|
||||
Process finished with exit code 0
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package lambdaThisMangling
|
||||
|
||||
private fun block(block: (String) -> Unit) {
|
||||
block("foo")
|
||||
}
|
||||
|
||||
fun main() {
|
||||
block { foo ->
|
||||
//Breakpoint!
|
||||
val a = 5
|
||||
}
|
||||
}
|
||||
|
||||
// SHOW_KOTLIN_VARIABLES
|
||||
// PRINT_FRAME
|
||||
|
||||
// EXPRESSION: foo
|
||||
// RESULT: "foo": Ljava/lang/String;
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
LineBreakpoint created at lambdaThisMangling.kt:10
|
||||
Run Java
|
||||
Connected to the target VM
|
||||
lambdaThisMangling.kt:10
|
||||
Compile bytecode for foo
|
||||
frame = invoke:10, LambdaThisManglingKt$main$1 {lambdaThisMangling}
|
||||
local = foo: java.lang.String = foo (sp = lambdaThisMangling.kt, 8)
|
||||
field = value: char[] = {char[3]@uniqueID} (sp = String.!EXT!)
|
||||
element = 0 = 'f' 102
|
||||
element = 1 = 'o' 111
|
||||
element = 2 = 'o' 111
|
||||
field = hash: int = 0 (sp = String.!EXT!)
|
||||
Disconnected from the target VM
|
||||
|
||||
Process finished with exit code 0
|
||||
Generated
+10
@@ -620,6 +620,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/coroutineContextLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultImplsMangling.kt")
|
||||
public void testDefaultImplsMangling() throws Exception {
|
||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/defaultImplsMangling.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("delegatedPropertyInClass.kt")
|
||||
public void testDelegatedPropertyInClass() throws Exception {
|
||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/delegatedPropertyInClass.kt");
|
||||
@@ -760,6 +765,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/lambdaParameterMangling.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lambdaThisMangling.kt")
|
||||
public void testLambdaThisMangling() throws Exception {
|
||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/lambdaThisMangling.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("localFunctionMangling.kt")
|
||||
public void testLocalFunctionMangling() throws Exception {
|
||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/localFunctionMangling.kt");
|
||||
|
||||
Reference in New Issue
Block a user