Bug 543385 - [lambda] no breakpoint hits for single line lambda calls

In case we have no condition, we can allow to stop at every location.

Change-Id: I7ac1f6629109dcea5a7eff20247a11bfd501a5f7
Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
index 1828248..652f592 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
@@ -32,6 +32,7 @@
 import org.eclipse.jdt.debug.tests.breakpoints.ImportBreakpointsTest;
 import org.eclipse.jdt.debug.tests.breakpoints.JavaBreakpointListenerTests;
 import org.eclipse.jdt.debug.tests.breakpoints.JavaThreadEventHandlerTests;
+import org.eclipse.jdt.debug.tests.breakpoints.LambdaBreakpointsInJava8Tests;
 import org.eclipse.jdt.debug.tests.breakpoints.MethodBreakpointTests;
 import org.eclipse.jdt.debug.tests.breakpoints.MethodBreakpointTests15;
 import org.eclipse.jdt.debug.tests.breakpoints.MiscBreakpointsTests;
@@ -351,6 +352,7 @@
 			addTest(new TestSuite(TestToggleBreakpointsTarget8.class));
 			addTest(new TestSuite(ModelPresentationTests18.class));
 			addTest(new TestSuite(ConditionalBreakpointsInJava8Tests.class));
+			addTest(new TestSuite(LambdaBreakpointsInJava8Tests.class));
 		}
 		if (JavaProjectHelper.isJava5Compatible()) {
 			addTest(new TestSuite(MethodBreakpointTests15.class));
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/LambdaBreakpointsInJava8Tests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/LambdaBreakpointsInJava8Tests.java
new file mode 100644
index 0000000..29e4572
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/LambdaBreakpointsInJava8Tests.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Andrey Loskutov and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Andrey Loskutov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.debug.tests.breakpoints;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.debug.core.IJavaDebugTarget;
+import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
+import org.eclipse.jdt.debug.core.IJavaThread;
+import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+import org.eclipse.jdt.debug.tests.TestUtil;
+
+/**
+ * Tests lambda breakpoints.
+ */
+public class LambdaBreakpointsInJava8Tests extends AbstractDebugTest {
+
+	public LambdaBreakpointsInJava8Tests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected IJavaProject getProjectContext() {
+		return get18Project();
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		assertNoErrorMarkersExist();
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		terminateAndRemoveJavaLaunches();
+		removeAllBreakpoints();
+		super.tearDown();
+	}
+
+	/**
+	 * Test for bug 543385 - we should stop multiple times on same line with many lambdas
+	 */
+	public void testBug541110_unconditional() throws Exception {
+		String typeName = "Bug541110";
+		int breakpointLineNumber = 22;
+
+		IJavaLineBreakpoint bp = createLineBreakpoint(breakpointLineNumber, typeName);
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToLineBreakpoint(typeName, bp);
+			thread.resume();
+			// now we should stop again in the lambda
+			TestUtil.waitForJobs(getName(), 1000, DEFAULT_TIMEOUT, ProcessConsole.class);
+			assertTrue("Thread should be suspended", thread.isSuspended());
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	/**
+	 * Test for bug 543385/541110 - we should stop only once if there is a condition.
+	 *
+	 * Note: if we implement proper lambda debugging support some time later, this test will probably fail.
+	 */
+	public void testBug541110_conditional() throws Exception {
+		String typeName = "Bug541110";
+		String breakpointCondition = "true";
+		int breakpointLineNumber = 22;
+
+		IJavaLineBreakpoint bp = createConditionalLineBreakpoint(breakpointLineNumber, typeName, breakpointCondition, true);
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToLineBreakpoint(typeName, bp);
+			thread.resume();
+			// now we should NOT stop again in the lambda (a more complex condition would most likely fail)
+			TestUtil.waitForJobs(getName(), 1000, DEFAULT_TIMEOUT, ProcessConsole.class);
+			assertTrue("Thread should be suspended", thread.isTerminated());
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	private void terminateAndRemoveJavaLaunches() {
+		ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
+		List<ILaunch> launches = Arrays.asList(launchManager.getLaunches());
+		for (ILaunch launch : launches) {
+			IDebugTarget debugTarget = launch.getDebugTarget();
+			if (debugTarget instanceof IJavaDebugTarget) {
+				terminateAndRemove((IJavaDebugTarget) debugTarget);
+			}
+		}
+	}
+
+}
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaLineBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaLineBreakpoint.java
index 71ab3ca..c7d8318 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaLineBreakpoint.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaLineBreakpoint.java
@@ -324,6 +324,14 @@
 		if (locations.size() <= 1) {
 			return locations;
 		}
+
+		// JVM has multiple breakpoint locations for this line.
+		// Bug 543385: in case we have no condition, we can allow to stop at every location.
+		// Bug 541110: In case we have condition, it will most likely fail due the wrong context
+		// if evaluated in a lambda where the condition arguments couldn't be resolved.
+		if (!hasCondition()) {
+			return locations;
+		}
 		List<Location> result = new ArrayList<>();
 		for (Location location : locations) {
 			Method method = location.method();