Bug 573589 - Add support for lambda evaluation with static imports

When performing lambda expression evaluation where the source file
contains static imports, the static imports are added as normal imports
into the code snippet. This happens both for source types and binary
types with source attached.

Change-Id: I5d58caa3fcf0d8d040166ae080d52647dd50a5aa
Signed-off-by: Gayan Perera <gayanper@gmail.com>
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.debug/+/180746
Tested-by: JDT Bot <jdt-bot@eclipse.org>
Reviewed-by: Sarika Sinha <sarika.sinha@in.ibm.com>
diff --git a/org.eclipse.jdt.debug.tests/java8/Bug573589.java b/org.eclipse.jdt.debug.tests/java8/Bug573589.java
new file mode 100644
index 0000000..0a8e9df
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/java8/Bug573589.java
@@ -0,0 +1,11 @@
+import static java.lang.Math.max;
+
+import java.util.stream.Stream;
+
+public class Bug573589 {
+
+	public static void main(String[] args) {
+		max(10, 11);
+		Stream.of(1,2,3).filter(i -> i > 2).map(i -> i * 2).count();
+	}
+}
diff --git a/org.eclipse.jdt.debug.tests/testresources/bug573589/classes/Bug573589Bin.class b/org.eclipse.jdt.debug.tests/testresources/bug573589/classes/Bug573589Bin.class
new file mode 100644
index 0000000..a11ac57
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testresources/bug573589/classes/Bug573589Bin.class
Binary files differ
diff --git a/org.eclipse.jdt.debug.tests/testresources/bug573589/src/Bug573589Bin.java b/org.eclipse.jdt.debug.tests/testresources/bug573589/src/Bug573589Bin.java
new file mode 100644
index 0000000..ab1b00f
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testresources/bug573589/src/Bug573589Bin.java
@@ -0,0 +1,11 @@
+import static java.lang.Math.max;
+
+import java.util.stream.Stream;
+
+public class Bug573589Bin {
+
+	public static void main(String[] args) {
+		max(10, 11);
+		Stream.of(1,2,3).filter(i -> i > 2).map(i -> i * 2).count();
+	}
+}
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 c9411c9..c5560d6 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
@@ -495,6 +495,7 @@
 				cfgs.add(createLaunchConfiguration(jp, "Bug571230"));
 				cfgs.add(createLaunchConfiguration(jp, "Bug572629"));
 				cfgs.add(createLaunchConfiguration(jp, "Bug569413"));
+				cfgs.add(createLaunchConfiguration(jp, "Bug573589"));
 	    		loaded18 = true;
 	    		waitForBuild();
 	        }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaExpressionEvalTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaExpressionEvalTest.java
new file mode 100644
index 0000000..21ab19a
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaExpressionEvalTest.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Gayan Perera 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:
+ *     Gayan Perera - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.debug.tests.eval;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.debug.core.IJavaThread;
+import org.eclipse.jdt.debug.testplugin.JavaProjectHelper;
+import org.eclipse.jdt.debug.testplugin.JavaTestPlugin;
+import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+
+public class LambdaExpressionEvalTest extends AbstractDebugTest {
+	private IJavaThread javaThread;
+
+	public LambdaExpressionEvalTest(String name) {
+		super(name);
+	}
+
+	@Override
+	protected IJavaProject getProjectContext() {
+		return get18Project();
+	}
+
+	public void testBug573589_EvalLambdaExpressionInSourceType_WithStaticImportInImports_ExpectSuccessfulEval() throws Exception {
+		debugWithBreakpoint("Bug573589", 9);
+		IValue value = doEval(javaThread, "Stream.of(1,2,3).filter(i -> i > 2).map(i -> i * 2).count();");
+
+		assertNotNull("value is null", value);
+		assertEquals("value is not 1", "1", value.getValueString());
+	}
+
+	public void testBug573589_EvalLambdaExpressionInBinaryType_WithStaticImportInImports_ExpectSuccessfulEval() throws Exception {
+		IPath container = new Path(JavaTestPlugin.getDefault().getFileInPlugin(new Path("./testresources/bug573589/classes")).getAbsolutePath());
+		JavaProjectHelper.addLibrary(getProjectContext(), container);
+		waitForBuild();
+
+		ILaunchConfiguration launchConfiguration = null;
+		try {
+			launchConfiguration = createLaunchConfiguration(getProjectContext(), "Bug573589Bin");
+			debugWithBreakpoint("Bug573589Bin", 9);
+			IValue value = doEval(javaThread, "java.util.stream.Stream.of(1,2,3).filter(i -> i > 2).map(i -> i * 2).count();");
+			assertNotNull("value is null", value);
+			assertEquals("value is not 1", "1", value.getValueString());
+		} finally {
+			if (launchConfiguration != null) {
+				launchConfiguration.delete();
+			}
+			JavaProjectHelper.removeFromClasspath(getProjectContext(), container);
+		}
+	}
+
+	public void testBug573589_EvalLambdaExpressionInBinaryTypeAttachedSource_WithStaticImportInImports_ExpectSuccessfulEval() throws Exception {
+		IPath container = new Path(JavaTestPlugin.getDefault().getFileInPlugin(new Path("./testresources/bug573589/classes")).getAbsolutePath());
+		IPath src = new Path(JavaTestPlugin.getDefault().getFileInPlugin(new Path("./testresources/bug573589/src")).getAbsolutePath());
+		JavaProjectHelper.addLibrary(getProjectContext(), container, src, container);
+		waitForBuild();
+
+		ILaunchConfiguration launchConfiguration = null;
+		try {
+			launchConfiguration = createLaunchConfiguration(getProjectContext(), "Bug573589Bin");
+			debugWithBreakpoint("Bug573589Bin", 9);
+			IValue value = doEval(javaThread, "Stream.of(1,2,3).filter(i -> i > 2).map(i -> i * 2).count();");
+			assertNotNull("value is null", value);
+			assertEquals("value is not 1", "1", value.getValueString());
+		} finally {
+			if (launchConfiguration != null) {
+				launchConfiguration.delete();
+			}
+			JavaProjectHelper.removeFromClasspath(getProjectContext(), container);
+		}
+	}
+
+	private void debugWithBreakpoint(String testClass, int lineNumber) throws Exception {
+		createLineBreakpoint(lineNumber, testClass);
+		javaThread = launchToBreakpoint(testClass);
+		assertNotNull("The program did not suspend", javaThread);
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		try {
+			terminateAndRemove(javaThread);
+		} finally {
+			super.tearDown();
+			removeAllBreakpoints();
+		}
+	}
+}