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.
This commit is contained in:
+2
-9
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.debugger.evaluate
|
|||||||
import com.intellij.debugger.DebuggerManagerEx
|
import com.intellij.debugger.DebuggerManagerEx
|
||||||
import com.intellij.debugger.engine.DebugProcessImpl
|
import com.intellij.debugger.engine.DebugProcessImpl
|
||||||
import com.intellij.debugger.engine.evaluation.CodeFragmentFactory
|
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.evaluation.TextWithImports
|
||||||
import com.intellij.debugger.engine.events.DebuggerCommandImpl
|
import com.intellij.debugger.engine.events.DebuggerCommandImpl
|
||||||
import com.intellij.debugger.impl.DebuggerContextImpl
|
import com.intellij.debugger.impl.DebuggerContextImpl
|
||||||
@@ -56,13 +55,7 @@ class KotlinCodeFragmentFactory : CodeFragmentFactory() {
|
|||||||
override fun createCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment {
|
override fun createCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment {
|
||||||
val contextElement = getContextElement(context)
|
val contextElement = getContextElement(context)
|
||||||
|
|
||||||
val constructor = when (item.kind) {
|
val codeFragment = KtBlockCodeFragment(project, "fragment.kt", item.text, initImports(item.imports), contextElement)
|
||||||
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)
|
|
||||||
supplyDebugInformation(item, codeFragment, context)
|
supplyDebugInformation(item, codeFragment, context)
|
||||||
|
|
||||||
codeFragment.putCopyableUserData(KtCodeFragment.RUNTIME_TYPE_EVALUATOR) { expression: KtExpression ->
|
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 {
|
override fun createPresentationCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment {
|
||||||
val kotlinCodeFragment = createCodeFragment(item, context, project)
|
val kotlinCodeFragment = createCodeFragment(item, context, project)
|
||||||
if (PsiTreeUtil.hasErrorElements(kotlinCodeFragment) && kotlinCodeFragment is KtExpressionCodeFragment) {
|
if (PsiTreeUtil.hasErrorElements(kotlinCodeFragment) && kotlinCodeFragment is KtCodeFragment) {
|
||||||
val javaExpression = try {
|
val javaExpression = try {
|
||||||
PsiElementFactory.SERVICE.getInstance(project).createExpressionFromText(item.text, context)
|
PsiElementFactory.SERVICE.getInstance(project).createExpressionFromText(item.text, context)
|
||||||
} catch (e: IncorrectOperationException) {
|
} catch (e: IncorrectOperationException) {
|
||||||
|
|||||||
+20
-10
@@ -238,20 +238,30 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, private val sourcePositi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun KtCodeFragment.wrapToStringIfNeeded(bindingContext: BindingContext): Boolean {
|
private fun KtCodeFragment.wrapToStringIfNeeded(bindingContext: BindingContext): Boolean {
|
||||||
if (this !is KtExpressionCodeFragment) {
|
val expression = runReadAction {
|
||||||
return false
|
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() }
|
return wrapToStringIfNeeded(expression, bindingContext)
|
||||||
val expressionType = bindingContext[BindingContext.EXPRESSION_TYPE_INFO, contentElement]?.type
|
}
|
||||||
if (contentElement != null && expressionType?.isInlineClassType() == true) {
|
|
||||||
|
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 newExpression = runReadAction {
|
||||||
val expressionText = contentElement.text
|
val expressionText = expression.text
|
||||||
KtPsiFactory(project).createExpression("($expressionText).toString()")
|
KtPsiFactory(expression.project).createExpression("($expressionText).toString()")
|
||||||
}
|
}
|
||||||
runInEdtAndWait {
|
runInEdtAndWait {
|
||||||
project.executeWriteCommand("Wrap with 'toString()'") {
|
expression.project.executeWriteCommand("Wrap with 'toString()'") {
|
||||||
contentElement.replace(newExpression)
|
expression.replace(newExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|||||||
+10
@@ -185,6 +185,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/funFromSuperClass.kt");
|
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")
|
@TestMetadata("genericCrossinlineArgument.kt")
|
||||||
public void testGenericCrossinlineArgument() throws Exception {
|
public void testGenericCrossinlineArgument() throws Exception {
|
||||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/genericCrossinlineArgument.kt");
|
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");
|
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")
|
@TestMetadata("staticField.kt")
|
||||||
public void testStaticField() throws Exception {
|
public void testStaticField() throws Exception {
|
||||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/staticField.kt");
|
runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/staticField.kt");
|
||||||
|
|||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package functionDeclaration
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPRESSION: fun foo() {}
|
||||||
|
// RESULT: VOID_VALUE
|
||||||
Vendored
+8
@@ -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
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package statements
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPRESSION: val b = 1
|
||||||
|
// RESULT: VOID_VALUE
|
||||||
+8
@@ -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
|
||||||
Reference in New Issue
Block a user