Watches: Add Kotlin/JVM views to watches window (KT-28134, KT-28087, KT-22250)
Kotlin mode: show only Kotlin variables and captured values. The variable names are Kotlin-friendly. JVM mode: show all variables available in the current stack position, including synthetic ones.
This commit is contained in:
@@ -17,15 +17,93 @@
|
|||||||
package org.jetbrains.kotlin.idea.debugger
|
package org.jetbrains.kotlin.idea.debugger
|
||||||
|
|
||||||
import com.intellij.debugger.engine.JavaStackFrame
|
import com.intellij.debugger.engine.JavaStackFrame
|
||||||
|
import com.intellij.debugger.engine.JavaValue
|
||||||
|
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||||
import com.intellij.debugger.jdi.LocalVariableProxyImpl
|
import com.intellij.debugger.jdi.LocalVariableProxyImpl
|
||||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||||
import com.intellij.debugger.ui.impl.watch.MethodsTracker
|
import com.intellij.debugger.ui.impl.watch.MethodsTracker
|
||||||
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl
|
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl
|
||||||
|
import com.intellij.xdebugger.frame.XValueChildrenList
|
||||||
|
import com.sun.jdi.Value
|
||||||
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
|
import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_PARAMETER_NAME
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.INLINE_FUN_VAR_SUFFIX
|
||||||
import org.jetbrains.kotlin.codegen.inline.isFakeLocalVariableForInline
|
import org.jetbrains.kotlin.codegen.inline.isFakeLocalVariableForInline
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.evaluate.THIS_NAME
|
||||||
|
|
||||||
class KotlinStackFrame(frame: StackFrameProxyImpl) : JavaStackFrame(StackFrameDescriptorImpl(frame, MethodsTracker()), true) {
|
class KotlinStackFrame(frame: StackFrameProxyImpl) : JavaStackFrame(StackFrameDescriptorImpl(frame, MethodsTracker()), true) {
|
||||||
override fun getVisibleVariables(): List<LocalVariableProxyImpl>? {
|
private val kotlinVariableViewService = ToggleKotlinVariablesState.getService()
|
||||||
return super.getStackFrameProxy().visibleVariablesSafe()
|
|
||||||
.filter { !isFakeLocalVariableForInline(it.name()) }
|
override fun superBuildVariables(evaluationContext: EvaluationContextImpl, children: XValueChildrenList) {
|
||||||
|
if (!kotlinVariableViewService.kotlinVariableView) {
|
||||||
|
return super.superBuildVariables(evaluationContext, children)
|
||||||
|
}
|
||||||
|
|
||||||
|
val nodeManager = evaluationContext.debugProcess.xdebugProcess!!.nodeManager
|
||||||
|
|
||||||
|
fun addItem(variable: LocalVariableProxyImpl) {
|
||||||
|
val variableDescriptor = nodeManager.getLocalVariableDescriptor(null, variable)
|
||||||
|
children.add(JavaValue.create(null, variableDescriptor, evaluationContext, nodeManager, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
val (thisReferences, otherVariables) = visibleVariables
|
||||||
|
.partition { it.name() == THIS_NAME || it.name().startsWith("$THIS_NAME ") }
|
||||||
|
|
||||||
|
thisReferences.forEach(::addItem)
|
||||||
|
otherVariables.forEach(::addItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getVisibleVariables(): List<LocalVariableProxyImpl> {
|
||||||
|
val allVisibleVariables = super.getStackFrameProxy().safeVisibleVariables()
|
||||||
|
|
||||||
|
if (!kotlinVariableViewService.kotlinVariableView) {
|
||||||
|
return allVisibleVariables.map { variable ->
|
||||||
|
if (isFakeLocalVariableForInline(variable.name())) variable.wrapSyntheticInlineVariable() else variable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allVisibleVariables.asSequence()
|
||||||
|
.filter { !isHidden(it) }
|
||||||
|
.map { remapVariableName(it) }
|
||||||
|
.distinctBy { it.name() }
|
||||||
|
.toList()
|
||||||
|
.sortedBy { it.variable }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isHidden(variable: LocalVariableProxyImpl): Boolean {
|
||||||
|
val name = variable.name()
|
||||||
|
return isFakeLocalVariableForInline(name)
|
||||||
|
|| name.endsWith(INLINE_FUN_VAR_SUFFIX)
|
||||||
|
|| name == CONTINUATION_PARAMETER_NAME.asString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun remapVariableName(variable: LocalVariableProxyImpl) = with(variable) {
|
||||||
|
when {
|
||||||
|
isLabeledThisReference() -> {
|
||||||
|
val label = variable.name().drop(AsmUtil.LABELED_THIS_PARAMETER.length)
|
||||||
|
clone(withName = "$THIS_NAME (@$label)")
|
||||||
|
}
|
||||||
|
else -> variable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun LocalVariableProxyImpl.isLabeledThisReference(): Boolean {
|
||||||
|
@Suppress("ConvertToStringTemplate")
|
||||||
|
return name().startsWith(AsmUtil.LABELED_THIS_PARAMETER)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun LocalVariableProxyImpl.clone(withName: String): LocalVariableProxyImpl {
|
||||||
|
return object : LocalVariableProxyImpl(frame, variable) {
|
||||||
|
override fun name() = withName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun LocalVariableProxyImpl.wrapSyntheticInlineVariable(): LocalVariableProxyImpl {
|
||||||
|
val proxyWrapper = object : StackFrameProxyImpl(frame.threadProxy(), frame.stackFrame, frame.indexFromBottom) {
|
||||||
|
override fun getValue(localVariable: LocalVariableProxyImpl): Value {
|
||||||
|
return frame.virtualMachine.mirrorOfVoid()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return LocalVariableProxyImpl(proxyWrapper, variable)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.debugger
|
||||||
|
|
||||||
|
import com.intellij.ide.util.PropertiesComponent
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||||
|
import com.intellij.openapi.actionSystem.ToggleAction
|
||||||
|
import com.intellij.openapi.components.ServiceManager
|
||||||
|
import com.intellij.xdebugger.XDebugSession
|
||||||
|
import com.intellij.xdebugger.impl.XDebuggerUtilImpl
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinFileTypeFactory
|
||||||
|
|
||||||
|
class ToggleKotlinVariablesState {
|
||||||
|
companion object {
|
||||||
|
private const val KOTLIN_VARIABLE_VIEW = "debugger.kotlin.variable.view"
|
||||||
|
|
||||||
|
fun getService(): ToggleKotlinVariablesState {
|
||||||
|
return ServiceManager.getService(ToggleKotlinVariablesState::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var kotlinVariableView = PropertiesComponent.getInstance().getBoolean(KOTLIN_VARIABLE_VIEW, true)
|
||||||
|
set(newValue) {
|
||||||
|
field = newValue
|
||||||
|
PropertiesComponent.getInstance().setValue(KOTLIN_VARIABLE_VIEW, newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ToggleKotlinVariablesView : ToggleAction() {
|
||||||
|
private val kotlinVariableViewService = ToggleKotlinVariablesState.getService()
|
||||||
|
|
||||||
|
override fun update(e: AnActionEvent) {
|
||||||
|
super.update(e)
|
||||||
|
val session = XDebugSession.DATA_KEY.getData(e.dataContext)
|
||||||
|
e.presentation.isEnabledAndVisible = session != null && session.isInKotlinFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun XDebugSession.isInKotlinFile(): Boolean {
|
||||||
|
val fileExtension = currentPosition?.file?.extension ?: return false
|
||||||
|
return fileExtension in KotlinFileTypeFactory.KOTLIN_EXTENSIONS
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isSelected(e: AnActionEvent) = kotlinVariableViewService.kotlinVariableView
|
||||||
|
|
||||||
|
override fun setSelected(e: AnActionEvent, state: Boolean) {
|
||||||
|
kotlinVariableViewService.kotlinVariableView = state
|
||||||
|
XDebuggerUtilImpl.rebuildAllSessionsViews(e.project)
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-6
@@ -470,15 +470,12 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
|
|||||||
val parameters = mutableListOf<Parameter>()
|
val parameters = mutableListOf<Parameter>()
|
||||||
val receiver = config.descriptor.receiverParameter
|
val receiver = config.descriptor.receiverParameter
|
||||||
if (receiver != null) {
|
if (receiver != null) {
|
||||||
parameters += Parameter(THIS_NAME, receiver.getParameterType(true))
|
parameters += Parameter(THIS_NAME + "@" + config.descriptor.name, receiver.getParameterType(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
for (param in config.descriptor.parameters) {
|
for (param in config.descriptor.parameters) {
|
||||||
val paramName = when {
|
val argument = param.argumentText
|
||||||
param.argumentText.contains("@") -> param.argumentText.substringBefore("@")
|
val paramName = if (argument.startsWith("::")) argument.substring(2) else argument
|
||||||
param.argumentText.startsWith("::") -> param.argumentText.substring(2)
|
|
||||||
else -> param.argumentText
|
|
||||||
}
|
|
||||||
|
|
||||||
val paramDescriptor = param.originalDescriptor
|
val paramDescriptor = param.originalDescriptor
|
||||||
if (paramDescriptor is SyntheticFieldDescriptor) {
|
if (paramDescriptor is SyntheticFieldDescriptor) {
|
||||||
|
|||||||
@@ -61,6 +61,17 @@
|
|||||||
<action id="AddToProblemApiInspection" class="org.jetbrains.kotlin.idea.inspections.api.AddIncompatibleApiAction"
|
<action id="AddToProblemApiInspection" class="org.jetbrains.kotlin.idea.inspections.api.AddIncompatibleApiAction"
|
||||||
text="Report as incompatible API">
|
text="Report as incompatible API">
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
<group id="Kotlin.XDebugger.Actions">
|
||||||
|
<action id="Kotlin.XDebugger.ToggleKotlinVariableView"
|
||||||
|
class="org.jetbrains.kotlin.idea.debugger.ToggleKotlinVariablesView"
|
||||||
|
icon="/org/jetbrains/kotlin/idea/icons/kotlin.png"/>
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<group id="Kotlin.XDebugger.Watches.Tree.Toolbar">
|
||||||
|
<reference ref="Kotlin.XDebugger.ToggleKotlinVariableView"/>
|
||||||
|
<add-to-group group-id="XDebugger.Watches.Tree.Toolbar" relative-to-action="XDebugger.SwitchWatchesInVariables" anchor="after"/>
|
||||||
|
</group>
|
||||||
</actions>
|
</actions>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="com.intellij">
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
@@ -77,6 +88,8 @@
|
|||||||
|
|
||||||
<projectService serviceImplementation="org.jetbrains.kotlin.idea.versions.SuppressNotificationState"/>
|
<projectService serviceImplementation="org.jetbrains.kotlin.idea.versions.SuppressNotificationState"/>
|
||||||
|
|
||||||
|
<applicationService serviceImplementation="org.jetbrains.kotlin.idea.debugger.ToggleKotlinVariablesState"/>
|
||||||
|
|
||||||
<debugger.jvmSmartStepIntoHandler implementation="org.jetbrains.kotlin.idea.debugger.stepping.KotlinSmartStepIntoHandler"/>
|
<debugger.jvmSmartStepIntoHandler implementation="org.jetbrains.kotlin.idea.debugger.stepping.KotlinSmartStepIntoHandler"/>
|
||||||
<debugger.positionManagerFactory implementation="org.jetbrains.kotlin.idea.debugger.KotlinPositionManagerFactory"/>
|
<debugger.positionManagerFactory implementation="org.jetbrains.kotlin.idea.debugger.KotlinPositionManagerFactory"/>
|
||||||
<debugger.codeFragmentFactory implementation="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory"/>
|
<debugger.codeFragmentFactory implementation="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory"/>
|
||||||
|
|||||||
@@ -61,6 +61,17 @@
|
|||||||
<action id="AddToProblemApiInspection" class="org.jetbrains.kotlin.idea.inspections.api.AddIncompatibleApiAction"
|
<action id="AddToProblemApiInspection" class="org.jetbrains.kotlin.idea.inspections.api.AddIncompatibleApiAction"
|
||||||
text="Report as incompatible API">
|
text="Report as incompatible API">
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
<group id="Kotlin.XDebugger.Actions">
|
||||||
|
<action id="Kotlin.XDebugger.ToggleKotlinVariableView"
|
||||||
|
class="org.jetbrains.kotlin.idea.debugger.ToggleKotlinVariablesView"
|
||||||
|
icon="/org/jetbrains/kotlin/idea/icons/kotlin.png"/>
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<group id="Kotlin.XDebugger.Watches.Tree.Toolbar">
|
||||||
|
<reference ref="Kotlin.XDebugger.ToggleKotlinVariableView"/>
|
||||||
|
<add-to-group group-id="XDebugger.Watches.Tree.Toolbar" relative-to-action="XDebugger.SwitchWatchesInVariables" anchor="after"/>
|
||||||
|
</group>
|
||||||
</actions>
|
</actions>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="com.intellij">
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
@@ -77,6 +88,8 @@
|
|||||||
|
|
||||||
<projectService serviceImplementation="org.jetbrains.kotlin.idea.versions.SuppressNotificationState"/>
|
<projectService serviceImplementation="org.jetbrains.kotlin.idea.versions.SuppressNotificationState"/>
|
||||||
|
|
||||||
|
<applicationService serviceImplementation="org.jetbrains.kotlin.idea.debugger.ToggleKotlinVariablesState"/>
|
||||||
|
|
||||||
<debugger.jvmSmartStepIntoHandler implementation="org.jetbrains.kotlin.idea.debugger.stepping.KotlinSmartStepIntoHandler"/>
|
<debugger.jvmSmartStepIntoHandler implementation="org.jetbrains.kotlin.idea.debugger.stepping.KotlinSmartStepIntoHandler"/>
|
||||||
<debugger.positionManagerFactory implementation="org.jetbrains.kotlin.idea.debugger.KotlinPositionManagerFactory"/>
|
<debugger.positionManagerFactory implementation="org.jetbrains.kotlin.idea.debugger.KotlinPositionManagerFactory"/>
|
||||||
<debugger.codeFragmentFactory implementation="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory"/>
|
<debugger.codeFragmentFactory implementation="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory"/>
|
||||||
|
|||||||
+2
@@ -33,7 +33,9 @@ class A {
|
|||||||
local = element: int = 1 (sp = frameInlineArgument.kt, 4)
|
local = element: int = 1 (sp = frameInlineArgument.kt, 4)
|
||||||
local = this_$iv: frameInlineArgument.A = {frameInlineArgument.A@uniqueID} (sp = null)
|
local = this_$iv: frameInlineArgument.A = {frameInlineArgument.A@uniqueID} (sp = null)
|
||||||
field = prop: int = 1 (sp = frameInlineArgument.kt, 17)
|
field = prop: int = 1 (sp = frameInlineArgument.kt, 17)
|
||||||
|
local = $i$f$inlineFun: int = undefined (sp = null)
|
||||||
local = element$iv: double = 1.0 (sp = frameInlineArgument.kt, 4)
|
local = element$iv: double = 1.0 (sp = frameInlineArgument.kt, 4)
|
||||||
|
local = $i$a$-inlineFun-FrameInlineArgumentKt$main$1: int = undefined (sp = null)
|
||||||
Disconnected from the target VM
|
Disconnected from the target VM
|
||||||
|
|
||||||
Process finished with exit code 0
|
Process finished with exit code 0
|
||||||
|
|||||||
+3
@@ -47,11 +47,14 @@ fun main(args: Array<String>) {
|
|||||||
local = element: float = 1.0 (sp = frameInlineArgumentInsideInlineFun.kt, 13)
|
local = element: float = 1.0 (sp = frameInlineArgumentInsideInlineFun.kt, 13)
|
||||||
local = this_$iv: frameInlineArgumentInsideInlineFun.B = {frameInlineArgumentInsideInlineFun.B@uniqueID} (sp = null)
|
local = this_$iv: frameInlineArgumentInsideInlineFun.B = {frameInlineArgumentInsideInlineFun.B@uniqueID} (sp = null)
|
||||||
- Class has no fields
|
- Class has no fields
|
||||||
|
local = $i$f$foo: int = undefined (sp = null)
|
||||||
local = element$iv: int = 1 (sp = frameInlineArgumentInsideInlineFun.kt, 13)
|
local = element$iv: int = 1 (sp = frameInlineArgumentInsideInlineFun.kt, 13)
|
||||||
local = this_$iv$iv: frameInlineArgumentInsideInlineFun.A = {frameInlineArgumentInsideInlineFun.A@uniqueID} (sp = null)
|
local = this_$iv$iv: frameInlineArgumentInsideInlineFun.A = {frameInlineArgumentInsideInlineFun.A@uniqueID} (sp = null)
|
||||||
- Class has no fields
|
- Class has no fields
|
||||||
|
local = $i$f$inlineFun: int = undefined (sp = null)
|
||||||
local = element$iv$iv: double = 1.0 (sp = frameInlineArgumentInsideInlineFun.kt, 13)
|
local = element$iv$iv: double = 1.0 (sp = frameInlineArgumentInsideInlineFun.kt, 13)
|
||||||
local = it$iv: int = 1 (sp = null)
|
local = it$iv: int = 1 (sp = null)
|
||||||
|
local = $i$a$-inlineFun-B$foo$1: int = undefined (sp = null)
|
||||||
Disconnected from the target VM
|
Disconnected from the target VM
|
||||||
|
|
||||||
Process finished with exit code 0
|
Process finished with exit code 0
|
||||||
|
|||||||
+1
@@ -37,6 +37,7 @@ class A {
|
|||||||
local = element: int = 1 (sp = frameInlineFun.kt, 12)
|
local = element: int = 1 (sp = frameInlineFun.kt, 12)
|
||||||
local = this_$iv: frameInlineFun.A = {frameInlineFun.A@uniqueID} (sp = null)
|
local = this_$iv: frameInlineFun.A = {frameInlineFun.A@uniqueID} (sp = null)
|
||||||
field = prop: int = 1 (sp = frameInlineFun.kt, 17)
|
field = prop: int = 1 (sp = frameInlineFun.kt, 17)
|
||||||
|
local = $i$f$inlineFun: int = undefined (sp = null)
|
||||||
local = element$iv: double = 1.0 (sp = frameInlineFun.kt, 12)
|
local = element$iv: double = 1.0 (sp = frameInlineFun.kt, 12)
|
||||||
Disconnected from the target VM
|
Disconnected from the target VM
|
||||||
|
|
||||||
|
|||||||
+2
@@ -60,11 +60,13 @@ fun main(args: Array<String>) {
|
|||||||
local = element: float = 1.0 (sp = frameInlineFunCallInsideInlineFun.kt, 5)
|
local = element: float = 1.0 (sp = frameInlineFunCallInsideInlineFun.kt, 5)
|
||||||
local = this_$iv: frameInlineFunCallInsideInlineFun.B = {frameInlineFunCallInsideInlineFun.B@uniqueID} (sp = null)
|
local = this_$iv: frameInlineFunCallInsideInlineFun.B = {frameInlineFunCallInsideInlineFun.B@uniqueID} (sp = null)
|
||||||
- Class has no fields
|
- Class has no fields
|
||||||
|
local = $i$f$foo: int = undefined (sp = null)
|
||||||
local = element$iv: int = 2 (sp = frameInlineFunCallInsideInlineFun.kt, 5)
|
local = element$iv: int = 2 (sp = frameInlineFunCallInsideInlineFun.kt, 5)
|
||||||
local = a$iv: frameInlineFunCallInsideInlineFun.A = {frameInlineFunCallInsideInlineFun.A@uniqueID} (sp = null)
|
local = a$iv: frameInlineFunCallInsideInlineFun.A = {frameInlineFunCallInsideInlineFun.A@uniqueID} (sp = null)
|
||||||
field = prop: int = 1 (sp = frameInlineFunCallInsideInlineFun.kt, 10)
|
field = prop: int = 1 (sp = frameInlineFunCallInsideInlineFun.kt, 10)
|
||||||
local = this_$iv$iv: frameInlineFunCallInsideInlineFun.A = {frameInlineFunCallInsideInlineFun.A@uniqueID} (sp = null)
|
local = this_$iv$iv: frameInlineFunCallInsideInlineFun.A = {frameInlineFunCallInsideInlineFun.A@uniqueID} (sp = null)
|
||||||
field = prop: int = 1 (sp = frameInlineFunCallInsideInlineFun.kt, 10)
|
field = prop: int = 1 (sp = frameInlineFunCallInsideInlineFun.kt, 10)
|
||||||
|
local = $i$f$inlineFun: int = undefined (sp = null)
|
||||||
local = element$iv$iv: double = 1.0 (sp = frameInlineFunCallInsideInlineFun.kt, 5)
|
local = element$iv$iv: double = 1.0 (sp = frameInlineFunCallInsideInlineFun.kt, 5)
|
||||||
Disconnected from the target VM
|
Disconnected from the target VM
|
||||||
|
|
||||||
|
|||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
// SHOW_KOTLIN_VARIABLES
|
||||||
|
|
||||||
|
package frameInlineFunCallInsideInlineFunKotlinVariables
|
||||||
|
|
||||||
|
class A {
|
||||||
|
inline fun inlineFun(s: (Int) -> Unit) {
|
||||||
|
val element = 1.0
|
||||||
|
//TODO breakpoint here doesn't work (not only in tests)
|
||||||
|
s(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
val prop = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
inline fun foo(s: (Int) -> Unit) {
|
||||||
|
val element = 2
|
||||||
|
val a = A()
|
||||||
|
// STEP_INTO: 1
|
||||||
|
// STEP_OVER: 1
|
||||||
|
//Breakpoint!
|
||||||
|
a.inlineFun {
|
||||||
|
val e = element
|
||||||
|
}
|
||||||
|
s(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
fun bar() {
|
||||||
|
val element = 1f
|
||||||
|
B().foo {
|
||||||
|
val e = element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
C().bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRINT_FRAME
|
||||||
|
|
||||||
|
// EXPRESSION: element
|
||||||
|
// RESULT: 1.0: D
|
||||||
|
|
||||||
|
// EXPRESSION: this.prop
|
||||||
|
// RESULT: 1: I
|
||||||
|
|
||||||
+65
@@ -0,0 +1,65 @@
|
|||||||
|
LineBreakpoint created at frameInlineFunCallInsideInlineFunKotlinVariables.kt:22
|
||||||
|
Run Java
|
||||||
|
Connected to the target VM
|
||||||
|
frameInlineFunCallInsideInlineFunKotlinVariables.kt:22
|
||||||
|
frameInlineFunCallInsideInlineFunKotlinVariables.kt:7
|
||||||
|
frameInlineFunCallInsideInlineFunKotlinVariables.kt:9
|
||||||
|
Compile bytecode for element
|
||||||
|
Compile bytecode for this.prop
|
||||||
|
// SHOW_KOTLIN_VARIABLES
|
||||||
|
|
||||||
|
package frameInlineFunCallInsideInlineFunKotlinVariables
|
||||||
|
|
||||||
|
class A {
|
||||||
|
inline fun inlineFun(s: (Int) -> Unit) {
|
||||||
|
val element = 1.0
|
||||||
|
//TODO breakpoint here doesn't work (not only in tests)
|
||||||
|
s(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
val prop = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
inline fun foo(s: (Int) -> Unit) {
|
||||||
|
val element = 2
|
||||||
|
val a = A()
|
||||||
|
// STEP_INTO: 1
|
||||||
|
// STEP_OVER: 1
|
||||||
|
//Breakpoint!
|
||||||
|
a.inlineFun {
|
||||||
|
val e = element
|
||||||
|
}
|
||||||
|
s(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
fun bar() {
|
||||||
|
val element = 1f
|
||||||
|
B().foo {
|
||||||
|
val e = element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
C().bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRINT_FRAME
|
||||||
|
|
||||||
|
// EXPRESSION: element
|
||||||
|
// RESULT: 1.0: D
|
||||||
|
|
||||||
|
// EXPRESSION: this.prop
|
||||||
|
// RESULT: 1: I
|
||||||
|
|
||||||
|
|
||||||
|
frame = bar:9, C {frameInlineFunCallInsideInlineFunKotlinVariables}
|
||||||
|
this = this = {frameInlineFunCallInsideInlineFunKotlinVariables.C@uniqueID}
|
||||||
|
- Class has no fields
|
||||||
|
local = element: float = 1.0 (sp = frameInlineFunCallInsideInlineFunKotlinVariables.kt, 7)
|
||||||
|
Disconnected from the target VM
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
Vendored
+2
@@ -24,6 +24,8 @@ inline fun foo(f: () -> Unit) {
|
|||||||
frame = main:7, FrameSharedVarLocalVarKt {frameSharedVarLocalVar}
|
frame = main:7, FrameSharedVarLocalVarKt {frameSharedVarLocalVar}
|
||||||
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = frameSharedVarLocalVar.kt, 3)
|
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = frameSharedVarLocalVar.kt, 3)
|
||||||
local = var1: int = 1 (sp = frameSharedVarLocalVar.kt, 4)
|
local = var1: int = 1 (sp = frameSharedVarLocalVar.kt, 4)
|
||||||
|
local = $i$f$foo: int = undefined (sp = null)
|
||||||
|
local = $i$a$-foo-FrameSharedVarLocalVarKt$main$1: int = undefined (sp = null)
|
||||||
Disconnected from the target VM
|
Disconnected from the target VM
|
||||||
|
|
||||||
Process finished with exit code 0
|
Process finished with exit code 0
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package kt28087
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
"a".indexed { index, c ->
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun CharSequence.indexed(action: (index: Int, Char) -> Unit): Unit {
|
||||||
|
var index = 0
|
||||||
|
for (item in this) action(index++, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPRESSION: index
|
||||||
|
// RESULT: 0: I
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
LineBreakpoint created at kt28087.kt:6
|
||||||
|
Run Java
|
||||||
|
Connected to the target VM
|
||||||
|
kt28087.kt:6
|
||||||
|
Compile bytecode for index
|
||||||
|
Disconnected from the target VM
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
+8
@@ -42,6 +42,7 @@ import org.jetbrains.eval4j.jdi.asValue
|
|||||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||||
import org.jetbrains.kotlin.idea.debugger.KotlinDebuggerTestBase
|
import org.jetbrains.kotlin.idea.debugger.KotlinDebuggerTestBase
|
||||||
import org.jetbrains.kotlin.idea.debugger.KotlinFrameExtraVariablesProvider
|
import org.jetbrains.kotlin.idea.debugger.KotlinFrameExtraVariablesProvider
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.ToggleKotlinVariablesState
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.AbstractKotlinEvaluateExpressionTest.PrinterConfig.DescriptorViewOptions
|
import org.jetbrains.kotlin.idea.debugger.evaluate.AbstractKotlinEvaluateExpressionTest.PrinterConfig.DescriptorViewOptions
|
||||||
import org.jetbrains.kotlin.idea.debugger.invokeInManagerThread
|
import org.jetbrains.kotlin.idea.debugger.invokeInManagerThread
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
@@ -57,6 +58,7 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
|
|||||||
private var appender: AppenderSkeleton? = null
|
private var appender: AppenderSkeleton? = null
|
||||||
|
|
||||||
private var oldLogLevel: Level? = null
|
private var oldLogLevel: Level? = null
|
||||||
|
private var oldShowKotlinVariables: Boolean = false
|
||||||
private var oldShowFqTypeNames = false
|
private var oldShowFqTypeNames = false
|
||||||
|
|
||||||
override fun setUp() {
|
override fun setUp() {
|
||||||
@@ -66,6 +68,8 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
|
|||||||
oldShowFqTypeNames = classRenderer.SHOW_FQ_TYPE_NAMES
|
oldShowFqTypeNames = classRenderer.SHOW_FQ_TYPE_NAMES
|
||||||
classRenderer.SHOW_FQ_TYPE_NAMES = true
|
classRenderer.SHOW_FQ_TYPE_NAMES = true
|
||||||
|
|
||||||
|
oldShowKotlinVariables = ToggleKotlinVariablesState.getService().kotlinVariableView
|
||||||
|
|
||||||
oldLogLevel = logger.level
|
oldLogLevel = logger.level
|
||||||
logger.level = Level.DEBUG
|
logger.level = Level.DEBUG
|
||||||
|
|
||||||
@@ -82,6 +86,8 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun tearDown() {
|
override fun tearDown() {
|
||||||
|
ToggleKotlinVariablesState.getService().kotlinVariableView = oldShowKotlinVariables
|
||||||
|
|
||||||
logger.level = oldLogLevel
|
logger.level = oldLogLevel
|
||||||
logger.removeAppender(appender)
|
logger.removeAppender(appender)
|
||||||
|
|
||||||
@@ -104,6 +110,8 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
|
|||||||
val skipInPrintFrame = if (shouldPrintFrame) findListWithPrefixes(fileText, "// SKIP: ") else emptyList()
|
val skipInPrintFrame = if (shouldPrintFrame) findListWithPrefixes(fileText, "// SKIP: ") else emptyList()
|
||||||
val descriptorViewOptions = DescriptorViewOptions.valueOf(findStringWithPrefixes(fileText, "// DESCRIPTOR_VIEW_OPTIONS: ") ?: "FULL")
|
val descriptorViewOptions = DescriptorViewOptions.valueOf(findStringWithPrefixes(fileText, "// DESCRIPTOR_VIEW_OPTIONS: ") ?: "FULL")
|
||||||
|
|
||||||
|
ToggleKotlinVariablesState.getService().kotlinVariableView = isDirectiveDefined(fileText, "// SHOW_KOTLIN_VARIABLES")
|
||||||
|
|
||||||
val expressions = loadTestDirectivesPairs(fileText, "// EXPRESSION: ", "// RESULT: ")
|
val expressions = loadTestDirectivesPairs(fileText, "// EXPRESSION: ", "// RESULT: ")
|
||||||
|
|
||||||
val blocks = findFilesWithBlocks(file).map { FileUtil.loadFile(it, true) }
|
val blocks = findFilesWithBlocks(file).map { FileUtil.loadFile(it, true) }
|
||||||
|
|||||||
Generated
+10
@@ -231,6 +231,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt22366.kt");
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt22366.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt28087.kt")
|
||||||
|
public void testKt28087() throws Exception {
|
||||||
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt28087.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt5554OnlyIntsShouldBeCoerced.kt")
|
@TestMetadata("kt5554OnlyIntsShouldBeCoerced.kt")
|
||||||
public void testKt5554OnlyIntsShouldBeCoerced() throws Exception {
|
public void testKt5554OnlyIntsShouldBeCoerced() throws Exception {
|
||||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt5554OnlyIntsShouldBeCoerced.kt");
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt5554OnlyIntsShouldBeCoerced.kt");
|
||||||
@@ -655,6 +660,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFun.kt");
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFun.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("frameInlineFunCallInsideInlineFunKotlinVariables.kt")
|
||||||
|
public void testFrameInlineFunCallInsideInlineFunKotlinVariables() throws Exception {
|
||||||
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFunKotlinVariables.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("frameInnerClass.kt")
|
@TestMetadata("frameInnerClass.kt")
|
||||||
public void testFrameInnerClass() throws Exception {
|
public void testFrameInnerClass() throws Exception {
|
||||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInnerClass.kt");
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInnerClass.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user