2 * Copyright 2000-2009 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
.jdi
.VirtualMachineProxyImpl
;
32 import com
.intellij
.debugger
.settings
.DebuggerSettings
;
33 import com
.intellij
.openapi
.application
.ApplicationManager
;
34 import com
.intellij
.openapi
.diagnostic
.Logger
;
35 import com
.intellij
.openapi
.util
.Computable
;
36 import com
.intellij
.psi
.PsiMethod
;
37 import com
.intellij
.psi
.util
.PsiTreeUtil
;
39 import com
.sun
.jdi
.request
.StepRequest
;
40 import org
.jetbrains
.annotations
.NonNls
;
41 import org
.jetbrains
.annotations
.NotNull
;
42 import org
.jetbrains
.annotations
.Nullable
;
44 public class RequestHint
{
45 public static final int STOP
= 0;
46 private static final Logger LOG
= Logger
.getInstance("#com.intellij.debugger.engine.RequestHint");
47 private final int myDepth
;
48 private SourcePosition myPosition
;
49 private int myFrameCount
;
50 private VirtualMachineProxyImpl myVirtualMachineProxy
;
52 private final @Nullable SmartStepFilter myTargetMethodSignature
;
53 private boolean myIgnoreFilters
= false;
54 private boolean myRestoreBreakpoints
= false;
55 private final boolean mySkipThisMethod
= false;
57 public static final class SmartStepFilter
{
58 private final JVMName myDeclaringClassName
;
59 private final @NonNls String myTargetMethodName
;
60 private final JVMName myTargetMethodSignature
;
62 public SmartStepFilter(PsiMethod psiMethod
) {
63 myDeclaringClassName
= JVMNameUtil
.getJVMQualifiedName(psiMethod
.getContainingClass());
64 myTargetMethodName
= psiMethod
.isConstructor()?
"<init>" : psiMethod
.getName();
65 myTargetMethodSignature
= JVMNameUtil
.getJVMSignature(psiMethod
);
68 public boolean shouldStopAtLocation(final SuspendContextImpl context
) {
70 final StackFrameProxyImpl frameProxy
= context
.getFrameProxy();
71 if (frameProxy
== null) {
74 final Location location
= frameProxy
.location();
75 final Method method
= location
.method();
76 if (!myTargetMethodName
.equals(method
.name())) {
79 final DebugProcessImpl process
= context
.getDebugProcess();
80 if (!signatureMatches(method
, myTargetMethodSignature
.getName(process
))) {
83 final ObjectReference thisObject
= frameProxy
.thisObject();
84 final ReferenceType locationClass
= thisObject
!= null? thisObject
.referenceType() : method
.declaringType();
85 return DebuggerUtilsEx
.isAssignableFrom(myDeclaringClassName
.getName(process
), locationClass
);
87 catch (EvaluateException e
) {
93 private static boolean signatureMatches(Method method
, final String expectedSignature
) throws EvaluateException
{
94 if (expectedSignature
.equals(method
.signature())) {
97 // check if there are any bridge methods that match
98 for (Method candidate
: method
.declaringType().methodsByName(method
.name())) {
99 if (candidate
!= method
&& candidate
.isBridge() && expectedSignature
.equals(candidate
.signature())) {
107 public RequestHint(final ThreadReferenceProxyImpl stepThread
, final SuspendContextImpl suspendContext
, @NotNull SmartStepFilter smartStepFilter
) {
108 this(stepThread
, suspendContext
, StepRequest
.STEP_INTO
, smartStepFilter
);
111 public RequestHint(final ThreadReferenceProxyImpl stepThread
, final SuspendContextImpl suspendContext
, int depth
) {
112 this(stepThread
, suspendContext
, depth
, null);
115 private RequestHint(final ThreadReferenceProxyImpl stepThread
, final SuspendContextImpl suspendContext
, int depth
, SmartStepFilter smartStepFilter
) {
116 final DebugProcessImpl debugProcess
= suspendContext
.getDebugProcess();
118 myTargetMethodSignature
= smartStepFilter
;
119 myVirtualMachineProxy
= debugProcess
.getVirtualMachineProxy();
122 myFrameCount
= stepThread
.frameCount();
124 ApplicationManager
.getApplication().runReadAction(new Runnable() {
126 myPosition
= ContextUtil
.getSourcePosition(new StackFrameContext() {
127 public StackFrameProxy
getFrameProxy() {
129 return stepThread
.frame(0);
131 catch (EvaluateException e
) {
132 if (LOG
.isDebugEnabled()) {
139 public DebugProcess
getDebugProcess() {
140 return suspendContext
.getDebugProcess();
146 catch (Exception e
) {
151 public void setIgnoreFilters(boolean ignoreFilters
) {
152 myIgnoreFilters
= ignoreFilters
;
155 public void setRestoreBreakpoints(boolean restoreBreakpoints
) {
156 myRestoreBreakpoints
= restoreBreakpoints
;
159 public boolean isRestoreBreakpoints() {
160 return myRestoreBreakpoints
;
163 public boolean isIgnoreFilters() {
164 return myIgnoreFilters
;
167 public int getDepth() {
168 return mySkipThisMethod ? StepRequest
.STEP_OUT
: myDepth
;
171 public int getNextStepDepth(final SuspendContextImpl context
) {
173 if ((myDepth
== StepRequest
.STEP_OVER
|| myDepth
== StepRequest
.STEP_INTO
) && myPosition
!= null) {
174 final Integer resultDepth
= ApplicationManager
.getApplication().runReadAction(new Computable
<Integer
>() {
175 public Integer
compute() {
176 final SourcePosition locationPosition
= ContextUtil
.getSourcePosition(context
);
177 if (locationPosition
== null) {
181 final ThreadReferenceProxyImpl contextThread
= context
.getThread();
182 if (contextThread
!= null) {
184 frameCount
= contextThread
.frameCount();
186 catch (EvaluateException e
) {
189 final boolean filesEqual
= myPosition
.getFile().equals(locationPosition
.getFile());
190 if (filesEqual
&& myPosition
.getLine() == locationPosition
.getLine() && myFrameCount
== frameCount
) {
193 if (myDepth
== StepRequest
.STEP_INTO
) {
194 // check if we are still at the line from which the stepping begun
195 if (filesEqual
&& myFrameCount
== frameCount
&& myPosition
.getLine() != locationPosition
.getLine()) {
202 if (resultDepth
!= null) {
203 return resultDepth
.intValue();
206 // the rest of the code makes sence for depth == STEP_INTO only
208 if (myDepth
== StepRequest
.STEP_INTO
) {
209 final DebuggerSettings settings
= DebuggerSettings
.getInstance();
210 if (settings
.SKIP_SYNTHETIC_METHODS
) {
211 final StackFrameProxyImpl frameProxy
= context
.getFrameProxy();
212 Location location
= frameProxy
.location();
213 Method method
= location
.method();
214 if (method
!= null) {
215 if (myVirtualMachineProxy
.canGetSyntheticAttribute()? method
.isSynthetic() : method
.name().indexOf('$') >= 0) {
220 if (!myIgnoreFilters
) {
221 if(settings
.SKIP_GETTERS
) {
222 boolean isGetter
= ApplicationManager
.getApplication().runReadAction(new Computable
<Boolean
>(){
223 public Boolean
compute() {
224 final PsiMethod psiMethod
= PsiTreeUtil
.getParentOfType(PositionUtil
.getContextElement(context
), PsiMethod
.class);
225 return (psiMethod
!= null && DebuggerUtils
.isSimpleGetter(psiMethod
))? Boolean
.TRUE
: Boolean
.FALSE
;
230 return StepRequest
.STEP_OUT
;
234 if (settings
.SKIP_CONSTRUCTORS
) {
235 Location location
= context
.getFrameProxy().location();
236 Method method
= location
.method();
237 if (method
!= null && method
.isConstructor()) {
238 return StepRequest
.STEP_OUT
;
242 if (settings
.SKIP_CLASSLOADERS
) {
243 Location location
= context
.getFrameProxy().location();
244 if (DebuggerUtilsEx
.isAssignableFrom("java.lang.ClassLoader", location
.declaringType())) {
245 return StepRequest
.STEP_OUT
;
249 // smart step feature
250 if (myTargetMethodSignature
!= null) {
251 if (!myTargetMethodSignature
.shouldStopAtLocation(context
)) {
252 return StepRequest
.STEP_OUT
;
257 catch (VMDisconnectedException e
) {
259 catch (EvaluateException e
) {