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 - remember user answer
This commit is contained in:
@@ -23,7 +23,6 @@ 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.JavaDebugProcess;
|
||||
import com.intellij.debugger.engine.JavaStackFrame;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl;
|
||||
@@ -79,85 +78,73 @@ public class PopFrameAction extends DebuggerAction {
|
||||
if(debugProcess == null) {
|
||||
return;
|
||||
}
|
||||
if (DebuggerSettings.getInstance().CHECK_FINALLY_ON_POP_FRAME) {
|
||||
|
||||
if (!DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME)) {
|
||||
List<PsiStatement> statements = getFinallyStatements(debuggerContext.getSourcePosition());
|
||||
if (!statements.isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (PsiStatement statement : statements) {
|
||||
sb.append("\n").append(statement.getText());
|
||||
}
|
||||
int res = MessageDialogBuilder
|
||||
.yesNoCancel(UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)),
|
||||
DebuggerBundle.message("warning.finally.block.detected") + sb)
|
||||
.project(project)
|
||||
.icon(Messages.getWarningIcon())
|
||||
.yesText(DebuggerBundle.message("button.drop.anyway"))
|
||||
.noText(DebuggerBundle.message("button.execute.finally"))
|
||||
.cancelText(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 = value;
|
||||
}
|
||||
|
||||
@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();
|
||||
|
||||
switch (res) {
|
||||
case Messages.CANCEL : return;
|
||||
case Messages.OK : break; // drop frame
|
||||
case Messages.NO : // evaluate
|
||||
JavaDebugProcess process = debugProcess.getXdebugProcess();
|
||||
XExpressionImpl expression = XExpressionImpl.fromText(sb.toString());
|
||||
expression = XExpressionImpl.changeMode(expression, EvaluationMode.CODE_FRAGMENT);
|
||||
XDebuggerEvaluator evaluator = stackFrame.getEvaluator();
|
||||
if (evaluator != null) {
|
||||
evaluator.evaluate(expression, new XDebuggerEvaluator.XEvaluationCallback() {
|
||||
if (DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME)) {
|
||||
evaluateAndPop(project, stackFrame, debuggerContext, debugProcess, sb);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
int res = MessageDialogBuilder
|
||||
.yesNoCancel(UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)),
|
||||
DebuggerBundle.message("warning.finally.block.detected") + sb)
|
||||
.project(project)
|
||||
.icon(Messages.getWarningIcon())
|
||||
.yesText(DebuggerBundle.message("button.execute.finally"))
|
||||
.noText(DebuggerBundle.message("button.drop.anyway"))
|
||||
.cancelText(CommonBundle.message("button.cancel"))
|
||||
.doNotAsk(
|
||||
new DialogWrapper.DoNotAskOption() {
|
||||
@Override
|
||||
public void evaluated(@NotNull XValue result) {
|
||||
debugProcess.getManagerThread().schedule(debugProcess.createPopFrameCommand(debuggerContext, stackFrame.getStackFrameProxy()));
|
||||
public boolean isToBeShown() {
|
||||
return !DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME) &&
|
||||
!DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void errorOccurred(@NotNull final String errorMessage) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Messages
|
||||
.showMessageDialog(project, DebuggerBundle.message("error.executing.finally", errorMessage),
|
||||
UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)), Messages.getErrorIcon());
|
||||
}
|
||||
});
|
||||
public void setToBeShown(boolean value, int exitCode) {
|
||||
if (!value) {
|
||||
DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME =
|
||||
exitCode == Messages.YES ? DebuggerSettings.EVALUATE_FINALLY_ALWAYS : DebuggerSettings.EVALUATE_FINALLY_NEVER;
|
||||
}
|
||||
else {
|
||||
DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_ASK;
|
||||
}
|
||||
}
|
||||
}, stackFrame.getSourcePosition());
|
||||
|
||||
@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();
|
||||
|
||||
switch (res) {
|
||||
case Messages.CANCEL:
|
||||
return;
|
||||
}
|
||||
else {
|
||||
Messages.showMessageDialog(project, XDebuggerBundle.message("xdebugger.evaluate.stack.frame.has.not.evaluator"),
|
||||
UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)),
|
||||
Messages.getErrorIcon());
|
||||
}
|
||||
case Messages.NO:
|
||||
break;
|
||||
case Messages.YES: // evaluate finally
|
||||
evaluateAndPop(project, stackFrame, debuggerContext, debugProcess, sb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,6 +160,40 @@ public class PopFrameAction extends DebuggerAction {
|
||||
}
|
||||
}
|
||||
|
||||
private static void evaluateAndPop(final Project project,
|
||||
final JavaStackFrame stackFrame,
|
||||
final DebuggerContextImpl debuggerContext,
|
||||
final DebugProcessImpl debugProcess, StringBuilder sb) {
|
||||
XExpressionImpl expression = XExpressionImpl.fromText(sb.toString());
|
||||
expression = XExpressionImpl.changeMode(expression, EvaluationMode.CODE_FRAGMENT);
|
||||
XDebuggerEvaluator evaluator = stackFrame.getEvaluator();
|
||||
if (evaluator != null) {
|
||||
evaluator.evaluate(expression, new XDebuggerEvaluator.XEvaluationCallback() {
|
||||
@Override
|
||||
public void evaluated(@NotNull XValue result) {
|
||||
debugProcess.getManagerThread().schedule(debugProcess.createPopFrameCommand(debuggerContext, stackFrame.getStackFrameProxy()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void errorOccurred(@NotNull final String errorMessage) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Messages
|
||||
.showMessageDialog(project, DebuggerBundle.message("error.executing.finally", errorMessage),
|
||||
UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)), Messages.getErrorIcon());
|
||||
}
|
||||
});
|
||||
}
|
||||
}, stackFrame.getSourcePosition());
|
||||
}
|
||||
else {
|
||||
Messages.showMessageDialog(project, XDebuggerBundle.message("xdebugger.evaluate.stack.frame.has.not.evaluator"),
|
||||
UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)),
|
||||
Messages.getErrorIcon());
|
||||
}
|
||||
}
|
||||
|
||||
private static List<PsiStatement> getFinallyStatements(SourcePosition position) {
|
||||
List<PsiStatement> res = new ArrayList<PsiStatement>();
|
||||
PsiElement element = position.getFile().findElementAt(position.getOffset());
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.classFilter.ClassFilter;
|
||||
import com.intellij.util.containers.hash.LinkedHashMap;
|
||||
import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters;
|
||||
@@ -55,6 +56,10 @@ public class DebuggerSettings implements Cloneable, PersistentStateComponent<Ele
|
||||
@NonNls public static final String RUN_HOTSWAP_NEVER = "RunHotswapNever";
|
||||
@NonNls public static final String RUN_HOTSWAP_ASK = "RunHotswapAsk";
|
||||
|
||||
@NonNls public static final String EVALUATE_FINALLY_ALWAYS = "EvaluateFinallyAlways";
|
||||
@NonNls public static final String EVALUATE_FINALLY_NEVER = "EvaluateFinallyNever";
|
||||
@NonNls public static final String EVALUATE_FINALLY_ASK = "EvaluateFinallyAsk";
|
||||
|
||||
public boolean TRACING_FILTERS_ENABLED;
|
||||
public int DEBUGGER_TRANSPORT;
|
||||
public boolean FORCE_CLASSIC_VM;
|
||||
@@ -74,7 +79,7 @@ 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;
|
||||
public String EVALUATE_FINALLY_ON_POP_FRAME = EVALUATE_FINALLY_ASK;
|
||||
|
||||
private ClassFilter[] mySteppingFilters = ClassFilter.EMPTY_ARRAY;
|
||||
|
||||
@@ -144,7 +149,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 &&
|
||||
StringUtil.equals(EVALUATE_FINALLY_ON_POP_FRAME, secondSettings.EVALUATE_FINALLY_ON_POP_FRAME) &&
|
||||
FORCE_CLASSIC_VM == secondSettings.FORCE_CLASSIC_VM &&
|
||||
DISABLE_JIT == secondSettings.DISABLE_JIT &&
|
||||
HOTSWAP_IN_BACKGROUND == secondSettings.HOTSWAP_IN_BACKGROUND &&
|
||||
|
||||
+49
-5
@@ -22,6 +22,7 @@ import com.intellij.ui.classFilter.ClassFilterEditor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
@@ -33,7 +34,9 @@ class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> {
|
||||
private JCheckBox myCbSkipClassLoaders;
|
||||
private ClassFilterEditor mySteppingFilterEditor;
|
||||
private JCheckBox myCbSkipSimpleGetters;
|
||||
private JCheckBox myCbCheckFinallyOnPopFrame;
|
||||
private JRadioButton myRbEvaluateFinallyAlways;
|
||||
private JRadioButton myRbEvaluateFinallyNever;
|
||||
private JRadioButton myRbEvaluateFinallyAsk;
|
||||
|
||||
@Override
|
||||
public void reset(@NotNull DebuggerSettings settings) {
|
||||
@@ -47,7 +50,15 @@ class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> {
|
||||
mySteppingFilterEditor.setFilters(settings.getSteppingFilters());
|
||||
mySteppingFilterEditor.setEnabled(settings.TRACING_FILTERS_ENABLED);
|
||||
|
||||
myCbCheckFinallyOnPopFrame.setSelected(settings.CHECK_FINALLY_ON_POP_FRAME);
|
||||
if (DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(settings.EVALUATE_FINALLY_ON_POP_FRAME)) {
|
||||
myRbEvaluateFinallyAlways.setSelected(true);
|
||||
}
|
||||
else if (DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(settings.EVALUATE_FINALLY_ON_POP_FRAME)) {
|
||||
myRbEvaluateFinallyNever.setSelected(true);
|
||||
}
|
||||
else {
|
||||
myRbEvaluateFinallyAsk.setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,7 +73,15 @@ class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> {
|
||||
settings.SKIP_CLASSLOADERS = myCbSkipClassLoaders.isSelected();
|
||||
settings.TRACING_FILTERS_ENABLED = myCbStepInfoFiltersEnabled.isSelected();
|
||||
|
||||
settings.CHECK_FINALLY_ON_POP_FRAME = myCbCheckFinallyOnPopFrame.isSelected();
|
||||
if (myRbEvaluateFinallyAlways.isSelected()) {
|
||||
settings.EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_ALWAYS;
|
||||
}
|
||||
else if (myRbEvaluateFinallyNever.isSelected()) {
|
||||
settings.EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_NEVER;
|
||||
}
|
||||
else {
|
||||
settings.EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_ASK;
|
||||
}
|
||||
|
||||
mySteppingFilterEditor.stopEditing();
|
||||
settings.setSteppingFilters(mySteppingFilterEditor.getFilters());
|
||||
@@ -83,13 +102,11 @@ 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");
|
||||
@@ -101,6 +118,33 @@ class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> {
|
||||
mySteppingFilterEditor.setEnabled(myCbStepInfoFiltersEnabled.isSelected());
|
||||
}
|
||||
});
|
||||
|
||||
myRbEvaluateFinallyAlways = new JRadioButton(DebuggerBundle.message("label.debugger.general.configurable.evaluate.finally.always"));
|
||||
myRbEvaluateFinallyNever = new JRadioButton(DebuggerBundle.message("label.debugger.general.configurable.evaluate.finally.never"));
|
||||
myRbEvaluateFinallyAsk = new JRadioButton(DebuggerBundle.message("label.debugger.general.configurable.evaluate.finally.ask"));
|
||||
|
||||
int cbLeftOffset = 0;
|
||||
final Border border = myCbSkipSimpleGetters.getBorder();
|
||||
if (border != null) {
|
||||
final Insets insets = border.getBorderInsets(myCbSkipSimpleGetters);
|
||||
if (insets != null) {
|
||||
cbLeftOffset = insets.left;
|
||||
}
|
||||
}
|
||||
|
||||
final ButtonGroup group = new ButtonGroup();
|
||||
group.add(myRbEvaluateFinallyAlways);
|
||||
group.add(myRbEvaluateFinallyNever);
|
||||
group.add(myRbEvaluateFinallyAsk);
|
||||
final Box box = Box.createHorizontalBox();
|
||||
box.add(myRbEvaluateFinallyAlways);
|
||||
box.add(myRbEvaluateFinallyNever);
|
||||
box.add(myRbEvaluateFinallyAsk);
|
||||
final JPanel evalFinallyPanel = new JPanel(new BorderLayout());
|
||||
evalFinallyPanel.add(box, BorderLayout.CENTER);
|
||||
evalFinallyPanel.add(new JLabel(DebuggerBundle.message("label.debugger.general.configurable.evaluate.finally.on.pop")), BorderLayout.WEST);
|
||||
panel.add(evalFinallyPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, cbLeftOffset, 0, 0), 0, 0));
|
||||
|
||||
return panel;
|
||||
}
|
||||
}
|
||||
@@ -225,7 +225,10 @@ 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.debugger.general.configurable.evaluate.finally.on.pop=Evaluate finally blocks on pop frame:
|
||||
label.debugger.general.configurable.evaluate.finally.always=&Always
|
||||
label.debugger.general.configurable.evaluate.finally.never=N&ever
|
||||
label.debugger.general.configurable.evaluate.finally.ask=As&k
|
||||
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