diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/FrameVisitor.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/FrameVisitor.kt index 8da76bf1b41..848fe1f9b9a 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/FrameVisitor.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/FrameVisitor.kt @@ -18,7 +18,7 @@ package org.jetbrains.kotlin.idea.debugger.evaluate import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil import com.intellij.debugger.engine.evaluation.EvaluationContextImpl -import com.intellij.debugger.jdi.StackFrameProxyImpl +import com.intellij.openapi.diagnostic.Attachment import com.sun.jdi.ClassType import com.sun.jdi.InvalidStackFrameException import com.sun.jdi.ObjectReference @@ -30,14 +30,17 @@ import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.inline.INLINE_FUN_VAR_SUFFIX import org.jetbrains.kotlin.codegen.inline.INLINE_TRANSFORMATION_SUFFIX import org.jetbrains.kotlin.codegen.inline.NUMBERED_FUNCTION_PREFIX +import org.jetbrains.kotlin.idea.debugger.DebuggerUtils import org.jetbrains.kotlin.idea.debugger.isInsideInlineFunctionBody import org.jetbrains.kotlin.idea.debugger.numberOfInlinedFunctions import org.jetbrains.kotlin.idea.util.application.runReadAction +import org.jetbrains.kotlin.idea.util.attachment.mergeAttachments import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.org.objectweb.asm.Type -class FrameVisitor(context: EvaluationContextImpl) { +class FrameVisitor(val context: EvaluationContextImpl) { private val scope = context.debugProcess.searchScope private val frame = context.frameProxy @@ -95,7 +98,31 @@ class FrameVisitor(context: EvaluationContextImpl) { } private fun fail(message: String, shouldFail: Boolean): Value? { - return if (shouldFail) throw EvaluateExceptionUtil.createEvaluateException(message) else null + if (!shouldFail) { + return null + } + + val location = frame?.location() + + val locationText = location?.run { "Location: ${sourceName()}:${lineNumber()}" } ?: "No location available" + + val sourceName = location?.sourceName() + val declaringTypeName = location?.declaringType()?.name()?.replace('.', '/')?.let { JvmClassName.byInternalName(it) } + + val sourceFile = if (sourceName != null && declaringTypeName != null) { + DebuggerUtils.findSourceFileForClassIncludeLibrarySources(context.project, scope, declaringTypeName, sourceName) + } else { + null + } + + val sourceFileText = runReadAction { sourceFile?.text } + + if (sourceName != null && sourceFileText != null) { + val attachments = mergeAttachments(Attachment(sourceName, sourceFileText), Attachment("location.txt", locationText)) + LOG.error(message, attachments) + } + + throw EvaluateExceptionUtil.createEvaluateException(message) } private fun findThis(asmType: Type?): Value? { diff --git a/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/funFromOuterClassInLamdba.kt b/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/funFromOuterClassInLamdba.kt index 195ac3ecd25..82c14795646 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/funFromOuterClassInLamdba.kt +++ b/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/funFromOuterClassInLamdba.kt @@ -23,7 +23,7 @@ class Outer { // outer isn't captured in lambda lambda { // EXPRESSION: foo() + 2 - // RESULT: Cannot find local variable: name = this + // RESULT: java.lang.AssertionError : Cannot find local variable: name = this //Breakpoint! val a = 1 } diff --git a/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/localFun.kt b/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/localFun.kt index ffa6b95f8b2..033cbccbc66 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/localFun.kt +++ b/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/localFun.kt @@ -16,7 +16,7 @@ fun main(args: Array) { fun myLocalFun3() { // EXPRESSION: myLocalFun1() + 1 - // RESULT: Cannot find local variable: name = myLocalFun1 + // RESULT: java.lang.AssertionError : Cannot find local variable: name = myLocalFun1 //Breakpoint! myLocalFun1() + 1 } @@ -56,7 +56,7 @@ fun main(args: Array) { i = 1 fun myLocalFun7() { // EXPRESSION: myLocalFun6() + 1 - // RESULT: Cannot find local variable: name = myLocalFun6 + // RESULT: java.lang.AssertionError : Cannot find local variable: name = myLocalFun6 //Breakpoint! myLocalFun6() + 1 } diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameLambdaNotUsed.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameLambdaNotUsed.kt index 5e328181b99..5b181bfbf4d 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameLambdaNotUsed.kt +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameLambdaNotUsed.kt @@ -15,4 +15,4 @@ fun foo(f: () -> Unit) { // PRINT_FRAME // EXPRESSION: val1 -// RESULT: Cannot find local variable: name = val1 \ No newline at end of file +// RESULT: java.lang.AssertionError : Cannot find local variable: name = val1 \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameLambdaNotUsed.out b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameLambdaNotUsed.out index 8e9d0b98db0..3216889f5d7 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameLambdaNotUsed.out +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameLambdaNotUsed.out @@ -20,7 +20,7 @@ fun foo(f: () -> Unit) { // PRINT_FRAME // EXPRESSION: val1 -// RESULT: Cannot find local variable: name = val1 +// RESULT: java.lang.AssertionError : Cannot find local variable: name = val1 frame = invoke:7, FrameLambdaNotUsedKt$main$1 {frameLambdaNotUsed} this = this = {frameLambdaNotUsed.FrameLambdaNotUsedKt$main$1@uniqueID}Function0 field = arity: int = 0 (sp = Lambda.!EXT!)