2 * Copyright 2000-2016 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @author: Eugene Zhuravlev
22 package com.intellij.debugger.engine;
24 import com.intellij.debugger.SourcePosition;
25 import com.intellij.debugger.engine.evaluation.EvaluateException;
26 import com.intellij.debugger.engine.jdi.StackFrameProxy;
27 import com.intellij.debugger.impl.DebuggerUtilsEx;
28 import com.intellij.debugger.impl.PositionUtil;
29 import com.intellij.debugger.jdi.StackFrameProxyImpl;
30 import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
31 import com.intellij.debugger.settings.DebuggerSettings;
32 import com.intellij.openapi.application.ApplicationManager;
33 import com.intellij.openapi.diagnostic.Logger;
34 import com.intellij.openapi.util.Computable;
35 import com.intellij.psi.PsiElement;
36 import com.intellij.util.Range;
37 import com.sun.jdi.Location;
38 import com.sun.jdi.Method;
39 import com.sun.jdi.VMDisconnectedException;
40 import com.sun.jdi.request.StepRequest;
41 import org.intellij.lang.annotations.MagicConstant;
42 import org.jetbrains.annotations.NotNull;
43 import org.jetbrains.annotations.Nullable;
45 public class RequestHint {
46 public static final int STOP = 0;
47 public static final int RESUME = -100;
49 private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.RequestHint");
50 @MagicConstant (intValues = {StepRequest.STEP_MIN, StepRequest.STEP_LINE})
51 private final int mySize;
52 @MagicConstant (intValues = {StepRequest.STEP_INTO, StepRequest.STEP_OVER, StepRequest.STEP_OUT})
53 private final int myDepth;
54 private final SourcePosition myPosition;
55 private final int myFrameCount;
56 private boolean mySteppedOut = false;
59 private final MethodFilter myMethodFilter;
60 private boolean myTargetMethodMatched = false;
62 private boolean myIgnoreFilters = false;
63 private boolean myResetIgnoreFilters = false;
64 private boolean myRestoreBreakpoints = false;
66 public RequestHint(final ThreadReferenceProxyImpl stepThread, final SuspendContextImpl suspendContext, @NotNull MethodFilter methodFilter) {
67 this(stepThread, suspendContext, StepRequest.STEP_LINE, StepRequest.STEP_INTO, methodFilter);
70 public RequestHint(final ThreadReferenceProxyImpl stepThread,
71 final SuspendContextImpl suspendContext,
72 @MagicConstant (intValues = {StepRequest.STEP_INTO, StepRequest.STEP_OVER, StepRequest.STEP_OUT}) int depth) {
73 this(stepThread, suspendContext, StepRequest.STEP_LINE, depth, null);
76 private RequestHint(final ThreadReferenceProxyImpl stepThread,
77 final SuspendContextImpl suspendContext,
78 @MagicConstant (intValues = {StepRequest.STEP_MIN, StepRequest.STEP_LINE}) int stepSize,
79 @MagicConstant (intValues = {StepRequest.STEP_INTO, StepRequest.STEP_OVER, StepRequest.STEP_OUT}) int depth,
80 @Nullable MethodFilter methodFilter) {
83 myMethodFilter = methodFilter;
86 SourcePosition position = null;
88 frameCount = stepThread.frameCount();
90 position = ContextUtil.getSourcePosition(new StackFrameContext() {
91 public StackFrameProxy getFrameProxy() {
93 return stepThread.frame(0);
95 catch (EvaluateException e) {
102 public DebugProcess getDebugProcess() {
103 return suspendContext.getDebugProcess();
107 catch (Exception e) {
111 myFrameCount = frameCount;
112 myPosition = position;
116 public void setIgnoreFilters(boolean ignoreFilters) {
117 myIgnoreFilters = ignoreFilters;
120 public void setResetIgnoreFilters(boolean resetIgnoreFilters) {
121 myResetIgnoreFilters = resetIgnoreFilters;
124 public boolean isResetIgnoreFilters() {
125 return myResetIgnoreFilters;
128 public void setRestoreBreakpoints(boolean restoreBreakpoints) {
129 myRestoreBreakpoints = restoreBreakpoints;
132 public boolean isRestoreBreakpoints() {
133 return myRestoreBreakpoints;
136 public boolean isIgnoreFilters() {
137 return myIgnoreFilters;
140 @MagicConstant (intValues = {StepRequest.STEP_MIN, StepRequest.STEP_LINE})
141 public int getSize() {
145 @MagicConstant (intValues = {StepRequest.STEP_INTO, StepRequest.STEP_OVER, StepRequest.STEP_OUT})
146 public int getDepth() {
151 public MethodFilter getMethodFilter() {
152 return myMethodFilter;
155 public boolean wasStepTargetMethodMatched() {
156 return myMethodFilter instanceof BreakpointStepMethodFilter || myTargetMethodMatched;
159 private boolean isTheSameFrame(SuspendContextImpl context) {
160 if (mySteppedOut) return false;
161 final ThreadReferenceProxyImpl contextThread = context.getThread();
162 if (contextThread != null) {
164 int currentDepth = contextThread.frameCount();
165 if (currentDepth < myFrameCount) mySteppedOut = true;
166 return currentDepth == myFrameCount;
168 catch (EvaluateException ignored) {
174 private boolean isOnTheSameLine(SourcePosition locationPosition) {
175 if (myMethodFilter == null) {
176 return myPosition.getLine() == locationPosition.getLine();
179 Range<Integer> exprLines = myMethodFilter.getCallingExpressionLines();
180 return exprLines != null && exprLines.isWithin(locationPosition.getLine());
184 private int reached(MethodFilter filter, SuspendContextImpl context) {
185 if (filter instanceof ActionMethodFilter) {
186 return ((ActionMethodFilter)filter).onReached(context, this);
191 public int getNextStepDepth(final SuspendContextImpl context) {
193 final StackFrameProxyImpl frameProxy = context.getFrameProxy();
195 // smart step feature stop check
196 if (myMethodFilter != null &&
197 frameProxy != null &&
198 !(myMethodFilter instanceof BreakpointStepMethodFilter) &&
199 myMethodFilter.locationMatches(context.getDebugProcess(), frameProxy.location()) &&
200 !isTheSameFrame(context)
202 myTargetMethodMatched = true;
203 return reached(myMethodFilter, context);
206 if ((myDepth == StepRequest.STEP_OVER || myDepth == StepRequest.STEP_INTO) && myPosition != null) {
207 SourcePosition locationPosition = ContextUtil.getSourcePosition(context);
208 if (locationPosition != null) {
209 Integer resultDepth = ApplicationManager.getApplication().runReadAction(new Computable<Integer>() {
210 public Integer compute() {
211 if (myPosition.getFile().equals(locationPosition.getFile()) && isTheSameFrame(context) && !mySteppedOut) {
212 return isOnTheSameLine(locationPosition) ? myDepth : STOP;
217 if (resultDepth != null) {
218 return resultDepth.intValue();
225 final DebuggerSettings settings = DebuggerSettings.getInstance();
227 if ((myMethodFilter != null || (settings.SKIP_SYNTHETIC_METHODS && !myIgnoreFilters))&& frameProxy != null) {
228 final Location location = frameProxy.location();
229 if (location != null) {
230 if (DebuggerUtils.isSynthetic(location.method())) {
236 if (!myIgnoreFilters) {
237 if(settings.SKIP_GETTERS) {
238 boolean isGetter = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>(){
239 public Boolean compute() {
240 PsiElement contextElement = ContextUtil.getContextElement(context);
241 return contextElement != null && DebuggerUtils.isInsideSimpleGetter(contextElement);
246 return StepRequest.STEP_OUT;
250 if (frameProxy != null) {
251 if (settings.SKIP_CONSTRUCTORS) {
252 final Location location = frameProxy.location();
253 if (location != null) {
254 final Method method = location.method();
255 if (method != null && method.isConstructor()) {
256 return StepRequest.STEP_OUT;
261 if (settings.SKIP_CLASSLOADERS) {
262 final Location location = frameProxy.location();
263 if (location != null && DebuggerUtilsEx.isAssignableFrom("java.lang.ClassLoader", location.declaringType())) {
264 return StepRequest.STEP_OUT;
269 for (ExtraSteppingFilter filter : ExtraSteppingFilter.EP_NAME.getExtensions()) {
271 if (filter.isApplicable(context)) return filter.getStepRequestDepth(context);
273 catch (Exception e) {LOG.error(e);}
274 catch (AssertionError e) {LOG.error(e);}
277 // smart step feature
278 if (myMethodFilter != null && !mySteppedOut) {
279 return StepRequest.STEP_OUT;
282 catch (VMDisconnectedException ignored) {
284 catch (EvaluateException e) {