more access for kotlin debugger
[idea/community.git] / java / debugger / impl / src / com / intellij / debugger / engine / RequestHint.java
1 /*
2  * Copyright 2000-2016 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  * Date: Jul 23, 2002
20  * Time: 11:10:11 AM
21  */
22 package com.intellij.debugger.engine;
23
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.jdi.StackFrameProxyImpl;
29 import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
30 import com.intellij.debugger.settings.DebuggerSettings;
31 import com.intellij.openapi.application.ApplicationManager;
32 import com.intellij.openapi.diagnostic.Logger;
33 import com.intellij.openapi.util.Computable;
34 import com.intellij.psi.PsiElement;
35 import com.intellij.util.Range;
36 import com.sun.jdi.Location;
37 import com.sun.jdi.Method;
38 import com.sun.jdi.VMDisconnectedException;
39 import com.sun.jdi.request.StepRequest;
40 import org.intellij.lang.annotations.MagicConstant;
41 import org.jetbrains.annotations.NotNull;
42 import org.jetbrains.annotations.Nullable;
43
44 public class RequestHint {
45   public static final int STOP = 0;
46   public static final int RESUME = -100;
47
48   private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.RequestHint");
49   @MagicConstant (intValues = {StepRequest.STEP_MIN, StepRequest.STEP_LINE})
50   private final int mySize;
51   @MagicConstant (intValues = {StepRequest.STEP_INTO, StepRequest.STEP_OVER, StepRequest.STEP_OUT})
52   private final int myDepth;
53   private final SourcePosition myPosition;
54   private final int myFrameCount;
55   private boolean mySteppedOut = false;
56
57   @Nullable
58   private final MethodFilter myMethodFilter;
59   private boolean myTargetMethodMatched = false;
60
61   private boolean myIgnoreFilters = false;
62   private boolean myResetIgnoreFilters = false;
63   private boolean myRestoreBreakpoints = false;
64
65   public RequestHint(final ThreadReferenceProxyImpl stepThread, final SuspendContextImpl suspendContext, @NotNull MethodFilter methodFilter) {
66     this(stepThread, suspendContext, StepRequest.STEP_LINE, StepRequest.STEP_INTO, methodFilter);
67   }
68
69   public RequestHint(final ThreadReferenceProxyImpl stepThread,
70                      final SuspendContextImpl suspendContext,
71                      @MagicConstant (intValues = {StepRequest.STEP_INTO, StepRequest.STEP_OVER, StepRequest.STEP_OUT}) int depth) {
72     this(stepThread, suspendContext, StepRequest.STEP_LINE, depth, null);
73   }
74
75   private RequestHint(final ThreadReferenceProxyImpl stepThread,
76                       final SuspendContextImpl suspendContext,
77                       @MagicConstant (intValues = {StepRequest.STEP_MIN, StepRequest.STEP_LINE}) int stepSize,
78                       @MagicConstant (intValues = {StepRequest.STEP_INTO, StepRequest.STEP_OVER, StepRequest.STEP_OUT}) int depth,
79                       @Nullable MethodFilter methodFilter) {
80     mySize = stepSize;
81     myDepth = depth;
82     myMethodFilter = methodFilter;
83
84     int frameCount = 0;
85     SourcePosition position = null;
86     try {
87       frameCount = stepThread.frameCount();
88
89       position = ContextUtil.getSourcePosition(new StackFrameContext() {
90         public StackFrameProxy getFrameProxy() {
91           try {
92             return stepThread.frame(0);
93           }
94           catch (EvaluateException e) {
95             LOG.debug(e);
96             return null;
97           }
98         }
99
100         @NotNull
101         public DebugProcess getDebugProcess() {
102           return suspendContext.getDebugProcess();
103         }
104       });
105     }
106     catch (Exception e) {
107       LOG.info(e);
108     }
109     finally {
110       myFrameCount = frameCount;
111       myPosition = position;
112     }
113   }
114
115   public void setIgnoreFilters(boolean ignoreFilters) {
116     myIgnoreFilters = ignoreFilters;
117   }
118
119   public void setResetIgnoreFilters(boolean resetIgnoreFilters) {
120     myResetIgnoreFilters = resetIgnoreFilters;
121   }
122
123   public boolean isResetIgnoreFilters() {
124     return myResetIgnoreFilters;
125   }
126
127   public void setRestoreBreakpoints(boolean restoreBreakpoints) {
128     myRestoreBreakpoints = restoreBreakpoints;
129   }
130
131   public boolean isRestoreBreakpoints() {
132     return myRestoreBreakpoints;
133   }
134
135   public boolean isIgnoreFilters() {
136     return myIgnoreFilters;
137   }
138
139   @MagicConstant (intValues = {StepRequest.STEP_MIN, StepRequest.STEP_LINE})
140   public int getSize() {
141     return mySize;
142   }
143
144   @MagicConstant (intValues = {StepRequest.STEP_INTO, StepRequest.STEP_OVER, StepRequest.STEP_OUT})
145   public int getDepth() {
146     return myDepth;
147   }
148
149   @Nullable
150   public MethodFilter getMethodFilter() {
151     return myMethodFilter;
152   }
153
154   public boolean wasStepTargetMethodMatched() {
155     return myMethodFilter instanceof BreakpointStepMethodFilter || myTargetMethodMatched;
156   }
157
158   protected boolean isTheSameFrame(SuspendContextImpl context) {
159     if (mySteppedOut) return false;
160     final ThreadReferenceProxyImpl contextThread = context.getThread();
161     if (contextThread != null) {
162       try {
163         int currentDepth = contextThread.frameCount();
164         if (currentDepth < myFrameCount) mySteppedOut = true;
165         return currentDepth == myFrameCount;
166       }
167       catch (EvaluateException ignored) {
168       }
169     }
170     return false;
171   }
172
173   private boolean isOnTheSameLine(SourcePosition locationPosition) {
174     if (myMethodFilter == null) {
175       return myPosition.getLine() == locationPosition.getLine();
176     }
177     else {
178       Range<Integer> exprLines = myMethodFilter.getCallingExpressionLines();
179       return exprLines != null && exprLines.isWithin(locationPosition.getLine());
180     }
181   }
182
183   private int reached(MethodFilter filter, SuspendContextImpl context) {
184     if (filter instanceof ActionMethodFilter) {
185       return ((ActionMethodFilter)filter).onReached(context, this);
186     }
187     return STOP;
188   }
189
190   protected boolean isSteppedOut() {
191     return mySteppedOut;
192   }
193
194   public int getNextStepDepth(final SuspendContextImpl context) {
195     try {
196       final StackFrameProxyImpl frameProxy = context.getFrameProxy();
197
198       // smart step feature stop check
199       if (myMethodFilter != null &&
200           frameProxy != null &&
201           !(myMethodFilter instanceof BreakpointStepMethodFilter) &&
202           myMethodFilter.locationMatches(context.getDebugProcess(), frameProxy.location()) &&
203           !isTheSameFrame(context)
204         ) {
205         myTargetMethodMatched = true;
206         return reached(myMethodFilter, context);
207       }
208
209       if ((myDepth == StepRequest.STEP_OVER || myDepth == StepRequest.STEP_INTO) && myPosition != null) {
210         SourcePosition locationPosition = ContextUtil.getSourcePosition(context);
211         if (locationPosition != null) {
212           Integer resultDepth = ApplicationManager.getApplication().runReadAction(new Computable<Integer>() {
213             public Integer compute() {
214               if (myPosition.getFile().equals(locationPosition.getFile()) && isTheSameFrame(context) && !mySteppedOut) {
215                 return isOnTheSameLine(locationPosition) ? myDepth : STOP;
216               }
217               return null;
218             }
219           });
220           if (resultDepth != null) {
221             return resultDepth.intValue();
222           }
223         }
224       }
225
226       // Now check filters
227
228       final DebuggerSettings settings = DebuggerSettings.getInstance();
229
230       if ((myMethodFilter != null || (settings.SKIP_SYNTHETIC_METHODS && !myIgnoreFilters))&& frameProxy != null) {
231         final Location location = frameProxy.location();
232         if (location != null) {
233           if (DebuggerUtils.isSynthetic(location.method())) {
234             return myDepth;
235           }
236         }
237       }
238
239       if (!myIgnoreFilters) {
240         if(settings.SKIP_GETTERS) {
241           boolean isGetter = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>(){
242             public Boolean compute() {
243               PsiElement contextElement = ContextUtil.getContextElement(context);
244               return contextElement != null && DebuggerUtils.isInsideSimpleGetter(contextElement);
245             }
246           }).booleanValue();
247
248           if(isGetter) {
249             return StepRequest.STEP_OUT;
250           }
251         }
252
253         if (frameProxy != null) {
254           if (settings.SKIP_CONSTRUCTORS) {
255             final Location location = frameProxy.location();
256             if (location != null) {
257               final Method method = location.method();
258               if (method != null && method.isConstructor()) {
259                 return StepRequest.STEP_OUT;
260               }
261             }
262           }
263
264           if (settings.SKIP_CLASSLOADERS) {
265             final Location location = frameProxy.location();
266             if (location != null && DebuggerUtilsEx.isAssignableFrom("java.lang.ClassLoader", location.declaringType())) {
267               return StepRequest.STEP_OUT;
268             }
269           }
270         }
271
272         for (ExtraSteppingFilter filter : ExtraSteppingFilter.EP_NAME.getExtensions()) {
273           try {
274             if (filter.isApplicable(context)) return filter.getStepRequestDepth(context);
275           }
276           catch (Exception e) {LOG.error(e);}
277           catch (AssertionError e) {LOG.error(e);}
278         }
279       }
280       // smart step feature
281       if (myMethodFilter != null && !mySteppedOut) {
282         return StepRequest.STEP_OUT;
283       }
284     }
285     catch (VMDisconnectedException ignored) {
286     }
287     catch (EvaluateException e) {
288       LOG.error(e);
289     }
290     return STOP;
291   }
292
293 }