Bug 528216 - Exit Breakpoint doesn't show method return value

Change-Id: Ia8f4325e5776cf8e58fa40ae894717b8ef110577
diff --git a/org.eclipse.jdt.debug.tests/testprograms/MethodExitAndException.java b/org.eclipse.jdt.debug.tests/testprograms/MethodExitAndException.java
new file mode 100644
index 0000000..fde01b7
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testprograms/MethodExitAndException.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Till Brychcy and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Till Brychcy - initial API and implementation
+ *******************************************************************************/
+
+class MyException extends Exception {
+
+    public final int value;
+
+    public MyException(int value) {
+        this.value = value;
+    }
+}
+
+public class MethodExitAndException {
+    public static void main(String[] args) {
+        int x = f();
+        try {
+            g(x);
+        } catch (MyException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private static int f() {
+        return 123;
+    }
+
+    private static void g(int i) throws MyException {
+        throw new MyException(i);
+    }
+}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/test/stepping/StepResultTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/test/stepping/StepResultTests.java
index 0b17dd8..08afb03 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/test/stepping/StepResultTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/test/stepping/StepResultTests.java
@@ -14,6 +14,8 @@
 import org.eclipse.debug.core.model.IStackFrame;
 import org.eclipse.debug.core.model.IVariable;
 import org.eclipse.jdt.debug.core.IJavaDebugTarget;
+import org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint;
+import org.eclipse.jdt.debug.core.IJavaMethodBreakpoint;
 import org.eclipse.jdt.debug.core.IJavaObject;
 import org.eclipse.jdt.debug.core.IJavaStackFrame;
 import org.eclipse.jdt.debug.core.IJavaThread;
@@ -503,4 +505,34 @@
 			removeAllBreakpoints();
 		}
 	}
+
+	public void testMethodResultOnMethodExitAndExceptionBreakpoints() throws Exception {
+		IPreferenceStore preferenceStore = JDIDebugUIPlugin.getDefault().getPreferenceStore();
+		boolean origPrefValue = preferenceStore.getBoolean(IJDIPreferencesConstants.PREF_SUSPEND_ON_UNCAUGHT_EXCEPTIONS);
+		preferenceStore.setValue(IJDIPreferencesConstants.PREF_SUSPEND_ON_UNCAUGHT_EXCEPTIONS, true);
+		String typeName = "MethodExitAndException";
+		IJavaMethodBreakpoint methodExitBreakpoint = createMethodBreakpoint("MethodExitAndException", "f", null, false, true);
+		IJavaExceptionBreakpoint exceptionBreakpoint = createExceptionBreakpoint("MyException", true, true);
+		methodExitBreakpoint.setEnabled(true);
+		exceptionBreakpoint.setEnabled(true);
+		IJavaThread thread = null;
+		try {
+			thread = launchAndSuspend(typeName);
+			IJavaStackFrame stackFrame = (IJavaStackFrame) thread.getTopStackFrame();
+			assertEquals("f", stackFrame.getMethodName());
+			assertEquals("f() is returning", stackFrame.getVariables()[0].getName());
+
+			resume(thread);
+
+			stackFrame = (IJavaStackFrame) thread.getTopStackFrame();
+			assertEquals("g", stackFrame.getMethodName());
+			assertEquals("g() is throwing", stackFrame.getVariables()[0].getName());
+		}
+		finally {
+			preferenceStore.setValue(IJDIPreferencesConstants.PREF_SUSPEND_ON_UNCAUGHT_EXCEPTIONS, origPrefValue);
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
 }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
index 58fcad9..8ebc2ee 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
@@ -197,7 +197,7 @@
 			"bug329294", "bug401270", "org.eclipse.debug.tests.targets.HcrClass2", "org.eclipse.debug.tests.targets.HcrClass3", "org.eclipse.debug.tests.targets.HcrClass4",
 			"org.eclipse.debug.tests.targets.HcrClass5", "org.eclipse.debug.tests.targets.HcrClass6", "org.eclipse.debug.tests.targets.HcrClass7", "org.eclipse.debug.tests.targets.HcrClass8",
 			"org.eclipse.debug.tests.targets.HcrClass9", "TestContributedStepFilterClass", "TerminateAll_01", "TerminateAll_02", "StepResult1",
-			"StepResult2", "StepResult3", "StepUncaught", "TriggerPoint_01", "BulkThreadCreationTest" };
+			"StepResult2", "StepResult3", "StepUncaught", "TriggerPoint_01", "BulkThreadCreationTest", "MethodExitAndException" };
 
 	/**
 	 * the default timeout
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaExceptionBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaExceptionBreakpoint.java
index b82a9e4..b355a70 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaExceptionBreakpoint.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaExceptionBreakpoint.java
@@ -32,6 +32,8 @@
 import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
 import org.eclipse.jdt.internal.debug.core.model.JDIThread;
 import org.eclipse.jdt.internal.debug.core.model.JDIValue;
+import org.eclipse.jdt.internal.debug.core.model.MethodResult;
+import org.eclipse.jdt.internal.debug.core.model.MethodResult.ResultType;
 
 import com.sun.jdi.ClassType;
 import com.sun.jdi.Location;
@@ -343,6 +345,18 @@
 	@Override
 	public boolean handleBreakpointEvent(Event event, JDIThread thread,
 			boolean suspendVote) {
+		boolean result = handleBreakpointEventInternal(event, thread, suspendVote);
+		if (!result) {
+			if (event instanceof ExceptionEvent) {
+				// about to suspend, store result
+				ExceptionEvent exceptionEvent = (ExceptionEvent) event;
+				thread.setMethodResult(new MethodResult(exceptionEvent.location().method(), -1, exceptionEvent.exception(), ResultType.throwing));
+			}
+		}
+		return result;
+	}
+
+	private boolean handleBreakpointEventInternal(Event event, JDIThread thread, boolean suspendVote) {
 		if (event instanceof ExceptionEvent) {
 			ObjectReference ex = ((ExceptionEvent) event).exception();
 			fLastTarget = thread.getJavaDebugTarget();
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java
index 7c25d2e..ba3ea73 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -28,6 +28,8 @@
 import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
 import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
 import org.eclipse.jdt.internal.debug.core.model.JDIThread;
+import org.eclipse.jdt.internal.debug.core.model.MethodResult;
+import org.eclipse.jdt.internal.debug.core.model.MethodResult.ResultType;
 
 import com.sun.jdi.ClassType;
 import com.sun.jdi.Location;
@@ -438,8 +440,13 @@
 			MethodExitEvent exitEvent = (MethodExitEvent) event;
 			fLastEventTypes.put(thread.getDebugTarget(), EXIT_EVENT);
 			//inActivateTriggerPoint(event);
-			return handleMethodEvent(exitEvent, exitEvent.method(), thread,
+			boolean result = handleMethodEvent(exitEvent, exitEvent.method(), thread,
 					suspendVote);
+			if (!result) {
+				// about to suspend, store result
+				thread.setMethodResult(new MethodResult(exitEvent.method(), -1, exitEvent.returnValue(), ResultType.returning));
+			}
+			return result;
 		} else if (event instanceof BreakpointEvent) {
 			fLastEventTypes.put(thread.getDebugTarget(), ENTRY_EVENT);
 			return super.handleBreakpointEvent(event, thread, suspendVote);
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.java
index 67040ba..7f1c9c7 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -124,7 +124,9 @@
 	public static String JDIStackFrame_pop_frame_not_supported;
 	public static String JDIStackFrame_Variable_information_unavailable_for_native_methods;
 	public static String JDIStackFrame_ReturnValue;
+	public static String JDIStackFrame_ReturningValue;
 	public static String JDIStackFrame_ExceptionThrown;
+	public static String JDIStackFrame_ThrowingException;
 	public static String JDIStackFrame_NoMethodReturnValue;
 
 	public static String JDIThisVariable_exception_while_retrieving_type_this;
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.properties b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.properties
index 3b8f5f6..fcf0b5d 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.properties
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2016 IBM Corporation and others.
+# Copyright (c) 2000, 2017 IBM Corporation and others.
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License v1.0
 # which accompanies this distribution, and is available at
@@ -92,7 +92,9 @@
 JDIStackFrame_pop_frame_not_supported=Popping frames not supported.
 JDIStackFrame_Variable_information_unavailable_for_native_methods=Variable information unavailable for native methods
 JDIStackFrame_ReturnValue={0}() returned
+JDIStackFrame_ReturningValue={0}() is returning
 JDIStackFrame_ExceptionThrown={0}() threw
+JDIStackFrame_ThrowingException={0}() is throwing
 JDIStackFrame_NoMethodReturnValue=no method return value
 
 JDIThisVariable_exception_while_retrieving_type_this={0} occurred while retrieving type ''this''.
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java
index 73235e0..01e8e16 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -20,7 +20,6 @@
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
-
 import org.eclipse.debug.core.DebugEvent;
 import org.eclipse.debug.core.DebugException;
 import org.eclipse.debug.core.model.IRegisterGroup;
@@ -30,12 +29,9 @@
 import org.eclipse.debug.core.model.ITerminate;
 import org.eclipse.debug.core.model.IThread;
 import org.eclipse.debug.core.model.IVariable;
-
 import org.eclipse.jdi.internal.ValueImpl;
 import org.eclipse.jdi.internal.VirtualMachineImpl;
-
 import org.eclipse.jdt.core.Signature;
-
 import org.eclipse.jdt.debug.core.IJavaClassType;
 import org.eclipse.jdt.debug.core.IJavaModifiers;
 import org.eclipse.jdt.debug.core.IJavaObject;
@@ -44,9 +40,9 @@
 import org.eclipse.jdt.debug.core.IJavaThread;
 import org.eclipse.jdt.debug.core.IJavaValue;
 import org.eclipse.jdt.debug.core.IJavaVariable;
-
 import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
 import org.eclipse.jdt.internal.debug.core.logicalstructures.JDIReturnValueVariable;
+import org.eclipse.jdt.internal.debug.core.model.MethodResult.ResultType;
 
 import com.ibm.icu.text.MessageFormat;
 import com.sun.jdi.AbsentInformationException;
@@ -384,22 +380,28 @@
 	 */
 	private void addStepReturnValue(List<IJavaVariable> variables) {
 		if (fIsTop) {
-			StepResult stepResult = fThread.fStepResult;
-			if (stepResult != null) {
-				if (stepResult.fIsReturnValue) {
-					if (fDepth + 1 != stepResult.fTargetFrameCount) {
+			MethodResult methodResult = fThread.getMethodResult();
+			if (methodResult != null) {
+				if (methodResult.fResultType == ResultType.returned) {
+					if (fDepth + 1 != methodResult.fTargetFrameCount) {
 						// can happen e.g., because of checkPackageAccess/System.getSecurityManager()
 						return;
 					}
-					String name = MessageFormat.format(JDIDebugModelMessages.JDIStackFrame_ReturnValue, stepResult.fMethod.name());
-					variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), stepResult.fValue), true));
-				} else {
-					if (fDepth + 1 > stepResult.fTargetFrameCount) {
+					String name = MessageFormat.format(JDIDebugModelMessages.JDIStackFrame_ReturnValue, methodResult.fMethod.name());
+					variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), methodResult.fValue), true));
+				} else if (methodResult.fResultType == ResultType.returning) {
+					String name = MessageFormat.format(JDIDebugModelMessages.JDIStackFrame_ReturningValue, methodResult.fMethod.name());
+					variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), methodResult.fValue), true));
+				} else if (methodResult.fResultType == ResultType.threw) {
+					if (fDepth + 1 > methodResult.fTargetFrameCount) {
 						// don't know if this really can happen, but other jvm suprises were not expected either
 						return;
 					}
-					String name = MessageFormat.format(JDIDebugModelMessages.JDIStackFrame_ExceptionThrown, stepResult.fMethod.name());
-					variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), stepResult.fValue), true));
+					String name = MessageFormat.format(JDIDebugModelMessages.JDIStackFrame_ExceptionThrown, methodResult.fMethod.name());
+					variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), methodResult.fValue), true));
+				} else if (methodResult.fResultType == ResultType.throwing) {
+					String name = MessageFormat.format(JDIDebugModelMessages.JDIStackFrame_ThrowingException, methodResult.fMethod.name());
+					variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), methodResult.fValue), true));
 				}
 			} else if(JDIThread.showStepResultIsEnabled()) {
 				variables.add(0, new JDIReturnValueVariable(JDIDebugModelMessages.JDIStackFrame_NoMethodReturnValue, new JDIPlaceholderValue(getJavaDebugTarget(), ""), false)); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
index f2572fd..3f8b497 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
@@ -55,6 +55,7 @@
 import org.eclipse.jdt.internal.debug.core.breakpoints.ConditionalBreakpointHandler;
 import org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint;
 import org.eclipse.jdt.internal.debug.core.breakpoints.JavaLineBreakpoint;
+import org.eclipse.jdt.internal.debug.core.model.MethodResult.ResultType;
 
 import com.ibm.icu.text.MessageFormat;
 import com.sun.jdi.BooleanValue;
@@ -290,9 +291,12 @@
 	 */
 	private int fStepReturnTargetFrameCount;
 
-	private StepResult fStepResultCandidate;
+	private MethodResult fStepResultCandidate;
 
-	StepResult fStepResult;
+	/**
+	 * Result of the last step step-over or step-return operation or method exit breakpoint of exception break point
+	 */
+	private MethodResult fMethodResult;
 
 	/**
 	 * Creates a new thread on the underlying thread reference in the given
@@ -1697,7 +1701,7 @@
 		}
 		try {
 			setRunning(true);
-			clearStepReturnResult();
+			clearMethodResult();
 			if (fireNotification) {
 				fireResumeEvent(DebugEvent.CLIENT_REQUEST);
 			}
@@ -1728,8 +1732,8 @@
 		}
 	}
 
-	private void clearStepReturnResult() {
-		fStepResult = null;
+	private void clearMethodResult() {
+		setMethodResult(null);
 	}
 
 	/**
@@ -2069,7 +2073,7 @@
 	protected synchronized void resumedByVM() throws DebugException {
 		fClientSuspendRequest = false;
 		setRunning(true);
-		clearStepReturnResult();
+		clearMethodResult();
 		preserveStackFrames();
 		// This method is called *before* the VM is actually resumed.
 		// To ensure that all threads will fully resume when the VM
@@ -2444,7 +2448,7 @@
 				setPendingStepHandler(this);
 				addJDIEventListener(this, getStepRequest());
 				setRunning(true);
-				clearStepReturnResult();
+				clearMethodResult();
 				preserveStackFrames();
 				fireResumeEvent(getStepDetail());
 				invokeThread();
@@ -2768,14 +2772,14 @@
 					if (stepResultMethod != null) {
 						MethodExitEvent methodExitEvent = (MethodExitEvent) event;
 						if (methodExitEvent.location().method().equals(stepResultMethod)) {
-							fStepResultCandidate = new StepResult(fStepResultMethod, fStepReturnTargetFrameCount, methodExitEvent.returnValue(), true);
+							fStepResultCandidate = new MethodResult(fStepResultMethod, fStepReturnTargetFrameCount, methodExitEvent.returnValue(), ResultType.returned);
 						}
 						return true;
 					}
 				}
 				if (event instanceof ExceptionEvent) {
 					ExceptionEvent exceptionEvent = (ExceptionEvent) event;
-					fStepResultCandidate = new StepResult(fStepResultMethod, fStepReturnTargetFrameCount, exceptionEvent.exception(), false);
+					fStepResultCandidate = new MethodResult(fStepResultMethod, fStepReturnTargetFrameCount, exceptionEvent.exception(), ResultType.threw);
 					return true;
 				}
 				if (event instanceof MethodEntryEvent) {
@@ -2793,7 +2797,7 @@
 				Location currentLocation = stepEvent.location();
 
 				if (fStepResultCandidate != null) {
-					fStepResult = fStepResultCandidate;
+					setMethodResult(fStepResultCandidate);
 					fStepResultMethod = null;
 					fStepReturnTargetFrameCount = -1;
 					fStepResultCandidate = null;
@@ -2840,7 +2844,7 @@
 					setRunning(true);
 					deleteStepRequest();
 					createSecondaryStepRequest();
-					clearStepReturnResult();
+					clearMethodResult();
 					return true;
 					// otherwise, we're done stepping
 				}
@@ -3183,7 +3187,7 @@
 				setRunning(true);
 				deleteStepRequest();
 				createSecondaryStepRequest();
-				clearStepReturnResult();
+				clearMethodResult();
 				return true;
 			} catch (DebugException e) {
 				logError(e);
@@ -3739,4 +3743,12 @@
 		return JAVA_STRATUM_CONSTANT.equals(currentLocation.declaringType().defaultStratum());
 	}
 
+	public MethodResult getMethodResult() {
+		return fMethodResult;
+	}
+
+	public void setMethodResult(MethodResult fMethodResult) {
+		this.fMethodResult = fMethodResult;
+	}
+
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/MethodResult.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/MethodResult.java
new file mode 100644
index 0000000..0312188
--- /dev/null
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/MethodResult.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2016, 2017 Till Brychcy and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Till Brychcy - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.debug.core.model;
+
+import com.sun.jdi.Method;
+import com.sun.jdi.Value;
+
+public class MethodResult {
+	public enum ResultType {
+		/** fValue is returned value after a step operation */
+		returned,
+
+		/** fValue is exception thrown after a step operation */
+		threw,
+
+		/** fValue is value being returned at a method exit breakpoint */
+		returning,
+
+		/** fValue is exception being thrown in a exception breakpoint */
+		throwing
+	}
+
+	public MethodResult(Method method, int targetFrameCount, Value value, ResultType resultType) {
+		this.fMethod = method;
+		this.fTargetFrameCount = targetFrameCount;
+		this.fValue = value;
+		this.fResultType = resultType;
+	}
+
+	/**
+	 * The method from which {@link #fValue} originates
+	 */
+	public final Method fMethod;
+
+	/**
+	 * If a step-return or step-over is in progress, this is the stack size at which the result value is expected. Otherwise ignored.
+	 */
+	public final int fTargetFrameCount;
+
+	/**
+	 * Return value or exception
+	 */
+	public final Value fValue;
+
+	/**
+	 * Whether {@link #fValue} was returned or thrown
+	 */
+	public final ResultType fResultType;
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/StepResult.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/StepResult.java
deleted file mode 100644
index 54a7c17..0000000
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/StepResult.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Till Brychcy and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *     Till Brychcy - initial API and implementation
- *******************************************************************************/
-
-package org.eclipse.jdt.internal.debug.core.model;
-
-import com.sun.jdi.Method;
-import com.sun.jdi.Value;
-
-public class StepResult {
-
-	public StepResult(Method method, int targetFrameCount, Value value, boolean isReturnValue) {
-		this.fMethod = method;
-		this.fTargetFrameCount = targetFrameCount;
-		this.fValue = value;
-		this.fIsReturnValue = isReturnValue;
-	}
-
-	/**
-	 * The method that was being stepped-over or step-returned from.
-	 */
-	public final Method fMethod;
-
-	/**
-	 * If a step-return or step-over is in progress, this is the stack size at which the result value is expected.
-	 */
-	public final int fTargetFrameCount;
-
-	/**
-	 * Returned value or thrown exception after a step-return or step-over.
-	 */
-	public final Value fValue;
-
-	/**
-	 * Whether {@link #fValue} was returned or thrown
-	 */
-	public final boolean fIsReturnValue;
-}
\ No newline at end of file