mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-129063 Show warning when 'Drop Frame' is invoked inside 'try' block with 'finally' section
This commit is contained in:
@@ -19,26 +19,37 @@
|
||||
*/
|
||||
package com.intellij.debugger.actions;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.debugger.DebuggerBundle;
|
||||
import com.intellij.debugger.SourcePosition;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.engine.JavaStackFrame;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
|
||||
import com.intellij.debugger.settings.DebuggerSettings;
|
||||
import com.intellij.debugger.ui.impl.watch.*;
|
||||
import com.intellij.idea.ActionsBundle;
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.MessageDialogBuilder;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.psi.PsiCodeBlock;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiTryStatement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.XDebuggerManager;
|
||||
import com.intellij.xdebugger.frame.XStackFrame;
|
||||
import com.sun.jdi.InvalidStackFrameException;
|
||||
import com.sun.jdi.NativeMethodException;
|
||||
import com.sun.jdi.VMDisconnectedException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class PopFrameAction extends DebuggerAction {
|
||||
@@ -54,10 +65,53 @@ public class PopFrameAction extends DebuggerAction {
|
||||
if(debugProcess == null) {
|
||||
return;
|
||||
}
|
||||
if (DebuggerSettings.getInstance().CHECK_FINALLY_ON_POP_FRAME && isInTryWithFinally(debuggerContext.getSourcePosition())) {
|
||||
int res = MessageDialogBuilder
|
||||
.yesNo(UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)),
|
||||
DebuggerBundle.message("warning.finally.block.detected"))
|
||||
.project(project)
|
||||
.icon(Messages.getWarningIcon())
|
||||
.yesText(DebuggerBundle.message("button.drop.anyway"))
|
||||
.noText(CommonBundle.message("button.cancel"))
|
||||
.doNotAsk(
|
||||
new DialogWrapper.DoNotAskOption() {
|
||||
@Override
|
||||
public boolean isToBeShown() {
|
||||
return DebuggerSettings.getInstance().CHECK_FINALLY_ON_POP_FRAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToBeShown(boolean value, int exitCode) {
|
||||
DebuggerSettings.getInstance().CHECK_FINALLY_ON_POP_FRAME = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeHidden() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSaveOptionsOnCancel() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDoNotShowMessage() {
|
||||
return CommonBundle.message("dialog.options.do.not.show");
|
||||
}
|
||||
})
|
||||
.show();
|
||||
|
||||
if (res == Messages.NO) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
debugProcess.getManagerThread().schedule(debugProcess.createPopFrameCommand(debuggerContext, stackFrame));
|
||||
}
|
||||
catch (NativeMethodException e2){
|
||||
Messages.showMessageDialog(project, DebuggerBundle.message("error.native.method.exception"), ActionsBundle.actionText(DebuggerActions.POP_FRAME), Messages.getErrorIcon());
|
||||
Messages.showMessageDialog(project, DebuggerBundle.message("error.native.method.exception"), UIUtil.removeMnemonic(
|
||||
ActionsBundle.actionText(DebuggerActions.POP_FRAME)), Messages.getErrorIcon());
|
||||
}
|
||||
catch (InvalidStackFrameException ignored) {
|
||||
}
|
||||
@@ -65,6 +119,19 @@ public class PopFrameAction extends DebuggerAction {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isInTryWithFinally(SourcePosition position) {
|
||||
PsiElement element = position.getFile().findElementAt(position.getOffset());
|
||||
PsiTryStatement tryStatement = PsiTreeUtil.getParentOfType(element, PsiTryStatement.class);
|
||||
while (tryStatement != null) {
|
||||
PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
|
||||
if (finallyBlock != null && finallyBlock.getStatements().length > 0) {
|
||||
return true;
|
||||
}
|
||||
tryStatement = PsiTreeUtil.getParentOfType(tryStatement, PsiTryStatement.class);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static StackFrameProxyImpl getStackFrameProxy(AnActionEvent e) {
|
||||
DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
|
||||
|
||||
@@ -74,6 +74,8 @@ public class DebuggerSettings implements Cloneable, PersistentStateComponent<Ele
|
||||
public volatile boolean AUTO_VARIABLES_MODE = false;
|
||||
public volatile boolean SHOW_LIBRARY_STACKFRAMES = true;
|
||||
|
||||
public boolean CHECK_FINALLY_ON_POP_FRAME = true;
|
||||
|
||||
private ClassFilter[] mySteppingFilters = ClassFilter.EMPTY_ARRAY;
|
||||
|
||||
private Map<String, ContentState> myContentStates = new LinkedHashMap<String, ContentState>();
|
||||
@@ -142,6 +144,7 @@ public class DebuggerSettings implements Cloneable, PersistentStateComponent<Ele
|
||||
return
|
||||
TRACING_FILTERS_ENABLED == secondSettings.TRACING_FILTERS_ENABLED &&
|
||||
DEBUGGER_TRANSPORT == secondSettings.DEBUGGER_TRANSPORT &&
|
||||
CHECK_FINALLY_ON_POP_FRAME == secondSettings.CHECK_FINALLY_ON_POP_FRAME &&
|
||||
FORCE_CLASSIC_VM == secondSettings.FORCE_CLASSIC_VM &&
|
||||
DISABLE_JIT == secondSettings.DISABLE_JIT &&
|
||||
HOTSWAP_IN_BACKGROUND == secondSettings.HOTSWAP_IN_BACKGROUND &&
|
||||
|
||||
+7
@@ -33,6 +33,7 @@ class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> {
|
||||
private JCheckBox myCbSkipClassLoaders;
|
||||
private ClassFilterEditor mySteppingFilterEditor;
|
||||
private JCheckBox myCbSkipSimpleGetters;
|
||||
private JCheckBox myCbCheckFinallyOnPopFrame;
|
||||
|
||||
@Override
|
||||
public void reset(@NotNull DebuggerSettings settings) {
|
||||
@@ -45,6 +46,8 @@ class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> {
|
||||
|
||||
mySteppingFilterEditor.setFilters(settings.getSteppingFilters());
|
||||
mySteppingFilterEditor.setEnabled(settings.TRACING_FILTERS_ENABLED);
|
||||
|
||||
myCbCheckFinallyOnPopFrame.setSelected(settings.CHECK_FINALLY_ON_POP_FRAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,6 +62,8 @@ class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> {
|
||||
settings.SKIP_CLASSLOADERS = myCbSkipClassLoaders.isSelected();
|
||||
settings.TRACING_FILTERS_ENABLED = myCbStepInfoFiltersEnabled.isSelected();
|
||||
|
||||
settings.CHECK_FINALLY_ON_POP_FRAME = myCbCheckFinallyOnPopFrame.isSelected();
|
||||
|
||||
mySteppingFilterEditor.stopEditing();
|
||||
settings.setSteppingFilters(mySteppingFilterEditor.getFilters());
|
||||
}
|
||||
@@ -78,11 +83,13 @@ class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> {
|
||||
myCbSkipConstructors = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.skip.constructors"));
|
||||
myCbSkipClassLoaders = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.skip.classLoaders"));
|
||||
myCbSkipSimpleGetters = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.skip.simple.getters"));
|
||||
myCbCheckFinallyOnPopFrame = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.check.finally.on.pop"));
|
||||
myCbStepInfoFiltersEnabled = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.step.filters.list.header"));
|
||||
panel.add(myCbSkipSyntheticMethods, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0));
|
||||
panel.add(myCbSkipConstructors, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0));
|
||||
panel.add(myCbSkipClassLoaders, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0));
|
||||
panel.add(myCbSkipSimpleGetters, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0));
|
||||
panel.add(myCbCheckFinallyOnPopFrame, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0));
|
||||
panel.add(myCbStepInfoFiltersEnabled, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(8, 0, 0, 0),0, 0));
|
||||
|
||||
mySteppingFilterEditor = new ClassFilterEditor(JavaDebuggerSupport.getContextProjectForEditorFieldsInDebuggerConfigurables(), null, "reference.viewBreakpoints.classFilters.newPattern");
|
||||
|
||||
@@ -27,6 +27,8 @@ title.customize.data.views=Customize Data Views
|
||||
title.evaluating=Evaluating...
|
||||
error.modification.watchpoints.not.supported=Target VM does not support modification watchpoints
|
||||
error.native.method.exception=None of the frames through and including frame may be native
|
||||
warning.finally.block.detected=Non-empty finally block detected
|
||||
button.drop.anyway=Drop frame anyway
|
||||
action.remove.watch.text={0,choice, 1#Remove Watch|2#Remove Watches}
|
||||
progress.evaluating=Evaluating {0}
|
||||
action.resume.thread.text.resume=Resume
|
||||
@@ -221,6 +223,7 @@ label.debugger.general.configurable.skip.constructors=Skip &constructors
|
||||
label.debugger.general.configurable.skip.classLoaders=Skip class l&oaders
|
||||
label.debugger.general.configurable.skip.simple.getters=Skip simple &getters
|
||||
label.debugger.general.configurable.step.filters.list.header=Do not step &into the classes
|
||||
label.debugger.general.configurable.check.finally.on.pop=Ask if in finally block on pop frame
|
||||
label.threads.view.configurable.show.source.file.name=Show source file name
|
||||
label.threads.view.configurable.show.class.name=Show class name
|
||||
label.threads.view.configurable.show.line.number=Show &line number
|
||||
|
||||
Reference in New Issue
Block a user