Debugger: Do not require a SourcePosition to exist
This commit is contained in:
+5
-1
@@ -95,10 +95,14 @@ class KotlinDebuggerCaches(project: Project) {
|
|||||||
|
|
||||||
fun compileCodeFragmentCacheAware(
|
fun compileCodeFragmentCacheAware(
|
||||||
codeFragment: KtCodeFragment,
|
codeFragment: KtCodeFragment,
|
||||||
sourcePosition: SourcePosition,
|
sourcePosition: SourcePosition?,
|
||||||
compileCode: () -> CompiledDataDescriptor,
|
compileCode: () -> CompiledDataDescriptor,
|
||||||
force: Boolean = false
|
force: Boolean = false
|
||||||
): Pair<CompiledDataDescriptor, Boolean> {
|
): Pair<CompiledDataDescriptor, Boolean> {
|
||||||
|
if (sourcePosition == null) {
|
||||||
|
return Pair(compileCode(), false)
|
||||||
|
}
|
||||||
|
|
||||||
val evaluateExpressionCache = getInstance(codeFragment.project)
|
val evaluateExpressionCache = getInstance(codeFragment.project)
|
||||||
|
|
||||||
val text = "${codeFragment.importsToString()}\n${codeFragment.text}"
|
val text = "${codeFragment.importsToString()}\n${codeFragment.text}"
|
||||||
|
|||||||
+25
-49
@@ -18,25 +18,20 @@ package org.jetbrains.kotlin.idea.debugger.evaluate
|
|||||||
|
|
||||||
import com.intellij.debugger.SourcePosition
|
import com.intellij.debugger.SourcePosition
|
||||||
import com.intellij.debugger.engine.DebugProcessImpl
|
import com.intellij.debugger.engine.DebugProcessImpl
|
||||||
import com.intellij.debugger.engine.SuspendContext
|
|
||||||
import com.intellij.debugger.engine.evaluation.EvaluateException
|
import com.intellij.debugger.engine.evaluation.EvaluateException
|
||||||
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil
|
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil
|
||||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||||
import com.intellij.debugger.engine.evaluation.expression.*
|
import com.intellij.debugger.engine.evaluation.expression.*
|
||||||
import com.intellij.diagnostic.LogMessageEx
|
|
||||||
import com.intellij.openapi.diagnostic.Attachment
|
import com.intellij.openapi.diagnostic.Attachment
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.progress.ProcessCanceledException
|
import com.intellij.openapi.progress.ProcessCanceledException
|
||||||
import com.intellij.openapi.project.DumbService
|
import com.intellij.openapi.project.DumbService
|
||||||
import com.intellij.psi.JavaPsiFacade
|
import com.intellij.psi.JavaPsiFacade
|
||||||
import com.intellij.psi.PsiDocumentManager
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.testFramework.runInEdtAndWait
|
import com.intellij.testFramework.runInEdtAndWait
|
||||||
import com.intellij.util.ExceptionUtil
|
|
||||||
import com.sun.jdi.*
|
import com.sun.jdi.*
|
||||||
import com.sun.jdi.Value
|
import com.sun.jdi.Value
|
||||||
import com.sun.jdi.request.EventRequest
|
|
||||||
import org.jetbrains.eval4j.*
|
import org.jetbrains.eval4j.*
|
||||||
import org.jetbrains.eval4j.Value as Eval4JValue
|
import org.jetbrains.eval4j.Value as Eval4JValue
|
||||||
import org.jetbrains.eval4j.jdi.JDIEval
|
import org.jetbrains.eval4j.jdi.JDIEval
|
||||||
@@ -85,36 +80,15 @@ internal const val GENERATED_CLASS_NAME = "Generated_for_debugger_class"
|
|||||||
|
|
||||||
object KotlinEvaluatorBuilder : EvaluatorBuilder {
|
object KotlinEvaluatorBuilder : EvaluatorBuilder {
|
||||||
override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator {
|
override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator {
|
||||||
if (codeFragment !is KtCodeFragment || position == null) {
|
if (codeFragment !is KtCodeFragment) {
|
||||||
return EvaluatorBuilderImpl.getInstance().build(codeFragment, position)
|
return EvaluatorBuilderImpl.getInstance().build(codeFragment, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position.line < 0 && position.file !is KtFile) {
|
val context = codeFragment.context ?: evaluationException("Cannot evaluate an expression without a context")
|
||||||
evaluationException("Couldn't evaluate Kotlin expression at $position")
|
val file = context.containingFile
|
||||||
}
|
|
||||||
|
|
||||||
val file = position.file
|
if (file !is KtFile) {
|
||||||
if (file is KtFile && position.line >= 0) {
|
reportError(codeFragment, position, "Unknown context${codeFragment.context?.javaClass}")
|
||||||
val document = PsiDocumentManager.getInstance(file.project).getDocument(file)
|
|
||||||
if (document == null || document.lineCount < position.line) {
|
|
||||||
evaluationException(
|
|
||||||
"Couldn't evaluate Kotlin expression: breakpoint is placed outside the file. " +
|
|
||||||
"It may happen when you've changed source file after starting a debug process."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (codeFragment.context !is KtElement) {
|
|
||||||
val attachments = arrayOf(
|
|
||||||
attachmentByPsiFile(position.file),
|
|
||||||
attachmentByPsiFile(codeFragment),
|
|
||||||
Attachment("breakpoint.info", "line: ${position.line}")
|
|
||||||
)
|
|
||||||
|
|
||||||
LOG.error(
|
|
||||||
"Trying to evaluate ${codeFragment::class.java} with context ${codeFragment.context?.javaClass}",
|
|
||||||
mergeAttachments(*attachments)
|
|
||||||
)
|
|
||||||
evaluationException("Couldn't evaluate Kotlin expression in this context")
|
evaluationException("Couldn't evaluate Kotlin expression in this context")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +96,7 @@ object KotlinEvaluatorBuilder : EvaluatorBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: SourcePosition) : Evaluator {
|
class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: SourcePosition?) : Evaluator {
|
||||||
override fun evaluate(context: EvaluationContextImpl): Any? {
|
override fun evaluate(context: EvaluationContextImpl): Any? {
|
||||||
if (codeFragment.text.isEmpty()) {
|
if (codeFragment.text.isEmpty()) {
|
||||||
return context.debugProcess.virtualMachineProxy.mirrorOfVoid()
|
return context.debugProcess.virtualMachineProxy.mirrorOfVoid()
|
||||||
@@ -157,25 +131,10 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
|
|||||||
evaluationException(e)
|
evaluationException(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
val text = runReadAction { codeFragment.context?.text ?: "null" }
|
reportError(codeFragment, sourcePosition, e.message ?: "An exception occurred", e)
|
||||||
val attachments = arrayOf(
|
|
||||||
attachmentByPsiFile(sourcePosition.file),
|
|
||||||
attachmentByPsiFile(codeFragment),
|
|
||||||
Attachment("breakpoint.info", "line: ${runReadAction { sourcePosition.line }}"),
|
|
||||||
Attachment("context.info", text)
|
|
||||||
)
|
|
||||||
|
|
||||||
LOG.error(
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
LogMessageEx.createEvent(
|
|
||||||
"Couldn't evaluate expression",
|
|
||||||
ExceptionUtil.getThrowableText(e),
|
|
||||||
mergeAttachments(*attachments)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val cause = if (e.message != null) ": ${e.message}" else ""
|
val cause = if (e.message != null) ": ${e.message}" else ""
|
||||||
evaluationException("An exception occurs during Evaluate Expression Action $cause")
|
evaluationException("Cannot evaluate the expression: $cause")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,5 +425,22 @@ private fun isSpecialException(th: Throwable): Boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun reportError(codeFragment: KtCodeFragment, position: SourcePosition?, message: String, throwable: Throwable? = null) {
|
||||||
|
val contextFile = codeFragment.context?.containingFile
|
||||||
|
|
||||||
|
val attachments = arrayOf(
|
||||||
|
attachmentByPsiFile(contextFile),
|
||||||
|
attachmentByPsiFile(codeFragment),
|
||||||
|
Attachment("breakpoint.info", "Position: " + position?.run { "${file.name}:$line" }),
|
||||||
|
Attachment("context.info", runReadAction { codeFragment.context?.text ?: "null" })
|
||||||
|
)
|
||||||
|
|
||||||
|
LOG.error(
|
||||||
|
"Cannot evaluate a code fragment of type " + codeFragment::class.java + ": " + message.decapitalize(),
|
||||||
|
throwable,
|
||||||
|
mergeAttachments(*attachments)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun evaluationException(msg: String): Nothing = throw EvaluateExceptionUtil.createEvaluateException(msg)
|
private fun evaluationException(msg: String): Nothing = throw EvaluateExceptionUtil.createEvaluateException(msg)
|
||||||
private fun evaluationException(e: Throwable): Nothing = throw EvaluateExceptionUtil.createEvaluateException(e)
|
private fun evaluationException(e: Throwable): Nothing = throw EvaluateExceptionUtil.createEvaluateException(e)
|
||||||
+2
-2
@@ -13,10 +13,10 @@ data class CompiledDataDescriptor(
|
|||||||
val parameters: List<CodeFragmentParameter.Dumb>,
|
val parameters: List<CodeFragmentParameter.Dumb>,
|
||||||
val crossingBounds: Set<CodeFragmentParameter.Dumb>,
|
val crossingBounds: Set<CodeFragmentParameter.Dumb>,
|
||||||
val mainMethodSignature: CodeFragmentCompiler.MethodSignature,
|
val mainMethodSignature: CodeFragmentCompiler.MethodSignature,
|
||||||
val sourcePosition: SourcePosition
|
val sourcePosition: SourcePosition?
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun from(result: CodeFragmentCompiler.CompilationResult, sourcePosition: SourcePosition): CompiledDataDescriptor {
|
fun from(result: CodeFragmentCompiler.CompilationResult, sourcePosition: SourcePosition?): CompiledDataDescriptor {
|
||||||
val localFunctionSuffixes = result.localFunctionSuffixes
|
val localFunctionSuffixes = result.localFunctionSuffixes
|
||||||
|
|
||||||
val dumbParameters = ArrayList<CodeFragmentParameter.Dumb>(result.parameterInfo.parameters.size)
|
val dumbParameters = ArrayList<CodeFragmentParameter.Dumb>(result.parameterInfo.parameters.size)
|
||||||
|
|||||||
Reference in New Issue
Block a user