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) {