From 716c9f79f7e52ffdf7c017500ae87a76c7c1c268 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Thu, 10 Oct 2019 21:26:26 +0900 Subject: [PATCH] Debugger: Do not use expression code fragments for evaluator (KT-32736, KT-32741) It seems like it doesn't make much sense to create expression code fragments. People type statements or several expressions separated with a semicolon to a single-line expression line. That is exactly what block code fragment was designed for. --- .../evaluate/KotlinCodeFragmentFactory.kt | 11 ++----- .../evaluate/KotlinEvaluatorBuilder.kt | 30 ++++++++++++------- ...KotlinEvaluateExpressionTestGenerated.java | 10 +++++++ .../singleBreakpoint/functionDeclaration.kt | 9 ++++++ .../singleBreakpoint/functionDeclaration.out | 8 +++++ .../evaluation/singleBreakpoint/statements.kt | 9 ++++++ .../singleBreakpoint/statements.out | 8 +++++ 7 files changed, 66 insertions(+), 19 deletions(-) create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/functionDeclaration.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/functionDeclaration.out create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/statements.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/statements.out diff --git a/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt b/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt index f8610ec5202..6b4c403304a 100644 --- a/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt +++ b/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.debugger.evaluate import com.intellij.debugger.DebuggerManagerEx import com.intellij.debugger.engine.DebugProcessImpl import com.intellij.debugger.engine.evaluation.CodeFragmentFactory -import com.intellij.debugger.engine.evaluation.CodeFragmentKind import com.intellij.debugger.engine.evaluation.TextWithImports import com.intellij.debugger.engine.events.DebuggerCommandImpl import com.intellij.debugger.impl.DebuggerContextImpl @@ -56,13 +55,7 @@ class KotlinCodeFragmentFactory : CodeFragmentFactory() { override fun createCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment { val contextElement = getContextElement(context) - val constructor = when (item.kind) { - null -> error("Code fragment kind should be set") - CodeFragmentKind.EXPRESSION -> ::KtExpressionCodeFragment - CodeFragmentKind.CODE_BLOCK -> ::KtBlockCodeFragment - } - - val codeFragment = constructor(project, "fragment.kt", item.text, initImports(item.imports), contextElement) + val codeFragment = KtBlockCodeFragment(project, "fragment.kt", item.text, initImports(item.imports), contextElement) supplyDebugInformation(item, codeFragment, context) codeFragment.putCopyableUserData(KtCodeFragment.RUNTIME_TYPE_EVALUATOR) { expression: KtExpression -> @@ -228,7 +221,7 @@ class KotlinCodeFragmentFactory : CodeFragmentFactory() { override fun createPresentationCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment { val kotlinCodeFragment = createCodeFragment(item, context, project) - if (PsiTreeUtil.hasErrorElements(kotlinCodeFragment) && kotlinCodeFragment is KtExpressionCodeFragment) { + if (PsiTreeUtil.hasErrorElements(kotlinCodeFragment) && kotlinCodeFragment is KtCodeFragment) { val javaExpression = try { PsiElementFactory.SERVICE.getInstance(project).createExpressionFromText(item.text, context) } catch (e: IncorrectOperationException) { diff --git a/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluatorBuilder.kt b/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluatorBuilder.kt index 5696fe082a7..0f3cfb9226e 100644 --- a/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluatorBuilder.kt +++ b/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluatorBuilder.kt @@ -238,20 +238,30 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, private val sourcePositi } private fun KtCodeFragment.wrapToStringIfNeeded(bindingContext: BindingContext): Boolean { - if (this !is KtExpressionCodeFragment) { - return false - } + val expression = runReadAction { + when (this) { + is KtExpressionCodeFragment -> getContentElement() + is KtBlockCodeFragment -> getContentElement().statements.lastOrNull() + else -> { + LOG.error("Invalid code fragment type: ${this.javaClass}") + null + } + } + } ?: return false - val contentElement = runReadAction { getContentElement() } - val expressionType = bindingContext[BindingContext.EXPRESSION_TYPE_INFO, contentElement]?.type - if (contentElement != null && expressionType?.isInlineClassType() == true) { + return wrapToStringIfNeeded(expression, bindingContext) + } + + private fun wrapToStringIfNeeded(expression: KtExpression, bindingContext: BindingContext): Boolean { + val expressionType = bindingContext[BindingContext.EXPRESSION_TYPE_INFO, expression]?.type ?: return false + if (expressionType.isInlineClassType()) { val newExpression = runReadAction { - val expressionText = contentElement.text - KtPsiFactory(project).createExpression("($expressionText).toString()") + val expressionText = expression.text + KtPsiFactory(expression.project).createExpression("($expressionText).toString()") } runInEdtAndWait { - project.executeWriteCommand("Wrap with 'toString()'") { - contentElement.replace(newExpression) + expression.project.executeWriteCommand("Wrap with 'toString()'") { + expression.replace(newExpression) } } return true diff --git a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinEvaluateExpressionTestGenerated.java b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinEvaluateExpressionTestGenerated.java index f1b197fdfa5..2563152104b 100644 --- a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinEvaluateExpressionTestGenerated.java @@ -185,6 +185,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/funFromSuperClass.kt"); } + @TestMetadata("functionDeclaration.kt") + public void testFunctionDeclaration() throws Exception { + runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/functionDeclaration.kt"); + } + @TestMetadata("genericCrossinlineArgument.kt") public void testGenericCrossinlineArgument() throws Exception { runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/genericCrossinlineArgument.kt"); @@ -400,6 +405,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/simple.kt"); } + @TestMetadata("statements.kt") + public void testStatements() throws Exception { + runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/statements.kt"); + } + @TestMetadata("staticField.kt") public void testStaticField() throws Exception { runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/staticField.kt"); diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/functionDeclaration.kt b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/functionDeclaration.kt new file mode 100644 index 00000000000..129028a82d2 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/functionDeclaration.kt @@ -0,0 +1,9 @@ +package functionDeclaration + +fun main() { + //Breakpoint! + val a = 5 +} + +// EXPRESSION: fun foo() {} +// RESULT: VOID_VALUE \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/functionDeclaration.out b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/functionDeclaration.out new file mode 100644 index 00000000000..0dde5795efa --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/functionDeclaration.out @@ -0,0 +1,8 @@ +LineBreakpoint created at functionDeclaration.kt:5 +Run Java +Connected to the target VM +functionDeclaration.kt:5 +Compile bytecode for fun foo() {} +Disconnected from the target VM + +Process finished with exit code 0 diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/statements.kt b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/statements.kt new file mode 100644 index 00000000000..aa01a4edb21 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/statements.kt @@ -0,0 +1,9 @@ +package statements + +fun main() { + //Breakpoint! + val a = 5 +} + +// EXPRESSION: val b = 1 +// RESULT: VOID_VALUE \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/statements.out b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/statements.out new file mode 100644 index 00000000000..4be507fbbc2 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/statements.out @@ -0,0 +1,8 @@ +LineBreakpoint created at statements.kt:5 +Run Java +Connected to the target VM +statements.kt:5 +Compile bytecode for val b = 1 +Disconnected from the target VM + +Process finished with exit code 0