From 4c681c787daa582cde7ebb60c4a0bf6a0dfd4239 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Fri, 7 Dec 2018 19:58:18 +0900 Subject: [PATCH] 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. --- .../kotlin/idea/debugger/KotlinStackFrame.kt | 84 ++++++++++++++++++- .../debugger/ToggleKotlinVariablesView.kt | 52 ++++++++++++ .../evaluate/KotlinEvaluationBuilder.kt | 9 +- idea/resources/META-INF/jvm.xml | 13 +++ idea/resources/META-INF/jvm.xml.181 | 13 +++ .../frame/frameInlineArgument.out | 2 + .../frameInlineArgumentInsideInlineFun.out | 3 + .../singleBreakpoint/frame/frameInlineFun.out | 1 + .../frameInlineFunCallInsideInlineFun.out | 2 + ...neFunCallInsideInlineFunKotlinVariables.kt | 49 +++++++++++ ...eFunCallInsideInlineFunKotlinVariables.out | 65 ++++++++++++++ .../frame/frameSharedVarLocalVar.out | 2 + .../src/evaluate/singleBreakpoint/kt28087.kt | 16 ++++ .../src/evaluate/singleBreakpoint/kt28087.out | 8 ++ .../AbstractKotlinEvaluateExpressionTest.kt | 8 ++ ...KotlinEvaluateExpressionTestGenerated.java | 10 +++ 16 files changed, 328 insertions(+), 9 deletions(-) create mode 100644 idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/ToggleKotlinVariablesView.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFunKotlinVariables.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFunKotlinVariables.out create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt28087.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt28087.out diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinStackFrame.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinStackFrame.kt index cdd0e384651..b4002f41750 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinStackFrame.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinStackFrame.kt @@ -17,15 +17,93 @@ package org.jetbrains.kotlin.idea.debugger 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.StackFrameProxyImpl import com.intellij.debugger.ui.impl.watch.MethodsTracker 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.idea.debugger.evaluate.THIS_NAME class KotlinStackFrame(frame: StackFrameProxyImpl) : JavaStackFrame(StackFrameDescriptorImpl(frame, MethodsTracker()), true) { - override fun getVisibleVariables(): List? { - return super.getStackFrameProxy().visibleVariablesSafe() - .filter { !isFakeLocalVariableForInline(it.name()) } + private val kotlinVariableViewService = ToggleKotlinVariablesState.getService() + + 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 { + 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) } \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/ToggleKotlinVariablesView.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/ToggleKotlinVariablesView.kt new file mode 100644 index 00000000000..9b29033bb9e --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/ToggleKotlinVariablesView.kt @@ -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) + } +} \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt index 5465f123f47..fc0466fd571 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -470,15 +470,12 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour val parameters = mutableListOf() val receiver = config.descriptor.receiverParameter 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) { - val paramName = when { - param.argumentText.contains("@") -> param.argumentText.substringBefore("@") - param.argumentText.startsWith("::") -> param.argumentText.substring(2) - else -> param.argumentText - } + val argument = param.argumentText + val paramName = if (argument.startsWith("::")) argument.substring(2) else argument val paramDescriptor = param.originalDescriptor if (paramDescriptor is SyntheticFieldDescriptor) { diff --git a/idea/resources/META-INF/jvm.xml b/idea/resources/META-INF/jvm.xml index 93531f8e876..41911ad62a9 100644 --- a/idea/resources/META-INF/jvm.xml +++ b/idea/resources/META-INF/jvm.xml @@ -61,6 +61,17 @@ + + + + + + + + + @@ -77,6 +88,8 @@ + + diff --git a/idea/resources/META-INF/jvm.xml.181 b/idea/resources/META-INF/jvm.xml.181 index bd2bc0ae91d..f8c8d5b573e 100644 --- a/idea/resources/META-INF/jvm.xml.181 +++ b/idea/resources/META-INF/jvm.xml.181 @@ -61,6 +61,17 @@ + + + + + + + + + @@ -77,6 +88,8 @@ + + diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineArgument.out b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineArgument.out index d0dbc055ef2..37c48e10ce3 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineArgument.out +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineArgument.out @@ -33,7 +33,9 @@ class A { local = element: int = 1 (sp = frameInlineArgument.kt, 4) local = this_$iv: frameInlineArgument.A = {frameInlineArgument.A@uniqueID} (sp = null) 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 = $i$a$-inlineFun-FrameInlineArgumentKt$main$1: int = undefined (sp = null) Disconnected from the target VM Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineArgumentInsideInlineFun.out b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineArgumentInsideInlineFun.out index f83f7a12476..16e02b361c0 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineArgumentInsideInlineFun.out +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineArgumentInsideInlineFun.out @@ -47,11 +47,14 @@ fun main(args: Array) { local = element: float = 1.0 (sp = frameInlineArgumentInsideInlineFun.kt, 13) local = this_$iv: frameInlineArgumentInsideInlineFun.B = {frameInlineArgumentInsideInlineFun.B@uniqueID} (sp = null) - Class has no fields + local = $i$f$foo: int = undefined (sp = null) local = element$iv: int = 1 (sp = frameInlineArgumentInsideInlineFun.kt, 13) local = this_$iv$iv: frameInlineArgumentInsideInlineFun.A = {frameInlineArgumentInsideInlineFun.A@uniqueID} (sp = null) - Class has no fields + local = $i$f$inlineFun: int = undefined (sp = null) local = element$iv$iv: double = 1.0 (sp = frameInlineArgumentInsideInlineFun.kt, 13) local = it$iv: int = 1 (sp = null) + local = $i$a$-inlineFun-B$foo$1: int = undefined (sp = null) Disconnected from the target VM Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFun.out b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFun.out index 651d2b0a1f5..1895694d2e2 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFun.out +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFun.out @@ -37,6 +37,7 @@ class A { local = element: int = 1 (sp = frameInlineFun.kt, 12) local = this_$iv: frameInlineFun.A = {frameInlineFun.A@uniqueID} (sp = null) 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) Disconnected from the target VM diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFun.out b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFun.out index 7c8b96a4fbe..a3925327fef 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFun.out +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFun.out @@ -60,11 +60,13 @@ fun main(args: Array) { local = element: float = 1.0 (sp = frameInlineFunCallInsideInlineFun.kt, 5) local = this_$iv: frameInlineFunCallInsideInlineFun.B = {frameInlineFunCallInsideInlineFun.B@uniqueID} (sp = null) - Class has no fields + local = $i$f$foo: int = undefined (sp = null) local = element$iv: int = 2 (sp = frameInlineFunCallInsideInlineFun.kt, 5) local = a$iv: frameInlineFunCallInsideInlineFun.A = {frameInlineFunCallInsideInlineFun.A@uniqueID} (sp = null) field = prop: int = 1 (sp = frameInlineFunCallInsideInlineFun.kt, 10) local = this_$iv$iv: frameInlineFunCallInsideInlineFun.A = {frameInlineFunCallInsideInlineFun.A@uniqueID} (sp = null) 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) Disconnected from the target VM diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFunKotlinVariables.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFunKotlinVariables.kt new file mode 100644 index 00000000000..5918b5b0617 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFunKotlinVariables.kt @@ -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) { + C().bar() +} + +// PRINT_FRAME + +// EXPRESSION: element +// RESULT: 1.0: D + +// EXPRESSION: this.prop +// RESULT: 1: I + diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFunKotlinVariables.out b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFunKotlinVariables.out new file mode 100644 index 00000000000..5f55948332b --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFunKotlinVariables.out @@ -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) { + 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 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameSharedVarLocalVar.out b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameSharedVarLocalVar.out index f96314ab98b..78e6ab556fa 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameSharedVarLocalVar.out +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameSharedVarLocalVar.out @@ -24,6 +24,8 @@ inline fun foo(f: () -> Unit) { frame = main:7, FrameSharedVarLocalVarKt {frameSharedVarLocalVar} local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = frameSharedVarLocalVar.kt, 3) 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 Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt28087.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt28087.kt new file mode 100644 index 00000000000..ac3b2e7ada6 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt28087.kt @@ -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 \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt28087.out b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt28087.out new file mode 100644 index 00000000000..4eaca81f219 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt28087.out @@ -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 diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt index b90db8903ce..f78076a3d4a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt @@ -42,6 +42,7 @@ import org.jetbrains.eval4j.jdi.asValue import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.debugger.KotlinDebuggerTestBase 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.invokeInManagerThread import org.jetbrains.kotlin.idea.util.application.runReadAction @@ -57,6 +58,7 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() { private var appender: AppenderSkeleton? = null private var oldLogLevel: Level? = null + private var oldShowKotlinVariables: Boolean = false private var oldShowFqTypeNames = false override fun setUp() { @@ -66,6 +68,8 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() { oldShowFqTypeNames = classRenderer.SHOW_FQ_TYPE_NAMES classRenderer.SHOW_FQ_TYPE_NAMES = true + oldShowKotlinVariables = ToggleKotlinVariablesState.getService().kotlinVariableView + oldLogLevel = logger.level logger.level = Level.DEBUG @@ -82,6 +86,8 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() { } override fun tearDown() { + ToggleKotlinVariablesState.getService().kotlinVariableView = oldShowKotlinVariables + logger.level = oldLogLevel logger.removeAppender(appender) @@ -104,6 +110,8 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() { val skipInPrintFrame = if (shouldPrintFrame) findListWithPrefixes(fileText, "// SKIP: ") else emptyList() 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 blocks = findFilesWithBlocks(file).map { FileUtil.loadFile(it, true) } diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index 28a833f76a4..4cbdcd095bd 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -231,6 +231,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat 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") public void testKt5554OnlyIntsShouldBeCoerced() throws Exception { 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"); } + @TestMetadata("frameInlineFunCallInsideInlineFunKotlinVariables.kt") + public void testFrameInlineFunCallInsideInlineFunKotlinVariables() throws Exception { + runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFunKotlinVariables.kt"); + } + @TestMetadata("frameInnerClass.kt") public void testFrameInnerClass() throws Exception { runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInnerClass.kt");