diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java index 254ed0799282..2d7c47544e75 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java @@ -36,8 +36,11 @@ import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.wm.ToolWindowId; +import com.intellij.openapi.wm.ToolWindowManager; import com.sun.jdi.InternalException; import com.sun.jdi.ThreadReference; import com.sun.jdi.VMDisconnectedException; @@ -388,6 +391,12 @@ public class DebugProcessEvents extends DebugProcessImpl { myReturnValueWatcher.disable(); } getSuspendManager().voteSuspend(suspendContext); + if (hint != null) { + final RequestHint.SmartStepFilter smartStepFilter = hint.getSmartStepFilter(); + if (smartStepFilter != null && !smartStepFilter.wasMethodExecuted()) { + ToolWindowManager.getInstance(getProject()).notifyByBalloon(ToolWindowId.DEBUG, MessageType.INFO, "Method " + smartStepFilter.getTargetMethodName() + "() has not been called"); + } + } } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/RequestHint.java b/java/debugger/impl/src/com/intellij/debugger/engine/RequestHint.java index e4f3ae8e97f4..aae460a44774 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/RequestHint.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/RequestHint.java @@ -58,13 +58,22 @@ public class RequestHint { private final JVMName myDeclaringClassName; private final @NonNls String myTargetMethodName; private final JVMName myTargetMethodSignature; + private boolean myMethodExecuted; public SmartStepFilter(PsiMethod psiMethod) { myDeclaringClassName = JVMNameUtil.getJVMQualifiedName(psiMethod.getContainingClass()); myTargetMethodName = psiMethod.isConstructor()? "" : psiMethod.getName(); myTargetMethodSignature = JVMNameUtil.getJVMSignature(psiMethod); } - + + public String getTargetMethodName() { + return myTargetMethodName; + } + + public boolean wasMethodExecuted() { + return myMethodExecuted; + } + public boolean shouldStopAtLocation(final SuspendContextImpl context) { try { final StackFrameProxyImpl frameProxy = context.getFrameProxy(); @@ -80,6 +89,7 @@ public class RequestHint { if (!signatureMatches(method, myTargetMethodSignature.getName(process))) { return false; } + myMethodExecuted = true; final ObjectReference thisObject = frameProxy.thisObject(); final ReferenceType locationClass = thisObject != null? thisObject.referenceType() : method.declaringType(); return DebuggerUtilsEx.isAssignableFrom(myDeclaringClassName.getName(process), locationClass); @@ -168,6 +178,11 @@ public class RequestHint { return mySkipThisMethod ? StepRequest.STEP_OUT : myDepth; } + @Nullable + public SmartStepFilter getSmartStepFilter() { + return myTargetMethodSignature; + } + public int getNextStepDepth(final SuspendContextImpl context) { try { if ((myDepth == StepRequest.STEP_OVER || myDepth == StepRequest.STEP_INTO) && myPosition != null) {