From 3a83b6a500593e97f7887e9bd12f18bf432df17c Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 21 May 2015 13:28:07 +0300 Subject: [PATCH] IDEA-138233 It's not possible to navigate to target class and line from exception trace --- .../intellij/debugger/engine/JavaValue.java | 69 ++++++++----- .../CustomPopupFullValueEvaluator.java | 77 --------------- .../render/CustomPopupFullValueEvaluator.java | 62 ++++++++++++ .../tree/render/GraphicsObjectRenderer.java | 2 +- .../ui/tree/render/IconObjectRenderer.java | 2 +- .../ui/tree/render/ImageObjectRenderer.java | 3 +- .../StackTraceElementObjectRenderer.java | 98 +++++++++++++++++++ .../src/messages/DebuggerBundle.properties | 1 + resources/src/META-INF/IdeaPlugin.xml | 1 + 9 files changed, 212 insertions(+), 103 deletions(-) delete mode 100644 java/debugger/impl/src/com/intellij/debugger/settings/CustomPopupFullValueEvaluator.java create mode 100644 java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CustomPopupFullValueEvaluator.java create mode 100644 java/debugger/impl/src/com/intellij/debugger/ui/tree/render/StackTraceElementObjectRenderer.java diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java index acdf8687dea2..4a6c6ba5efb5 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java @@ -27,7 +27,6 @@ import com.intellij.debugger.engine.events.DebuggerCommandImpl; import com.intellij.debugger.engine.events.SuspendContextCommandImpl; import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.impl.DebuggerUtilsEx; -import com.intellij.debugger.ui.tree.render.ToStringBasedRenderer; import com.intellij.debugger.ui.impl.DebuggerTreeRenderer; import com.intellij.debugger.ui.impl.watch.*; import com.intellij.debugger.ui.tree.*; @@ -156,29 +155,14 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV } } else if (value.length() > XValueNode.MAX_VALUE_LENGTH) { - node.setFullValueEvaluator(new XFullValueEvaluator() { + node.setFullValueEvaluator(new JavaFullValueEvaluator(myEvaluationContext) { @Override - public void startEvaluation(@NotNull final XFullValueEvaluationCallback callback) { - myEvaluationContext.getManagerThread().schedule(new SuspendContextCommandImpl(suspendContext) { + public void evaluate(@NotNull final XFullValueEvaluationCallback callback) throws Exception { + final ValueDescriptorImpl fullValueDescriptor = myValueDescriptor.getFullValueDescriptor(); + fullValueDescriptor.updateRepresentation(myEvaluationContext, new DescriptorLabelListener() { @Override - public Priority getPriority() { - return Priority.NORMAL; - } - - @Override - protected void commandCancelled() { - callback.errorOccurred(DebuggerBundle.message("error.context.has.changed")); - } - - @Override - public void contextAction() throws Exception { - final ValueDescriptorImpl fullValueDescriptor = myValueDescriptor.getFullValueDescriptor(); - fullValueDescriptor.updateRepresentation(myEvaluationContext, new DescriptorLabelListener() { - @Override - public void labelChanged() { - callback.evaluated(fullValueDescriptor.getValueText()); - } - }); + public void labelChanged() { + callback.evaluated(fullValueDescriptor.getValueText()); } }); } @@ -191,6 +175,47 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV }); } + public abstract static class JavaFullValueEvaluator extends XFullValueEvaluator { + private final EvaluationContextImpl myEvaluationContext; + + public JavaFullValueEvaluator(@NotNull String linkText, EvaluationContextImpl evaluationContext) { + super(linkText); + myEvaluationContext = evaluationContext; + } + + public JavaFullValueEvaluator(EvaluationContextImpl evaluationContext) { + myEvaluationContext = evaluationContext; + } + + public abstract void evaluate(@NotNull XFullValueEvaluationCallback callback) throws Exception; + + protected EvaluationContextImpl getEvaluationContext() { + return myEvaluationContext; + } + + @Override + public void startEvaluation(@NotNull final XFullValueEvaluationCallback callback) { + if (callback.isObsolete()) return; + myEvaluationContext.getManagerThread().schedule(new SuspendContextCommandImpl(myEvaluationContext.getSuspendContext()) { + @Override + public Priority getPriority() { + return Priority.NORMAL; + } + + @Override + protected void commandCancelled() { + callback.errorOccurred(DebuggerBundle.message("error.context.has.changed")); + } + + @Override + public void contextAction() throws Exception { + if (callback.isObsolete()) return; + evaluate(callback); + } + }); + } + } + private static String truncateToMaxLength(String value) { return value.substring(0, Math.min(value.length(), XValueNode.MAX_VALUE_LENGTH)); } diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/CustomPopupFullValueEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/settings/CustomPopupFullValueEvaluator.java deleted file mode 100644 index 4f7288c8303d..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/settings/CustomPopupFullValueEvaluator.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.debugger.settings; - -import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; -import com.intellij.debugger.engine.events.SuspendContextCommandImpl; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.JBPopup; -import com.intellij.openapi.wm.WindowManager; -import com.intellij.ui.awt.RelativePoint; -import com.intellij.xdebugger.frame.XFullValueEvaluator; -import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.*; - -/** - * @author egor - */ -public abstract class CustomPopupFullValueEvaluator extends XFullValueEvaluator { - protected final EvaluationContextImpl myEvaluationContext; - - public CustomPopupFullValueEvaluator(@NotNull String linkText, @NotNull EvaluationContextImpl evaluationContext) { - super(linkText); - myEvaluationContext = evaluationContext; - setShowValuePopup(false); - } - - protected abstract T getData(); - - protected abstract JComponent createComponent(T data); - - @Override - public void startEvaluation(@NotNull final XFullValueEvaluationCallback callback) { - myEvaluationContext.getManagerThread().schedule(new SuspendContextCommandImpl(myEvaluationContext.getSuspendContext()) { - @Override - public Priority getPriority() { - return Priority.NORMAL; - } - - @Override - public void contextAction() throws Exception { - if (callback.isObsolete()) return; - final T data = getData(); - DebuggerUIUtil.invokeLater(new Runnable() { - @Override - public void run() { - if (callback.isObsolete()) return; - final JComponent comp = createComponent(data); - Project project = myEvaluationContext.getProject(); - JBPopup popup = DebuggerUIUtil.createValuePopup(project, comp, null); - JFrame frame = WindowManager.getInstance().getFrame(project); - Dimension frameSize = frame.getSize(); - Dimension size = new Dimension(frameSize.width / 2, frameSize.height / 2); - popup.setSize(size); - callback.evaluated(""); - popup.show(new RelativePoint(frame, new Point(size.width / 2, size.height / 2))); - } - }); - } - }); - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CustomPopupFullValueEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CustomPopupFullValueEvaluator.java new file mode 100644 index 000000000000..6917cdf00496 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CustomPopupFullValueEvaluator.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.debugger.ui.tree.render; + +import com.intellij.debugger.engine.JavaValue; +import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; + +/** + * @author egor + */ +public abstract class CustomPopupFullValueEvaluator extends JavaValue.JavaFullValueEvaluator { + public CustomPopupFullValueEvaluator(@NotNull String linkText, @NotNull EvaluationContextImpl evaluationContext) { + super(linkText, evaluationContext); + setShowValuePopup(false); + } + + protected abstract T getData(); + + protected abstract JComponent createComponent(T data); + + @Override + public void evaluate(@NotNull final XFullValueEvaluationCallback callback) throws Exception { + final T data = getData(); + DebuggerUIUtil.invokeLater(new Runnable() { + @Override + public void run() { + if (callback.isObsolete()) return; + final JComponent comp = createComponent(data); + Project project = getEvaluationContext().getProject(); + JBPopup popup = DebuggerUIUtil.createValuePopup(project, comp, null); + JFrame frame = WindowManager.getInstance().getFrame(project); + Dimension frameSize = frame.getSize(); + Dimension size = new Dimension(frameSize.width / 2, frameSize.height / 2); + popup.setSize(size); + callback.evaluated(""); + popup.show(new RelativePoint(frame, new Point(size.width / 2, size.height / 2))); + } + }); + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/GraphicsObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/GraphicsObjectRenderer.java index eccc01d16e03..1676cf2736c3 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/GraphicsObjectRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/GraphicsObjectRenderer.java @@ -55,7 +55,7 @@ public class GraphicsObjectRenderer extends ToStringBasedRenderer implements Ful return new ImageObjectRenderer.IconPopupEvaluator(DebuggerBundle.message("message.node.show.image"), evaluationContext) { @Override protected Icon getData() { - return ImageObjectRenderer.getIcon(myEvaluationContext, bufImgValue, "imageToBytes"); + return ImageObjectRenderer.getIcon(getEvaluationContext(), bufImgValue, "imageToBytes"); } }; } catch (Exception ignored) {} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/IconObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/IconObjectRenderer.java index c9b5d635fffb..085c5cfd363d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/IconObjectRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/IconObjectRenderer.java @@ -58,7 +58,7 @@ class IconObjectRenderer extends ToStringBasedRenderer implements FullValueEvalu return new ImageObjectRenderer.IconPopupEvaluator(DebuggerBundle.message("message.node.show.icon"), evaluationContext) { @Override protected Icon getData() { - return ImageObjectRenderer.getIcon(myEvaluationContext, valueDescriptor.getValue(), "iconToBytes"); + return ImageObjectRenderer.getIcon(getEvaluationContext(), valueDescriptor.getValue(), "iconToBytes"); } }; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ImageObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ImageObjectRenderer.java index e511a6aca5a8..701f7ef7945e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ImageObjectRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ImageObjectRenderer.java @@ -22,7 +22,6 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.impl.ClassLoadingUtils; -import com.intellij.debugger.settings.CustomPopupFullValueEvaluator; import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; import com.intellij.openapi.diagnostic.Logger; @@ -57,7 +56,7 @@ class ImageObjectRenderer extends ToStringBasedRenderer implements FullValueEval return new IconPopupEvaluator(DebuggerBundle.message("message.node.show.image"), evaluationContext) { @Override protected Icon getData() { - return getIcon(myEvaluationContext, valueDescriptor.getValue(), "imageToBytes"); + return getIcon(getEvaluationContext(), valueDescriptor.getValue(), "imageToBytes"); } }; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/StackTraceElementObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/StackTraceElementObjectRenderer.java new file mode 100644 index 000000000000..d9e7ffd9eb1d --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/StackTraceElementObjectRenderer.java @@ -0,0 +1,98 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.debugger.ui.tree.render; + +import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.engine.FullValueEvaluatorProvider; +import com.intellij.debugger.engine.JavaValue; +import com.intellij.debugger.engine.evaluation.EvaluateException; +import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; +import com.intellij.debugger.settings.NodeRendererSettings; +import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; +import com.intellij.execution.filters.ExceptionFilter; +import com.intellij.execution.filters.Filter; +import com.intellij.execution.filters.HyperlinkInfo; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.xdebugger.frame.XFullValueEvaluator; +import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; +import com.sun.jdi.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; + +/** +* @author egor +*/ +class StackTraceElementObjectRenderer extends ToStringBasedRenderer implements FullValueEvaluatorProvider { + private static final Logger LOG = Logger.getInstance(StackTraceElementObjectRenderer.class); + + public StackTraceElementObjectRenderer(final NodeRendererSettings rendererSettings) { + super(rendererSettings, "StackTraceElement", null, null); + setClassName("java.lang.StackTraceElement"); + setEnabled(true); + } + + @Nullable + @Override + public XFullValueEvaluator getFullValueEvaluator(final EvaluationContextImpl evaluationContext, final ValueDescriptorImpl valueDescriptor) { + return new JavaValue.JavaFullValueEvaluator(DebuggerBundle.message("message.node.navigate"), evaluationContext) { + @Override + public void evaluate(@NotNull XFullValueEvaluationCallback callback) throws Exception { + Value value = valueDescriptor.getValue(); + ClassType type = ((ClassType)value.type()); + Method toString = type.concreteMethodByName("toString", "()Ljava/lang/String;"); + if (toString != null) { + try { + Value res = + evaluationContext.getDebugProcess().invokeMethod(evaluationContext, (ObjectReference)value, toString, Collections.emptyList()); + if (res instanceof StringReference) { + callback.evaluated(""); + final String line = ((StringReference)res).value(); + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + ExceptionFilter filter = new ExceptionFilter(evaluationContext.getDebugProcess().getSession().getSearchScope()); + Filter.Result result = filter.applyFilter(line, line.length()); + if (result != null) { + final HyperlinkInfo info = result.getFirstHyperlinkInfo(); + if (info != null) { + DebuggerUIUtil.invokeLater(new Runnable() { + @Override + public void run() { + info.navigate(valueDescriptor.getProject()); + } + }); + } + } + } + }); + } + } + catch (EvaluateException e) { + LOG.info("Exception while getting stack info", e); + } + } + } + + @Override + public boolean isShowValuePopup() { + return false; + } + }; + } +} diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties index dfc2a108eaea..717c257fc5f3 100644 --- a/resources-en/src/messages/DebuggerBundle.properties +++ b/resources-en/src/messages/DebuggerBundle.properties @@ -399,6 +399,7 @@ message.node.thread.has.no.frames=Thread has no frames message.node.evaluation.not.possible=Target VM is not paused by breakpoint request. Evaluation of methods is not possible in this mode message.node.show.image=\u2026 Show image message.node.show.icon=\u2026 Show icon +message.node.navigate=\u2026 Navigate label.thread.node.thread.collected=Thread ''{0}'' has been garbage-collected label.thread.node=\"{0}\"@{1}: {2} label.thread.node.in.group=\"{0}\"@{1} in group \"{3}\": {2} diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 03ea759a7145..4d8d7fa9c1a6 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1529,6 +1529,7 @@ +