diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/MethodInvokeUtils.kt b/java/debugger/impl/src/com/intellij/debugger/engine/MethodInvokeUtils.kt index 3763ada6f7a4..e24e55aaa3d3 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/MethodInvokeUtils.kt +++ b/java/debugger/impl/src/com/intellij/debugger/engine/MethodInvokeUtils.kt @@ -14,7 +14,6 @@ import com.intellij.openapi.diagnostic.Attachment import com.intellij.openapi.diagnostic.RuntimeExceptionWithAttachments import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.util.registry.Registry -import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.CommonClassNames import com.intellij.rt.debugger.MethodInvoker import com.intellij.util.BitUtil.isSet @@ -23,22 +22,22 @@ import com.sun.jdi.ObjectReference.INVOKE_NONVIRTUAL object MethodInvokeUtils { fun getHelperExceptionStackTrace(evaluationContext: EvaluationContextImpl, e: Exception): String? { - e as? EvaluateException ?: return null + if (e !is EvaluateException) return null val exceptionFromTargetVM = e.exceptionFromTargetVM ?: return null - var exceptionStack = DebuggerUtilsImpl.getExceptionText(evaluationContext, exceptionFromTargetVM) - if (!exceptionStack.isNullOrEmpty()) { - // drop user frames - val currentStackDepth = DebugProcessImpl.getEvaluationThread(evaluationContext).frameCount() - val lines = StringUtil.splitByLines(exceptionStack) // exclude empty lines - if (lines.size > currentStackDepth) { - return lines.asSequence().take(lines.size - currentStackDepth).joinToString(separator = "\n") - } - else { - logger().error("Invalid helper stack (expected currentStackDepth = ${currentStackDepth}) : ${exceptionStack}") - return exceptionStack - } + val stackTraceArray = DebuggerUtilsImpl.invokeThrowableGetStackTrace(exceptionFromTargetVM, evaluationContext, true) + if (stackTraceArray !is ArrayReference) return null + val values = stackTraceArray.values + if (values.isEmpty()) return null + // drop user frames + val currentStackDepth = DebugProcessImpl.getEvaluationThread(evaluationContext).frameCount() + val keepLines = if (values.size <= currentStackDepth) values.size else values.size - currentStackDepth + val stackTraceString = + DebuggerUtils.getValueAsString(evaluationContext, exceptionFromTargetVM) + "\n" + + values.asSequence().take(keepLines).map { DebuggerUtils.getValueAsString(evaluationContext, it) }.joinToString(prefix = "\tat ", separator = "\n") + if (values.size <= currentStackDepth) { + logger().error("Invalid helper stack (expected currentStackDepth = ${currentStackDepth}) : ${stackTraceString}") } - return null + return stackTraceString } } diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java index a1f8efe1792e..7bcc2430da3d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java @@ -544,4 +544,18 @@ public final class DebuggerUtilsImpl extends DebuggerUtilsEx { Collections.singletonList(exceptionObject)); return value != null ? ((StringReference)value).value() : null; } + + @Nullable + public static Value invokeThrowableGetStackTrace(@NotNull ObjectReference exceptionObj, + @NotNull EvaluationContextImpl evaluationContext, + boolean keepResult) throws EvaluateException { + if (instanceOf(exceptionObj.type(), "java.lang.Throwable")) { + Method method = findMethod(exceptionObj.referenceType(), "getStackTrace", "()[Ljava/lang/StackTraceElement;"); + DebugProcessImpl debugProcess = evaluationContext.getDebugProcess(); + ThrowableComputable invoker = () -> debugProcess.invokeInstanceMethod( + evaluationContext, exceptionObj, Objects.requireNonNull(method), Collections.emptyList(), 0, true); + return keepResult ? evaluationContext.computeAndKeep(invoker) : invoker.compute(); + } + return null; + } } \ No newline at end of file diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java index 045f26ea57db..00d22b6967de 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java @@ -12,6 +12,7 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.impl.DebuggerContextImpl; +import com.intellij.debugger.impl.DebuggerUtilsImpl; import com.intellij.debugger.impl.PositionUtil; import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.settings.ViewsGeneralSettings; @@ -129,7 +130,7 @@ public class FieldDescriptorImpl extends ValueDescriptorImpl implements FieldDes ((ArrayReference)value).length() == 0 && DebuggerUtils.instanceOf(myObject.type(), CommonClassNames.JAVA_LANG_THROWABLE)) { try { - invokeExceptionGetStackTrace(myObject, evaluationContext); + DebuggerUtilsImpl.invokeThrowableGetStackTrace(myObject, evaluationContext, false); return true; } catch (Throwable e) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java index a50abd9c3126..50832d93f0d3 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java @@ -4,7 +4,10 @@ package com.intellij.debugger.ui.impl.watch; import com.intellij.Patches; import com.intellij.debugger.DebuggerContext; import com.intellij.debugger.JavaDebuggerBundle; -import com.intellij.debugger.engine.*; +import com.intellij.debugger.engine.DebugProcessImpl; +import com.intellij.debugger.engine.DebuggerManagerThreadImpl; +import com.intellij.debugger.engine.JavaValue; +import com.intellij.debugger.engine.SuspendContextImpl; import com.intellij.debugger.engine.evaluation.CodeFragmentFactoryContextWrapper; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; @@ -19,8 +22,8 @@ import com.intellij.debugger.ui.tree.DebuggerTreeNode; import com.intellij.debugger.ui.tree.NodeDescriptor; import com.intellij.debugger.ui.tree.NodeDescriptorNameAdjuster; import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.debugger.ui.tree.render.Renderer; import com.intellij.debugger.ui.tree.render.*; +import com.intellij.debugger.ui.tree.render.Renderer; import com.intellij.icons.AllIcons; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; @@ -46,7 +49,6 @@ import org.jetbrains.concurrency.Promise; import org.jetbrains.concurrency.Promises; import javax.swing.*; -import java.util.Collections; import java.util.Objects; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; @@ -263,17 +265,6 @@ public abstract class ValueDescriptorImpl extends NodeDescriptorImpl implements return myInitFuture; } - @Nullable - protected static Value invokeExceptionGetStackTrace(ObjectReference exceptionObj, EvaluationContextImpl evaluationContext) - throws EvaluateException { - Method method = DebuggerUtils.findMethod(exceptionObj.referenceType(), "getStackTrace", "()[Ljava/lang/StackTraceElement;"); - if (method != null) { - return evaluationContext.getDebugProcess().invokeInstanceMethod( - evaluationContext, exceptionObj, method, Collections.emptyList(), 0, true); - } - return null; - } - @Nullable private static ObjectReference getTargetExceptionWithStackTraceFilled(@Nullable EvaluationContextImpl evaluationContext, EvaluateException ex, @@ -281,10 +272,10 @@ public abstract class ValueDescriptorImpl extends NodeDescriptorImpl implements final ObjectReference exceptionObj = ex.getExceptionFromTargetVM(); if (exceptionObj != null && evaluationContext != null) { try { - Value trace = invokeExceptionGetStackTrace(exceptionObj, evaluationContext); + Value trace = DebuggerUtilsImpl.invokeThrowableGetStackTrace(exceptionObj, evaluationContext, false); // print to console as well - if (printToConsole && trace instanceof ArrayReference) { + if (printToConsole && trace != null) { evaluationContext.getDebugProcess().printToConsole(DebuggerUtilsImpl.getExceptionText(evaluationContext, exceptionObj)); } }