blob: f89ae5ce8292fb13d37e8b4a2e37f040ec8a6e45 [file] [log] [blame]
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -08001/*
2 * Copyright 2000-2009 JetBrains s.r.o.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * @author Eugene Zhuravlev
19 */
20package com.intellij.debugger.actions;
21
Tor Norbyee782c572014-09-18 11:43:07 -070022import com.intellij.CommonBundle;
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -080023import com.intellij.debugger.DebuggerBundle;
Tor Norbyee782c572014-09-18 11:43:07 -070024import com.intellij.debugger.SourcePosition;
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -080025import com.intellij.debugger.engine.DebugProcessImpl;
Tor Norbyec667c1f2014-05-28 17:06:51 -070026import com.intellij.debugger.engine.JavaStackFrame;
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -080027import com.intellij.debugger.engine.SuspendContextImpl;
28import com.intellij.debugger.impl.DebuggerContextImpl;
29import com.intellij.debugger.jdi.StackFrameProxyImpl;
30import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
Tor Norbyee782c572014-09-18 11:43:07 -070031import com.intellij.debugger.settings.DebuggerSettings;
32import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
33import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl;
34import com.intellij.debugger.ui.impl.watch.ThreadDescriptorImpl;
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -080035import com.intellij.idea.ActionsBundle;
36import com.intellij.openapi.actionSystem.ActionPlaces;
37import com.intellij.openapi.actionSystem.AnActionEvent;
Tor Norbye32218cc2013-10-08 09:48:09 -070038import com.intellij.openapi.actionSystem.CommonDataKeys;
Tor Norbyee782c572014-09-18 11:43:07 -070039import com.intellij.openapi.application.ApplicationManager;
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -080040import com.intellij.openapi.project.Project;
Tor Norbyee782c572014-09-18 11:43:07 -070041import com.intellij.openapi.ui.DialogWrapper;
42import com.intellij.openapi.ui.MessageDialogBuilder;
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -080043import com.intellij.openapi.ui.Messages;
Tor Norbyee782c572014-09-18 11:43:07 -070044import com.intellij.psi.PsiCodeBlock;
45import com.intellij.psi.PsiElement;
46import com.intellij.psi.PsiStatement;
47import com.intellij.psi.PsiTryStatement;
48import com.intellij.psi.util.PsiTreeUtil;
49import com.intellij.util.containers.ContainerUtil;
50import com.intellij.util.ui.UIUtil;
Tor Norbyec667c1f2014-05-28 17:06:51 -070051import com.intellij.xdebugger.XDebugSession;
Tor Norbyee782c572014-09-18 11:43:07 -070052import com.intellij.xdebugger.XDebuggerBundle;
Tor Norbyec667c1f2014-05-28 17:06:51 -070053import com.intellij.xdebugger.XDebuggerManager;
Tor Norbyee782c572014-09-18 11:43:07 -070054import com.intellij.xdebugger.evaluation.EvaluationMode;
55import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
Tor Norbyec667c1f2014-05-28 17:06:51 -070056import com.intellij.xdebugger.frame.XStackFrame;
Tor Norbyee782c572014-09-18 11:43:07 -070057import com.intellij.xdebugger.frame.XValue;
58import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl;
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -080059import com.sun.jdi.InvalidStackFrameException;
60import com.sun.jdi.NativeMethodException;
61import com.sun.jdi.VMDisconnectedException;
Tor Norbyee782c572014-09-18 11:43:07 -070062import org.jetbrains.annotations.NotNull;
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -080063import org.jetbrains.annotations.Nullable;
64
Tor Norbyee782c572014-09-18 11:43:07 -070065import java.util.ArrayList;
66import java.util.List;
67
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -080068public class PopFrameAction extends DebuggerAction {
69 public void actionPerformed(AnActionEvent e) {
Tor Norbyee782c572014-09-18 11:43:07 -070070 final Project project = e.getData(CommonDataKeys.PROJECT);
71 final JavaStackFrame stackFrame = getStackFrame(e);
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -080072 if(stackFrame == null) {
73 return;
74 }
75 try {
Tor Norbyee782c572014-09-18 11:43:07 -070076 final DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
77 final DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -080078 if(debugProcess == null) {
79 return;
80 }
Tor Norbyee782c572014-09-18 11:43:07 -070081
82 if (!DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME)) {
83 List<PsiStatement> statements = getFinallyStatements(debuggerContext.getSourcePosition());
84 if (!statements.isEmpty()) {
85 StringBuilder sb = new StringBuilder();
86 for (PsiStatement statement : statements) {
87 sb.append("\n").append(statement.getText());
88 }
89 if (DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME)) {
90 evaluateAndPop(project, stackFrame, debuggerContext, debugProcess, sb);
91 return;
92 }
93 else {
94 int res = MessageDialogBuilder
95 .yesNoCancel(UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)),
96 DebuggerBundle.message("warning.finally.block.detected") + sb)
97 .project(project)
98 .icon(Messages.getWarningIcon())
99 .yesText(DebuggerBundle.message("button.execute.finally"))
100 .noText(DebuggerBundle.message("button.drop.anyway"))
101 .cancelText(CommonBundle.message("button.cancel"))
102 .doNotAsk(
103 new DialogWrapper.DoNotAskOption() {
104 @Override
105 public boolean isToBeShown() {
106 return !DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME) &&
107 !DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME);
108 }
109
110 @Override
111 public void setToBeShown(boolean value, int exitCode) {
112 if (!value) {
113 DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME =
114 exitCode == Messages.YES ? DebuggerSettings.EVALUATE_FINALLY_ALWAYS : DebuggerSettings.EVALUATE_FINALLY_NEVER;
115 }
116 else {
117 DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_ASK;
118 }
119 }
120
121 @Override
122 public boolean canBeHidden() {
123 return true;
124 }
125
126 @Override
127 public boolean shouldSaveOptionsOnCancel() {
128 return false;
129 }
130
131 @NotNull
132 @Override
133 public String getDoNotShowMessage() {
134 return CommonBundle.message("dialog.options.do.not.show");
135 }
136 })
137 .show();
138
139 switch (res) {
140 case Messages.CANCEL:
141 return;
142 case Messages.NO:
143 break;
144 case Messages.YES: // evaluate finally
145 evaluateAndPop(project, stackFrame, debuggerContext, debugProcess, sb);
146 return;
147 }
148 }
149 }
150 }
151 debugProcess.getManagerThread().schedule(debugProcess.createPopFrameCommand(debuggerContext, stackFrame.getStackFrameProxy()));
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -0800152 }
153 catch (NativeMethodException e2){
Tor Norbyee782c572014-09-18 11:43:07 -0700154 Messages.showMessageDialog(project, DebuggerBundle.message("error.native.method.exception"),
155 UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)), Messages.getErrorIcon());
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -0800156 }
157 catch (InvalidStackFrameException ignored) {
158 }
Tor Norbyee782c572014-09-18 11:43:07 -0700159 catch(VMDisconnectedException ignored) {
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -0800160 }
161 }
162
Tor Norbyee782c572014-09-18 11:43:07 -0700163 private static void evaluateAndPop(final Project project,
164 final JavaStackFrame stackFrame,
165 final DebuggerContextImpl debuggerContext,
166 final DebugProcessImpl debugProcess, StringBuilder sb) {
167 XDebuggerEvaluator evaluator = stackFrame.getEvaluator();
168 if (evaluator != null) {
169 evaluator.evaluate(XExpressionImpl.fromText(sb.toString(), EvaluationMode.CODE_FRAGMENT),
170 new XDebuggerEvaluator.XEvaluationCallback() {
171 @Override
172 public void evaluated(@NotNull XValue result) {
173 debugProcess.getManagerThread()
174 .schedule(debugProcess.createPopFrameCommand(debuggerContext, stackFrame.getStackFrameProxy()));
175 }
176
177 @Override
178 public void errorOccurred(@NotNull final String errorMessage) {
179 ApplicationManager.getApplication().invokeLater(new Runnable() {
180 @Override
181 public void run() {
182 Messages
183 .showMessageDialog(project, DebuggerBundle.message("error.executing.finally", errorMessage),
184 UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)),
185 Messages.getErrorIcon());
186 }
187 });
188 }
189 }, stackFrame.getSourcePosition());
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -0800190 }
Tor Norbyee782c572014-09-18 11:43:07 -0700191 else {
192 Messages.showMessageDialog(project, XDebuggerBundle.message("xdebugger.evaluate.stack.frame.has.not.evaluator"),
193 UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)),
194 Messages.getErrorIcon());
195 }
196 }
197
198 private static List<PsiStatement> getFinallyStatements(SourcePosition position) {
199 List<PsiStatement> res = new ArrayList<PsiStatement>();
200 PsiElement element = position.getFile().findElementAt(position.getOffset());
201 PsiTryStatement tryStatement = PsiTreeUtil.getParentOfType(element, PsiTryStatement.class);
202 while (tryStatement != null) {
203 PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
204 if (finallyBlock != null) {
205 ContainerUtil.addAll(res, finallyBlock.getStatements());
206 }
207 tryStatement = PsiTreeUtil.getParentOfType(tryStatement, PsiTryStatement.class);
208 }
209 return res;
210 }
211
212 @Nullable
213 private static JavaStackFrame getStackFrame(AnActionEvent e) {
214 //DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
215 //if(selectedNode != null) {
216 // NodeDescriptorImpl descriptor = selectedNode.getDescriptor();
217 // if(descriptor instanceof StackFrameDescriptorImpl) {
218 // if(selectedNode.getNextSibling() != null) {
219 // StackFrameDescriptorImpl frameDescriptor = ((StackFrameDescriptorImpl)descriptor);
220 // return frameDescriptor.getFrameProxy();
221 // }
222 // return null;
223 // }
224 // else if(descriptor instanceof ThreadDescriptorImpl || descriptor instanceof ThreadGroupDescriptorImpl) {
225 // return null;
226 // }
227 //}
Tor Norbyec667c1f2014-05-28 17:06:51 -0700228
229 Project project = e.getProject();
230 if (project != null) {
231 XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession();
232 if (session != null) {
233 XStackFrame frame = session.getCurrentStackFrame();
234 if (frame instanceof JavaStackFrame) {
235 StackFrameProxyImpl proxy = ((JavaStackFrame)frame).getStackFrameProxy();
Tor Norbyee782c572014-09-18 11:43:07 -0700236 return !proxy.isBottom() ? ((JavaStackFrame)frame) : null;
Tor Norbyec667c1f2014-05-28 17:06:51 -0700237 }
238 }
239 }
240
Tor Norbyee782c572014-09-18 11:43:07 -0700241 //DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
242 //StackFrameProxyImpl frameProxy = debuggerContext.getFrameProxy();
243 //
244 //if(frameProxy == null || frameProxy.isBottom()) {
245 // return null;
246 //}
247 //return frameProxy;
248 return null;
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -0800249 }
250
251 private static boolean isAtBreakpoint(AnActionEvent e) {
252 DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
253 if(selectedNode != null && selectedNode.getDescriptor() instanceof StackFrameDescriptorImpl) {
254 DebuggerTreeNodeImpl parent = selectedNode.getParent();
255 if(parent != null) {
256 return ((ThreadDescriptorImpl)parent.getDescriptor()).isAtBreakpoint();
257 }
258 }
259 DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
260 SuspendContextImpl suspendContext = debuggerContext.getSuspendContext();
261 return suspendContext != null && debuggerContext.getThreadProxy() == suspendContext.getThread();
262 }
263
264 public void update(AnActionEvent e) {
265 boolean enable = false;
Tor Norbyee782c572014-09-18 11:43:07 -0700266 JavaStackFrame stackFrame = getStackFrame(e);
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -0800267
Tor Norbyee782c572014-09-18 11:43:07 -0700268 if(stackFrame != null && isAtBreakpoint(e)) {
269 VirtualMachineProxyImpl virtualMachineProxy = stackFrame.getStackFrameProxy().getVirtualMachine();
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -0800270 enable = virtualMachineProxy.canPopFrames();
271 }
272
Tor Norbyee782c572014-09-18 11:43:07 -0700273 if(ActionPlaces.isMainMenuOrActionSearch(e.getPlace()) || ActionPlaces.DEBUGGER_TOOLBAR.equals(e.getPlace())) {
Jean-Baptiste Querub56ea2a2013-01-08 11:11:20 -0800274 e.getPresentation().setEnabled(enable);
275 }
276 else {
277 e.getPresentation().setVisible(enable);
278 }
279 }
280}