Merge remote-tracking branch 'origin/master' into BETA_JAVA15

Change-Id: I4eafcc756e145df6e5b5ea9a526462fcb50d2333
diff --git a/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/Bar.class b/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/Bar.class
new file mode 100644
index 0000000..fb2a878
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/Bar.class
Binary files differ
diff --git a/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/Foo.class b/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/Foo.class
new file mode 100644
index 0000000..7346879
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/Foo.class
Binary files differ
diff --git a/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/SyntheticTest$1$1.class b/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/SyntheticTest$1$1.class
new file mode 100644
index 0000000..f3bc8dc
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/SyntheticTest$1$1.class
Binary files differ
diff --git a/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/SyntheticTest$1.class b/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/SyntheticTest$1.class
new file mode 100644
index 0000000..1bf3317
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/SyntheticTest$1.class
Binary files differ
diff --git a/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/SyntheticTest.class b/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/SyntheticTest.class
new file mode 100644
index 0000000..b4d7b63
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testresources/synthetic/bin/SyntheticTest.class
Binary files differ
diff --git a/org.eclipse.jdt.debug.tests/testresources/synthetic/src/Bar.java b/org.eclipse.jdt.debug.tests/testresources/synthetic/src/Bar.java
new file mode 100644
index 0000000..d1f6355
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testresources/synthetic/src/Bar.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2020 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
+ *******************************************************************************/
+
+public abstract class Bar {
+	public abstract Foo bar(String vbar);
+}
diff --git a/org.eclipse.jdt.debug.tests/testresources/synthetic/src/Foo.java b/org.eclipse.jdt.debug.tests/testresources/synthetic/src/Foo.java
new file mode 100644
index 0000000..d3cff81
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testresources/synthetic/src/Foo.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2020 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
+ *******************************************************************************/
+
+public abstract class Foo {
+	public abstract String foo(String foo);
+}
diff --git a/org.eclipse.jdt.debug.tests/testresources/synthetic/src/SyntheticTest.java b/org.eclipse.jdt.debug.tests/testresources/synthetic/src/SyntheticTest.java
new file mode 100644
index 0000000..fe5e928
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testresources/synthetic/src/SyntheticTest.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2020 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
+ *******************************************************************************/
+import java.util.function.Predicate;
+
+public class SyntheticTest {
+	public static void main(String[] args) {
+		(new SyntheticTest()).exec(s -> s.isEmpty()).bar("bar").foo("foo");
+	}
+
+	public Bar exec(Predicate<String> predicate) {
+		return new Bar() {
+			private Object bar;
+			@Override
+			public Foo bar(String vbar) {
+				return new Foo() {
+					private Object foo;
+					@Override
+					public String foo(String vfoo) {
+						predicate.test("vfoo");
+						return vfoo;
+					}
+				};
+			}
+		};
+	}
+}
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 8b73956..10086fb 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
@@ -91,6 +91,7 @@
 import org.eclipse.jdt.debug.tests.core.WorkspaceSourceContainerTests;
 import org.eclipse.jdt.debug.tests.eval.GeneralEvalTests;
 import org.eclipse.jdt.debug.tests.eval.GenericsEvalTests;
+import org.eclipse.jdt.debug.tests.eval.SyntheticVariableTests;
 import org.eclipse.jdt.debug.tests.launching.ClasspathShortenerTests;
 import org.eclipse.jdt.debug.tests.launching.ConfigurationEncodingTests;
 import org.eclipse.jdt.debug.tests.launching.ConfigurationResourceMappingTests;
@@ -231,9 +232,7 @@
 		addTest(new TestSuite(ClasspathContainerTests.class));
 		addTest(new TestSuite(RuntimeClasspathEntryTests.class));
 		addTest(new TestSuite(ClasspathProviderTests.class));
-		if (!JavaProjectHelper.isJava9Compatible()) {
-			addTest(new TestSuite(BootpathTests.class));
-		}
+		addTest(new TestSuite(BootpathTests.class));
 		addTest(new TestSuite(EEDefinitionTests.class));
 		if (JavaProjectHelper.isJava9Compatible()) {
 			addTest(new TestSuite(ModuleOptionsTests.class));
@@ -264,6 +263,7 @@
 		addTest(new TestSuite(JavaDebugTargetTests.class));
 		addTest(new TestSuite(WorkingDirectoryTests.class));
 		addTest(new TestSuite(EventDispatcherTest.class));
+		addTest(new TestSuite(SyntheticVariableTests.class));
 
 	// Refactoring tests
 		//TODO: project rename
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/BootpathTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/BootpathTests.java
index c0a6137..ed29561 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/BootpathTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/BootpathTests.java
@@ -21,6 +21,8 @@
 import org.eclipse.core.runtime.Path;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.debug.testplugin.JavaProjectHelper;
 import org.eclipse.jdt.debug.tests.AbstractDebugTest;
 import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
 import org.eclipse.jdt.launching.IRuntimeClasspathEntry;
@@ -32,12 +34,22 @@
  */
 public class BootpathTests extends AbstractDebugTest {
 
+	String mainClass;
+	boolean isJava9Compatible;
+
 	public BootpathTests(String name) {
 		super(name);
+		this.isJava9Compatible = JavaProjectHelper.isJava9Compatible();
+		this.mainClass = this.isJava9Compatible ? "LogicalStructures" : "Breakpoints";
+	}
+
+	@Override
+	protected IJavaProject getProjectContext() {
+		return this.isJava9Compatible ? get9Project() : super.getProjectContext();
 	}
 
 	public void testDefaultBootpath() throws Exception {
-		ILaunchConfiguration config = getLaunchConfiguration("Breakpoints");
+		ILaunchConfiguration config = getLaunchConfiguration(this.mainClass);
 
 		JavaLaunchDelegate delegate = new JavaLaunchDelegate();
 		String[] path = delegate.getBootpath(config);
@@ -51,15 +63,20 @@
 	}
 
 	public void testEmptyBootpath() throws Exception {
-		ILaunchConfiguration config = getLaunchConfiguration("Breakpoints");
+		ILaunchConfiguration config = getLaunchConfiguration(this.mainClass);
 		ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy();
 
 		wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_DEFAULT_CLASSPATH, false);
 
 		JavaLaunchDelegate delegate = new JavaLaunchDelegate();
 		String[] path = delegate.getBootpath(wc);
-		assertNotNull("Empty bootpath should be empty array", path);
-		assertEquals("bootpath should be empty", 0, path.length);
+		if (this.isJava9Compatible) {
+			// strange difference between versions
+			assertNull("Empty bootpath should be null", path);
+		} else {
+			assertNotNull("Empty bootpath should be empty array", path);
+			assertEquals("bootpath should be empty", 0, path.length);
+		}
 		String[][] pathInfo= delegate.getBootpathExt(config);
 		assertNotNull("Bootpath info should'nt be null", pathInfo);
 		assertEquals("Wrong bootpath info array size",3, pathInfo.length);
@@ -69,7 +86,7 @@
 	}
 
 	public void testPrependBootpath() throws Exception {
-		ILaunchConfiguration config = getLaunchConfiguration("Breakpoints");
+		ILaunchConfiguration config = getLaunchConfiguration(this.mainClass);
 		ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy();
 		IRuntimeClasspathEntry[] classpath = JavaRuntime.computeUnresolvedRuntimeClasspath(wc);
 		IRuntimeClasspathEntry[] newpath = new IRuntimeClasspathEntry[classpath.length + 1];
@@ -91,9 +108,39 @@
 		Map<String, Object> map = delegate.getVMSpecificAttributesMap(wc);
 		assertNotNull("Missing VM specific attributes map", map);
 		String[] prepath = (String[]) map.get(IJavaLaunchConfigurationConstants.ATTR_BOOTPATH_PREPEND);
-		assertNotNull("Missing bootpath prepend", pre);
+		assertNotNull("Missing bootpath prepend", prepath);
 		assertEquals("Incorrect number of prepends", 1, prepath.length);
 		assertEquals("wrong prepended path", jar.getLocation().toOSString(), prepath[0]);
 	}
 
+	public void testAppendBootpathJava() throws Exception {
+		IJavaProject project = getProjectContext();
+
+		IResource jar = get14Project().getProject().getFile(new Path("src/A.jar"));
+
+		List<String> mementos = new ArrayList<>(3);
+		mementos.add(JavaRuntime.newDefaultProjectClasspathEntry(project).getMemento());
+		if (this.isJava9Compatible) {
+			mementos.add(JavaRuntime.computeModularJREEntry(project).getMemento());
+		} else {
+			mementos.add(JavaRuntime.computeJREEntry(project).getMemento());
+		}
+		IRuntimeClasspathEntry jarEntry = JavaRuntime.newArchiveRuntimeClasspathEntry(jar.getFullPath());
+		jarEntry.setClasspathProperty(IRuntimeClasspathEntry.BOOTSTRAP_CLASSES);
+		mementos.add(jarEntry.getMemento());
+
+		ILaunchConfiguration config = getLaunchConfiguration(project, this.mainClass);
+		ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy();
+		wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_DEFAULT_CLASSPATH, false);
+		wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_CLASSPATH, mementos);
+
+		JavaLaunchDelegate delegate = new JavaLaunchDelegate();
+		Map<String, Object> map = delegate.getVMSpecificAttributesMap(wc);
+		assertNotNull("Missing VM specific attributes map", map);
+		String[] postpath = (String[]) map.get(IJavaLaunchConfigurationConstants.ATTR_BOOTPATH_APPEND);
+		assertNotNull("Missing bootpath append", postpath);
+		assertEquals("Incorrect number of appends", 1, postpath.length);
+		assertEquals("wrong appended path", jar.getLocation().toOSString(), postpath[0]);
+	}
+
 }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/EEDefinitionTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/EEDefinitionTests.java
index 45d69bd..9af53b2 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/EEDefinitionTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/EEDefinitionTests.java
@@ -88,16 +88,20 @@
 		String[] expected = new String[]{"end.jar", "classes.txt", "others.txt", "add.jar", "ext1.jar", "ext2.jar", "opt-ext.jar"};
 		assertEquals("Wrong number of libraries", expected.length, libs.length);
 		for (int i = 0; i < expected.length; i++) {
-			if (i == 4) {
+			switch (i) {
+			case 4:
 				// ext1 and ext2 can be in either order due to file system ordering
 				assertTrue("Wrong library", expected[i].equals(libs[i].getSystemLibraryPath().lastSegment()) ||
-						expected[i].equals(libs[i+1].getSystemLibraryPath().lastSegment()));
-			} else if (i == 5) {
+					expected[i].equals(libs[i+1].getSystemLibraryPath().lastSegment()));
+				break;
+			case 5:
 				// ext1 and ext2 can be in either order due to file system ordering
 				assertTrue("Wrong library", expected[i].equals(libs[i].getSystemLibraryPath().lastSegment()) ||
-						expected[i].equals(libs[i-1].getSystemLibraryPath().lastSegment()));
-			} else {
+					expected[i].equals(libs[i-1].getSystemLibraryPath().lastSegment()));
+				break;
+			default:
 				assertEquals("Wrong library", expected[i], libs[i].getSystemLibraryPath().lastSegment());
+				break;
 			}
 			if ("classes.txt".equals(expected[i])) {
 				assertEquals("source.txt", libs[i].getSystemLibrarySourcePath().lastSegment());
@@ -116,18 +120,23 @@
 		String[] expected = new String[]{"end.txt", "source.txt", "source.txt", "sourceaddsource.jar", "extra1-src.txt", "extra2-src.txt", ""};
 		assertEquals("Wrong number of libraries", expected.length, libs.length);
 		for (int i = 0; i < expected.length; i++) {
-			if (i == 4) {
+			switch (i) {
+			case 4:
 				// ext1 and ext2 can be in either order due to file system ordering
 				assertTrue("Wrong attachment", expected[i].equals(libs[i].getSystemLibrarySourcePath().lastSegment()) ||
-						expected[i].equals(libs[i+1].getSystemLibrarySourcePath().lastSegment()));
-			} else if (i == 5) {
+					expected[i].equals(libs[i+1].getSystemLibrarySourcePath().lastSegment()));
+				break;
+			case 5:
 				// ext1 and ext2 can be in either order due to file system ordering
 				assertTrue("Wrong attachment", expected[i].equals(libs[i].getSystemLibrarySourcePath().lastSegment()) ||
-						expected[i].equals(libs[i-1].getSystemLibrarySourcePath().lastSegment()));
-			} else if (i == 6){
+					expected[i].equals(libs[i-1].getSystemLibrarySourcePath().lastSegment()));
+				break;
+			case 6:
 				assertEquals("Wrong attachment", Path.EMPTY, libs[i].getSystemLibrarySourcePath());
-			} else {
+				break;
+			default:
 				assertEquals("Wrong attachment", expected[i], libs[i].getSystemLibrarySourcePath().lastSegment());
+				break;
 			}
 		}
 	}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/SyntheticVariableTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/SyntheticVariableTests.java
new file mode 100644
index 0000000..6d21d24
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/SyntheticVariableTests.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2020 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 java.io.File;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.internal.ui.stringsubstitution.SelectedResourceManager;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.contexts.IDebugContextListener;
+import org.eclipse.debug.ui.contexts.IDebugContextProvider;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.debug.core.IJavaThread;
+import org.eclipse.jdt.debug.core.JDIDebugModel;
+import org.eclipse.jdt.debug.testplugin.JavaProjectHelper;
+import org.eclipse.jdt.debug.testplugin.JavaTestPlugin;
+import org.eclipse.jdt.debug.tests.ui.AbstractDebugUiTests;
+import org.eclipse.jdt.internal.debug.ui.contentassist.CurrentFrameContext;
+import org.eclipse.jdt.internal.debug.ui.contentassist.JavaDebugContentAssistProcessor;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.TextViewer;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+
+public class SyntheticVariableTests extends AbstractDebugUiTests {
+
+	private IJavaThread javaThread;
+	private IDebugContextProvider debugContextProvider;
+	private IJavaProject project;
+
+	public SyntheticVariableTests(String name) {
+		super(name);
+		debugContextProvider = new IDebugContextProvider() {
+			@Override
+			public void removeDebugContextListener(IDebugContextListener listener) {
+			}
+
+			@Override
+			public IWorkbenchPart getPart() {
+				return null;
+			}
+
+			@Override
+			public ISelection getActiveContext() {
+				try {
+					return new StructuredSelection(javaThread.getTopStackFrame());
+				} catch (DebugException e) {
+					return null;
+				}
+			}
+
+			@Override
+			public void addDebugContextListener(IDebugContextListener listener) {
+			}
+		};
+	}
+
+	public void testEvaluateMethodParameter_DeepInTwoNestedClasses() throws Exception {
+		addClasses();
+		createBreakPoint(31);
+		try {
+			javaThread = launchToBreakpoint("SyntheticTest");
+
+			IValue value = doEval(javaThread, "predicate");
+
+			assertNotNull("type is null : ", value.getReferenceTypeName());
+			assertTrue("Not expected lambda type : ", value.getReferenceTypeName().startsWith("SyntheticTest$$Lambda"));
+			assertNotNull("value is null :", value.getValueString());
+		} finally {
+			terminateAndRemove(javaThread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testCompleteMethodParameter_DeepInTwoNestedClasses() throws Exception {
+		addClasses();
+		createBreakPoint(31);
+		try {
+			javaThread = launchToBreakpoint("SyntheticTest");
+			registerContextProvider();
+			waitForBuild();
+			List<ICompletionProposal> proposals = computeCompletionProposals(" ", 0);
+
+			assertNotNull("proposals are null : ", proposals);
+			assertTrue("proposals are empty : ", !proposals.isEmpty());
+			System.out.println(proposals);
+			assertTrue("expected variable is not in proposals :", proposals.stream().anyMatch(p -> p.getDisplayString().equals("predicate : Predicate")));
+		} finally {
+			unregisterContextProvider();
+			terminateAndRemove(javaThread);
+			removeAllBreakpoints();
+		}
+	}
+
+	private List<ICompletionProposal> computeCompletionProposals(String source, int completionIndex) throws Exception {
+		JavaDebugContentAssistProcessor comp = new JavaDebugContentAssistProcessor(new CurrentFrameContext());
+		ICompletionProposal[] proposals = sync(new Callable<ICompletionProposal[]>() {
+
+			@Override
+			public ICompletionProposal[] call() throws Exception {
+				ITextViewer viewer = new TextViewer(Display.getDefault().getActiveShell(), SWT.NONE);
+				viewer.setDocument(new Document(source));
+				return comp.computeCompletionProposals(viewer, completionIndex);
+			}
+		});
+		assertNull(String.format("Has errors : %s", comp.getErrorMessage()), comp.getErrorMessage());
+		assertNotNull("proposals are null", proposals);
+
+		return Arrays.asList(proposals);
+	}
+
+	private void createBreakPoint(int lineNumber) throws CoreException {
+		JDIDebugModel.createLineBreakpoint(getProjectContext().getProject(), "SyntheticTest", lineNumber, -1, -1, 0, true, null);
+	}
+
+	@Override
+	protected IJavaProject getProjectContext() {
+		if (project == null) {
+			try {
+				project = createProject("Synthetic", "testresources/synthetic/src", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, true);
+			} catch (Exception e) {
+				fail(e.getMessage());
+			}
+		}
+		return project;
+	}
+
+	private void addClasses() throws Exception {
+		IPath bin = getProjectContext().getPath().append(JavaProjectHelper.BIN_DIR).makeAbsolute();
+		File classDir = JavaTestPlugin.getDefault().getFileInPlugin(new Path("testresources/synthetic/bin"));
+		JavaProjectHelper.importFilesFromDirectory(classDir, bin, null);
+		createLaunchConfiguration("SyntheticTest");
+	}
+
+	private void registerContextProvider() {
+		IWorkbenchWindow activeWindow = SelectedResourceManager.getDefault().getActiveWindow();
+		assertNotNull("activeWindow is null", activeWindow);
+		DebugUITools.getDebugContextManager().getContextService(activeWindow).addDebugContextProvider(debugContextProvider);
+	}
+
+	private void unregisterContextProvider() {
+		IWorkbenchWindow activeWindow = SelectedResourceManager.getDefault().getActiveWindow();
+		assertNotNull("activeWindow is null", activeWindow);
+		DebugUITools.getDebugContextManager().getContextService(activeWindow).removeDebugContextProvider(debugContextProvider);
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		super.tearDown();
+		project.getProject().delete(true, null);
+		project = null;
+	}
+}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/launching/ClasspathShortenerTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/launching/ClasspathShortenerTests.java
index 6c7a43d..22a1247 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/launching/ClasspathShortenerTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/launching/ClasspathShortenerTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2018, 2019 Cedric Chabanois and others.
+ * Copyright (c) 2018, 2020 Cedric Chabanois and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -123,8 +123,12 @@
 		assertArrayEquals(new String[] { JAVA_10_PATH, ENCODING_ARG, "-classpath", classpathShortener.getProcessTempFiles().get(0).getAbsolutePath(),
 				MAIN_CLASS, "-arg1", "arg2" }, classpathShortener.getCmdLine());
 		List<File> classpathJars = getClasspathJarsFromJarManifest(classpathShortener.getProcessTempFiles().get(0));
-		assertEquals(new File(userHomePath("/workspace/myProject/bin")), classpathJars.get(0).getCanonicalFile());
-		assertEquals(new File(userHomePath("/workspace/myProject/lib/lib 1.jar")), classpathJars.get(1).getCanonicalFile());
+		String filePathSuffix = new File(userHomePath("/workspace/myProject/bin")).getPath();
+		int index = classpathJars.get(0).getCanonicalFile().getPath().lastIndexOf(filePathSuffix);
+		assertTrue("First Classpath jar file location not found", index != -1);
+		filePathSuffix = new File(userHomePath("/workspace/myProject/lib/lib 1.jar")).getPath();
+		index = classpathJars.get(1).getCanonicalFile().getPath().lastIndexOf(filePathSuffix);
+		assertTrue("Second Classpath jar file location not found", index != -1);
 	}
 
 	public void testArgFileUsedForLongClasspathOnJava9() throws Exception {
@@ -205,8 +209,12 @@
 		assertArrayEquals(new String[] { JAVA_8_PATH, ENCODING_ARG, "-cp", classpathShortener.getProcessTempFiles().get(0).getAbsolutePath(),
 				MAIN_CLASS, "-arg1", "arg2" }, classpathShortener.getCmdLine());
 		List<File> classpathJars = getClasspathJarsFromJarManifest(classpathShortener.getProcessTempFiles().get(0));
-		assertEquals(new File(userHomePath("/workspace/myProject/bin")), classpathJars.get(0).getCanonicalFile());
-		assertEquals(new File(userHomePath("/workspace/myProject/lib/lib 1.jar")), classpathJars.get(1).getCanonicalFile());
+		String filePathSuffix = new File(userHomePath("/workspace/myProject/bin")).getPath();
+		int index = classpathJars.get(0).getCanonicalFile().getPath().lastIndexOf(filePathSuffix);
+		assertTrue("First Classpath jar file location not found", index != -1);
+		filePathSuffix = new File(userHomePath("/workspace/myProject/lib/lib 1.jar")).getPath();
+		index = classpathJars.get(1).getCanonicalFile().getPath().lastIndexOf(filePathSuffix);
+		assertTrue("Second Classpath jar file location not found", index != -1);
 	}
 
 	public void testClasspathEnvVariableUsedForLongClasspathOnJava8OnWindows() {
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/launching/LongModulePathTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/launching/LongModulePathTests.java
index b3f4e8a..467029e 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/launching/LongModulePathTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/launching/LongModulePathTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2018 Cedric Chabanois and others.
+ * Copyright (c) 2018, 2020 Cedric Chabanois and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -38,6 +38,7 @@
 import org.eclipse.jdt.debug.core.IJavaThread;
 import org.eclipse.jdt.debug.testplugin.JavaProjectHelper;
 import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+import org.eclipse.jdt.debug.tests.TestUtil;
 import org.eclipse.jdt.internal.launching.LaunchingPlugin;
 import org.eclipse.jdt.internal.ui.wizards.buildpaths.BuildPathSupport;
 import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
@@ -82,6 +83,10 @@
 	 * When JVM > 9, an argument file for the modulepath is created when modulepath is too long
 	 */
 	public void testVeryLongModulepathWithArgumentFile() throws Exception {
+		// Disabled for OS other than Win due to Bug 561967
+		if (!Platform.getOS().equals(Platform.OS_WIN32)) {
+			return;
+		}
 		// Given
 		javaProject = createJavaProjectClone("testVeryLongModulePath", CLASSPATH_PROJECT_CONTENT_PATH.toString(), JavaProjectHelper.JAVA_SE_9_EE_NAME, true);
 		useComplianceFromExecutionEnvironment(javaProject);
@@ -89,7 +94,8 @@
 		launchConfiguration = createLaunchConfigurationStopInMain(javaProject, MAIN_TYPE_NAME);
 		int minModulePathLength = 300000;
 		setLongModulepath(javaProject, minModulePathLength);
-		waitForBuild();
+		TestUtil.waitForJobs("testVeryLongModulePath", 100, 10000);
+		TestUtil.runEventLoop();
 
 		// When
 		thread = launchAndSuspend(launchConfiguration);
diff --git a/org.eclipse.jdt.debug.ui/icons/full/dtool16/debug_exc.png b/org.eclipse.jdt.debug.ui/icons/full/dtool16/debug_exc.png
index 07904b7..b352e55 100644
--- a/org.eclipse.jdt.debug.ui/icons/full/dtool16/debug_exc.png
+++ b/org.eclipse.jdt.debug.ui/icons/full/dtool16/debug_exc.png
Binary files differ
diff --git a/org.eclipse.jdt.debug.ui/icons/full/dtool16/debug_exc@2x.png b/org.eclipse.jdt.debug.ui/icons/full/dtool16/debug_exc@2x.png
index 522659a..7892105 100644
--- a/org.eclipse.jdt.debug.ui/icons/full/dtool16/debug_exc@2x.png
+++ b/org.eclipse.jdt.debug.ui/icons/full/dtool16/debug_exc@2x.png
Binary files differ
diff --git a/org.eclipse.jdt.debug.ui/icons/full/etool16/debug_exc.png b/org.eclipse.jdt.debug.ui/icons/full/etool16/debug_exc.png
index 17bb448..59875d1 100644
--- a/org.eclipse.jdt.debug.ui/icons/full/etool16/debug_exc.png
+++ b/org.eclipse.jdt.debug.ui/icons/full/etool16/debug_exc.png
Binary files differ
diff --git a/org.eclipse.jdt.debug.ui/icons/full/etool16/debug_exc@2x.png b/org.eclipse.jdt.debug.ui/icons/full/etool16/debug_exc@2x.png
index 8c168ee..f082faa 100644
--- a/org.eclipse.jdt.debug.ui/icons/full/etool16/debug_exc@2x.png
+++ b/org.eclipse.jdt.debug.ui/icons/full/etool16/debug_exc@2x.png
Binary files differ
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/core/refactoring/JDTDebugRefactoringUtil.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/core/refactoring/JDTDebugRefactoringUtil.java
index b05d0d2..2e2e672 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/core/refactoring/JDTDebugRefactoringUtil.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/core/refactoring/JDTDebugRefactoringUtil.java
@@ -41,13 +41,12 @@
 	 */
 	public static Change createChangeFromList(List<Change> changes, String changeLabel) {
 		int nbChanges= changes.size();
-		if (nbChanges == 0) {
+		switch (nbChanges) {
+		case 0:
 			return null;
-		}
-		else if (nbChanges == 1) {
+		case 1:
 			return changes.get(0);
-		}
-		else {
+		default:
 			return new CompositeChange(changeLabel, changes.toArray(new Change[changes.size()]));
 		}
 	}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaWordFinder.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaWordFinder.java
index 82840ea..bf1765f 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaWordFinder.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaWordFinder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -19,7 +19,6 @@
 import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.text.Region;
 
-import com.ibm.icu.text.UTF16;
 
 /**
  * Contains a static helper method to search documents for the 'word' that encloses the current
@@ -56,7 +55,7 @@
 				c= document.getChar(pos);
 				if (!Character.isJavaIdentifierPart(c)) {
 					// Check for surrogates
-					if (UTF16.isSurrogate(c)) {
+					if (Character.isSurrogate(c)) {
 						/*
 						 * XXX: Here we should create the code point and test whether it is a Java
 						 * identifier part. Currently this is not possible because
@@ -78,8 +77,9 @@
 
 			while (pos < length) {
 				c= document.getChar(pos);
-				if (!Character.isJavaIdentifierPart(c))
+				if (!Character.isJavaIdentifierPart(c)) {
 					break;
+				}
 				++pos;
 			}
 
@@ -89,12 +89,13 @@
 		}
 
 		if (start >= -1 && end > -1) {
-			if (start == offset && end == offset)
+			if (start == offset && end == offset) {
 				return new Region(offset, 0);
-			else if (start == offset)
+			} else if (start == offset) {
 				return new Region(start, end - start);
-			else
+			} else {
 				return new Region(start + 1, end - start - 1);
+			}
 		}
 
 		return null;
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ExpressionInputDialog.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ExpressionInputDialog.java
index f846a4a..17bbae8 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ExpressionInputDialog.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ExpressionInputDialog.java
@@ -259,24 +259,34 @@
                     char[] chars = currentValue.toCharArray();
                     for (int i = 0; i < chars.length; i++) {
                         char c = chars[i];
-                        if (c == '\b') {
-                            buffer.append("\\b"); //$NON-NLS-1$
-                        } else if (c == '\t') {
-                            buffer.append("\\t"); //$NON-NLS-1$
-                        } else if (c == '\n') {
-                            buffer.append("\\n"); //$NON-NLS-1$
-                        } else if (c == '\f') {
-                            buffer.append("\\f"); //$NON-NLS-1$
-                        } else if (c == '\r') {
-                            buffer.append("\\r"); //$NON-NLS-1$
-                        } else if (c == '"') {
-                            buffer.append("\\\""); //$NON-NLS-1$
-                        } else if (c == '\'') {
-                            buffer.append("\\\'"); //$NON-NLS-1$
-                        } else if (c == '\\') {
-                            buffer.append("\\\\"); //$NON-NLS-1$
-                        } else {
-                            buffer.append(c);
+                        switch (c) {
+                        	case '\b':
+                        		buffer.append("\\b"); //$NON-NLS-1$
+                        		break;
+                        	case '\t':
+                        		buffer.append("\\t"); //$NON-NLS-1$
+                        		break;
+                        	case '\n':
+                        		buffer.append("\\n"); //$NON-NLS-1$
+                        		break;
+                        	case '\f':
+                        		buffer.append("\\f"); //$NON-NLS-1$
+                        		break;
+                        	case '\r':
+                        		buffer.append("\\r"); //$NON-NLS-1$
+                        		break;
+                        	case '"':
+                        		buffer.append("\\\""); //$NON-NLS-1$
+                        		break;
+                        	case '\'':
+                        		buffer.append("\\\'"); //$NON-NLS-1$
+                        		break;
+                        	case '\\':
+                        		buffer.append("\\\\"); //$NON-NLS-1$
+                        		break;
+                        	default:
+                        		buffer.append(c);
+                        		break;
                         }
                     }
                     buffer.append('"'); // Surround value in quotes
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/contentassist/CurrentFrameContext.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/contentassist/CurrentFrameContext.java
index ed71f21..671e782 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/contentassist/CurrentFrameContext.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/contentassist/CurrentFrameContext.java
@@ -13,6 +13,9 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.debug.ui.contentassist;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.debug.core.DebugException;
@@ -24,6 +27,8 @@
 import org.eclipse.jdt.internal.debug.core.JavaDebugUtils;
 import org.eclipse.jdt.internal.debug.core.logicalstructures.JDIPlaceholderVariable;
 import org.eclipse.jdt.internal.debug.core.model.JDIThisVariable;
+import org.eclipse.jdt.internal.debug.core.model.SyntheticVariableUtils;
+import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTEvaluationEngine;
 
 
 /**
@@ -63,7 +68,7 @@
 	public String[][] getLocalVariables() throws CoreException {
         IJavaStackFrame frame = getStackFrame();
         if (frame != null) {
-            IVariable[] variables = frame.getVariables();
+			IVariable[] variables = extractVariables(frame);
             int index = 0;
 			while (index < variables.length
 					&& (variables[index] instanceof JDIThisVariable || JDIPlaceholderVariable.class.isAssignableFrom(variables[index].getClass()))) {
@@ -72,7 +77,7 @@
             String[][] locals = new String[2][variables.length - index];
             for (int i = 0; i < locals[0].length; i++) {
                 IJavaVariable var = (IJavaVariable) variables[index];
-                locals[0][i] = var.getName();
+				locals[0][i] = resolveVarName(var);
                 try {
                 	locals[1][i] = var.getJavaType().getName();
                 }
@@ -86,9 +91,29 @@
         return super.getLocalVariables();
     }
 
-    /* (non-Javadoc)
-     * @see org.eclipse.jdt.internal.debug.ui.contentassist.IJavaDebugContentAssistContext#isStatic()
-     */
+	private IVariable[] extractVariables(IJavaStackFrame frame) throws DebugException {
+		ArrayList<IVariable> vars = new ArrayList<>(Arrays.asList(frame.getVariables()));
+		for (IVariable var : vars) {
+			if (var instanceof JDIThisVariable) {
+				vars.addAll(Arrays.asList(SyntheticVariableUtils.findSyntheticVariables(var.getValue().getVariables())));
+				break;
+			}
+		}
+		return vars.toArray(new IVariable[0]);
+	}
+
+	private String resolveVarName(IJavaVariable var) throws DebugException {
+		final String name = var.getName();
+		if (name.startsWith(ASTEvaluationEngine.ANONYMOUS_VAR_PREFIX)) {
+			return name.substring(ASTEvaluationEngine.ANONYMOUS_VAR_PREFIX.length());
+		}
+		return name;
+	}
+
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.internal.debug.ui.contentassist.IJavaDebugContentAssistContext#isStatic()
+	 */
     @Override
 	public boolean isStatic() throws CoreException {
         IJavaStackFrame frame = getStackFrame();
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/JREsPreferencePage.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/JREsPreferencePage.java
index 0dd221c..99f35a5 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/JREsPreferencePage.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/JREsPreferencePage.java
@@ -355,15 +355,20 @@
 					JREMessages.JREsPreferencePage_8 };
 			MessageDialog dialog = new MessageDialog(getShell(), title, null, message, MessageDialog.QUESTION, buttonLabels, 0);
 			int res = dialog.open();
-			if (res == 0) { // apply
+			switch (res) {
+			case 0:
+				// apply
 				return performOk() && super.okToLeave();
-			} else if (res == 1) { // discard
+			case 1:
+				// discard
 				fJREBlock.fillWithWorkspaceJREs();
 				fJREBlock.restoreColumnSettings(JDIDebugUIPlugin.getDefault().getDialogSettings(), IJavaDebugHelpContextIds.JRE_PREFERENCE_PAGE);
 				initDefaultVM();
 				fJREBlock.initializeTimeStamp();
-			} else {
+				break;
+			default:
 				// apply later
+				break;
 			}
 		}
 		return super.okToLeave();
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/LibraryLabelProvider.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/LibraryLabelProvider.java
index 3ae7fce..cbd1143 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/LibraryLabelProvider.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/LibraryLabelProvider.java
@@ -91,7 +91,8 @@
 		} else if (element instanceof SubElement) {
 			SubElement subElement= (SubElement) element;
 			StringBuilder text= new StringBuilder();
-			if (subElement.getType() == SubElement.SOURCE_PATH) {
+			switch (subElement.getType()) {
+			case SubElement.SOURCE_PATH:
 				text.append(JREMessages.VMLibraryBlock_0);
 				IPath systemLibrarySourcePath= subElement.getParent().getSystemLibrarySourcePath();
 				if (systemLibrarySourcePath != null && !Path.EMPTY.equals(systemLibrarySourcePath)) {
@@ -99,7 +100,8 @@
 				} else {
 					text.append(JREMessages.VMLibraryBlock_1);
 				}
-			} else if(subElement.getType() == SubElement.JAVADOC_URL){
+				break;
+			case SubElement.JAVADOC_URL:
 				text.append(JREMessages.LibraryLabelProvider_0);
 				URL javadocLocation= subElement.getParent().getJavadocLocation();
 				if (javadocLocation != null) {
@@ -107,7 +109,8 @@
 				} else {
 					text.append(JREMessages.VMLibraryBlock_1);
 				}
-			} else if (subElement.getType() == SubElement.EXTERNAL_ANNOTATIONS_PATH) {
+				break;
+			case SubElement.EXTERNAL_ANNOTATIONS_PATH:
 				text.append(JREMessages.VMExternalAnnsBlock_1);
 				IPath externalAnnotationsPath = subElement.getParent().getExternalAnnotationsPath();
 				if (externalAnnotationsPath != null && !Path.EMPTY.equals(externalAnnotationsPath)) {
@@ -115,6 +118,9 @@
 				} else {
 					text.append(JREMessages.VMExternalAnnsBlock_2);
 				}
+				break;
+			default:
+				break;
 			}
 			return text.toString();
 		}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/VMLibraryBlock.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/VMLibraryBlock.java
index 4c9b867..d3ed19e 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/VMLibraryBlock.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/VMLibraryBlock.java
@@ -342,33 +342,40 @@
 		}
 		if(standin != null) {
 			LibraryLocation library = standin.toLibraryLocation();
-			if (type == SubElement.JAVADOC_URL) {
+			switch (type) {
+			case SubElement.JAVADOC_URL:
 				URL[] urls = BuildPathDialogAccess.configureJavadocLocation(fLibraryViewer.getControl().getShell(), library.getSystemLibraryPath().toOSString(), library.getJavadocLocation());
 				if (urls != null) {
 					fLibraryContentProvider.setJavadoc(urls[0], selection);
 				}
-			}
-			else if(type == SubElement.SOURCE_PATH){
-				IRuntimeClasspathEntry entry = JavaRuntime.newArchiveRuntimeClasspathEntry(library.getSystemLibraryPath());
-				entry.setSourceAttachmentPath(library.getSystemLibrarySourcePath());
-				entry.setSourceAttachmentRootPath(library.getPackageRootPath());
-				IClasspathEntry classpathEntry = BuildPathDialogAccess.configureSourceAttachment(fLibraryViewer.getControl().getShell(), entry.getClasspathEntry());
-				if (classpathEntry != null) {
-					fLibraryContentProvider.setSourcePath(classpathEntry.getSourceAttachmentPath(), classpathEntry.getSourceAttachmentRootPath(), selection);
+				break;
+			case SubElement.SOURCE_PATH:
+				{
+					IRuntimeClasspathEntry entry = JavaRuntime.newArchiveRuntimeClasspathEntry(library.getSystemLibraryPath());
+					entry.setSourceAttachmentPath(library.getSystemLibrarySourcePath());
+					entry.setSourceAttachmentRootPath(library.getPackageRootPath());
+					IClasspathEntry classpathEntry = BuildPathDialogAccess.configureSourceAttachment(fLibraryViewer.getControl().getShell(), entry.getClasspathEntry());
+					if (classpathEntry != null) {
+						fLibraryContentProvider.setSourcePath(classpathEntry.getSourceAttachmentPath(), classpathEntry.getSourceAttachmentRootPath(), selection);
+					}
+					break;
 				}
-			}
-			else if(type == SubElement.EXTERNAL_ANNOTATIONS_PATH) {
-				IRuntimeClasspathEntry entry = JavaRuntime.newArchiveRuntimeClasspathEntry(library.getSystemLibraryPath());
-				entry.setExternalAnnotationsPath(library.getExternalAnnotationsPath());
-				IClasspathAttribute[] extraAttributes = entry.getClasspathEntry().getExtraAttributes();
-				String annotationPathString = findClasspathAttribute(extraAttributes, IClasspathAttribute.EXTERNAL_ANNOTATION_PATH);
-				IPath annotationPath = null == annotationPathString ? null : new Path(annotationPathString);
-
-				IPath newPath = BuildPathDialogAccess.configureExternalAnnotationsAttachment(fLibraryViewer.getControl().getShell(), annotationPath);
-				if (null == newPath) {
-					return;
+			case SubElement.EXTERNAL_ANNOTATIONS_PATH:
+				{
+					IRuntimeClasspathEntry entry = JavaRuntime.newArchiveRuntimeClasspathEntry(library.getSystemLibraryPath());
+					entry.setExternalAnnotationsPath(library.getExternalAnnotationsPath());
+					IClasspathAttribute[] extraAttributes = entry.getClasspathEntry().getExtraAttributes();
+					String annotationPathString = findClasspathAttribute(extraAttributes, IClasspathAttribute.EXTERNAL_ANNOTATION_PATH);
+					IPath annotationPath = null == annotationPathString ? null : new Path(annotationPathString);
+					IPath newPath = BuildPathDialogAccess.configureExternalAnnotationsAttachment(fLibraryViewer.getControl().getShell(), annotationPath);
+					if (null == newPath) {
+						return;
+					}
+					fLibraryContentProvider.setAnnotationsPath(newPath.segmentCount() == 0 ? null : newPath, selection);
+					break;
 				}
-				fLibraryContentProvider.setAnnotationsPath(newPath.segmentCount() == 0 ? null : newPath, selection);
+			default:
+				break;
 			}
 		}
 	}
diff --git a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
index b7a15bc..bacd7f3 100644
--- a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
+++ b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
@@ -74,6 +74,7 @@
 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.LambdaUtils;
+import org.eclipse.jdt.internal.debug.core.model.SyntheticVariableUtils;
 import org.eclipse.jdt.internal.debug.eval.EvaluationResult;
 import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstructionSequence;
 
@@ -303,7 +304,7 @@
 			IJavaObject thisClass = context.getThis();
 			IVariable[] innerClassFields; // For anonymous classes, getting variables from outer class
 			if (null != thisClass) {
-				innerClassFields = thisClass.getVariables();
+				innerClassFields = extractVariables(thisClass);
 			} else {
 				innerClassFields = new IVariable[0];
 			}
@@ -397,6 +398,13 @@
 		return createExpressionFromAST(snippet, mapper, unit);
 	}
 
+	private IVariable[] extractVariables(IJavaObject thisClass) throws DebugException {
+		IVariable[] vars = thisClass.getVariables();
+		List<IVariable> varList = new ArrayList<>(Arrays.asList(vars));
+		varList.addAll(Arrays.asList(SyntheticVariableUtils.findSyntheticVariables(vars)));
+		return varList.toArray(new IVariable[0]);
+	}
+
 	private String getFixedUnresolvableGenericTypes(IJavaVariable variable) throws DebugException {
 		/*
 		 * This actually fix variables which are type of Generic Types which cannot be resolved to a type in the current content. For example variable
diff --git a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/SourceDebugExtensionParser.java b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/SourceDebugExtensionParser.java
index e3e9785..ed2fbeb 100644
--- a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/SourceDebugExtensionParser.java
+++ b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/SourceDebugExtensionParser.java
@@ -413,34 +413,34 @@
 	 */
 	private void parseFileInfo(Lexer lexer) throws AbsentInformationException {
 		int lexemType = lexer.lexemType();
-		if (lexemType == Lexer.NUMBER) {
-			int fileId = integerValue(lexer.lexem());
-			if (isAsteriskLexem(lexer.nextLexem())) {
-				throw new AbsentInformationException(
-						JDIMessages.SourceDebugExtensionParser_16);
-			}
-			fCurrentStratum.addFileInfo(fileId, getNonAsteriskString(lexer));
-		} else if (lexemType == Lexer.PLUS) {
-			if (lexer.nextLexem() != Lexer.NUMBER) {
-				throw new AbsentInformationException(
-						JDIMessages.SourceDebugExtensionParser_17);
-			}
-			int fileId = integerValue(lexer.lexem());
-			if (isAsteriskLexem(lexer.nextLexem())) {
-				throw new AbsentInformationException(
-						JDIMessages.SourceDebugExtensionParser_16);
-			}
-			String fileName = getNonAsteriskString(lexer);
-			if (isAsteriskLexem(lexer.lexemType())) {
-				throw new AbsentInformationException(
-						JDIMessages.SourceDebugExtensionParser_19);
-			}
-			fCurrentStratum.addFileInfo(fileId, fileName,
-					getNonAsteriskString(lexer));
-		} else {
-			throw new AbsentInformationException(NLS.bind(
-					JDIMessages.SourceDebugExtensionParser_12,
-					new String[] { new String(lexer.lexem()) }));
+		switch (lexemType) {
+			case Lexer.NUMBER:
+				int fileId = integerValue(lexer.lexem());
+				if (isAsteriskLexem(lexer.nextLexem())) {
+					throw new AbsentInformationException(
+							JDIMessages.SourceDebugExtensionParser_16);
+				}
+				fCurrentStratum.addFileInfo(fileId, getNonAsteriskString(lexer));
+				break;
+			case Lexer.PLUS:
+				if (lexer.nextLexem() != Lexer.NUMBER) {
+					throw new AbsentInformationException(
+							JDIMessages.SourceDebugExtensionParser_17);
+				}
+				fileId = integerValue(lexer.lexem());
+				if (isAsteriskLexem(lexer.nextLexem())) {
+					throw new AbsentInformationException(
+							JDIMessages.SourceDebugExtensionParser_16);
+				}
+				String fileName = getNonAsteriskString(lexer);
+				if (isAsteriskLexem(lexer.lexemType())) {
+					throw new AbsentInformationException(
+							JDIMessages.SourceDebugExtensionParser_19);
+				}
+				fCurrentStratum.addFileInfo(fileId, fileName, getNonAsteriskString(lexer));
+				break;
+			default:
+				throw new AbsentInformationException(NLS.bind(JDIMessages.SourceDebugExtensionParser_12, new String[] { new String(lexer.lexem()) }));
 		}
 	}
 
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 f7b5255..4c51147 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
@@ -60,7 +60,6 @@
 import org.eclipse.jdt.internal.debug.core.JavaDebugUtils;
 import org.eclipse.jdt.internal.debug.core.logicalstructures.JDILambdaVariable;
 import org.eclipse.jdt.internal.debug.core.logicalstructures.JDIReturnValueVariable;
-import org.eclipse.jdt.internal.debug.core.model.MethodResult.ResultType;
 
 import com.sun.jdi.AbsentInformationException;
 import com.sun.jdi.ClassNotLoadedException;
@@ -530,30 +529,42 @@
 	private void addStepReturnValue(List<IJavaVariable> variables) {
 		if (fIsTop) {
 			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;
+			if (methodResult != null && methodResult.fResultType != null) {
+				switch (methodResult.fResultType) {
+					case returned:{
+						if (fDepth + 1 != methodResult.fTargetFrameCount) {
+							// can happen e.g., because of checkPackageAccess/System.getSecurityManager()
+							return;
+						}
+						String name = MessageFormat.format(JDIDebugModelMessages.JDIStackFrame_ReturnValue, methodResult.fMethod.name());
+						variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), methodResult.fValue), true));
+						break;
 					}
-					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;
+					case returning:{
+						String name = MessageFormat.format(JDIDebugModelMessages.JDIStackFrame_ReturningValue, methodResult.fMethod.name());
+						variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), methodResult.fValue), true));
+						break;
 					}
-					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 (methodResult.fResultType == ResultType.step_timeout) {
-					String msg = JDIDebugModelMessages.JDIStackFrame_NotObservedBecauseOfTimeout;
-					variables.add(0, new JDIReturnValueVariable(JDIDebugModelMessages.JDIStackFrame_NoMethodReturnValue, new JDIPlaceholderValue(getJavaDebugTarget(), msg), false));
+					case 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, methodResult.fMethod.name());
+						variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), methodResult.fValue), true));
+						break;
+					}
+					case throwing:{
+						String name = MessageFormat.format(JDIDebugModelMessages.JDIStackFrame_ThrowingException, methodResult.fMethod.name());
+						variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), methodResult.fValue), true));
+						break;
+					}
+					case step_timeout:
+						String msg = JDIDebugModelMessages.JDIStackFrame_NotObservedBecauseOfTimeout;
+						variables.add(0, new JDIReturnValueVariable(JDIDebugModelMessages.JDIStackFrame_NoMethodReturnValue, new JDIPlaceholderValue(getJavaDebugTarget(), msg), false));
+						break;
+					default:
+						break;
 				}
 			} else if (JDIThread.showStepResultIsEnabled(getDebugTarget())) {
 				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/SyntheticVariableUtils.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/SyntheticVariableUtils.java
new file mode 100644
index 0000000..b898892
--- /dev/null
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/SyntheticVariableUtils.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2020 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.internal.debug.core.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.model.IVariable;
+import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTEvaluationEngine;
+
+/**
+ * Utility class for handling Synthetic Variables.
+ */
+public final class SyntheticVariableUtils {
+	private static final String ENCLOSING_INSTANCE_PREFIX = "this$"; //$NON-NLS-1$
+	private static final String ANONYMOUS_VAR_PREFIX = ASTEvaluationEngine.ANONYMOUS_VAR_PREFIX;
+
+	private SyntheticVariableUtils() {
+	}
+
+	/**
+	 * When many anonymous objects are nested as below
+	 *
+	 * <pre>
+	 * public Bar exec(Predicate&lt;String&gt; predicate) {
+	 *
+	 * 	return new Bar() {
+	 * 		private Object bar;
+	 *
+	 * 		&#64;Override
+	 * 		public Foo bar(String vbar) {
+	 * 			return new Foo() {
+	 * 				private Object foo;
+	 *
+	 * 				&#64;Override
+	 * 				public String foo(String vfoo) {
+	 * 					predicate.test("vfoo");
+	 * 					return vfoo;
+	 * 				}
+	 * 			};
+	 * 		}
+	 * 	};
+	 * }
+	 * </pre>
+	 *
+	 * The outermost method parameters are not available as synthetic variables in the bottom most object. This method try to extract those variables
+	 * from the variable graph. This method looks for synthetic variables in enclosing instances and traverse variables of those instances and collect
+	 * synthetic outer local variables and return them.
+	 *
+	 * @param variables
+	 *            variable to search on
+	 * @return array of variables
+	 * @throws DebugException
+	 */
+	public static IVariable[] findSyntheticVariables(IVariable[] variables) throws DebugException {
+		ArrayList<IVariable> extracted = new ArrayList<>();
+		for (IVariable variable : variables) {
+			if (variable.getName().startsWith(ANONYMOUS_VAR_PREFIX)) {
+				extracted.add(variable);
+			}
+
+			if (variable.getName().startsWith(ENCLOSING_INSTANCE_PREFIX)) {
+				extracted.addAll(Arrays.asList(findSyntheticVariables(variable.getValue().getVariables())));
+			}
+		}
+		return extracted.toArray(new IVariable[extracted.size()]);
+	}
+
+}
diff --git a/org.eclipse.jdt.launching.javaagent/pom.xml b/org.eclipse.jdt.launching.javaagent/pom.xml
index 900fbcc..5ab364c 100644
--- a/org.eclipse.jdt.launching.javaagent/pom.xml
+++ b/org.eclipse.jdt.launching.javaagent/pom.xml
@@ -18,7 +18,7 @@
 
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.launching.javaagent</artifactId>
-  <version>3.9.200-SNAPSHOT</version>
+  <version>3.9.300-SNAPSHOT</version>
 
   <dependencies>
     <dependency>
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/AbstractJavaLaunchConfigurationDelegate.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/AbstractJavaLaunchConfigurationDelegate.java
index e511152..90b2b98 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/AbstractJavaLaunchConfigurationDelegate.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/AbstractJavaLaunchConfigurationDelegate.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -322,13 +322,10 @@
 		IRuntimeClasspathEntry jreEntry = null;
 		while (jreEntry == null && index < entries.length) {
 			IRuntimeClasspathEntry entry = entries[index++];
-			if (entry.getClasspathProperty() == IRuntimeClasspathEntry.BOOTSTRAP_CLASSES
-					|| entry.getClasspathProperty() == IRuntimeClasspathEntry.STANDARD_CLASSES) {
-				if (JavaRuntime.isVMInstallReference(entry)) {
-					jreEntry = entry;
-				} else {
-					bootEntriesPrepend.add(entry);
-				}
+			if (JavaRuntime.isVMInstallReference(entry)) {
+				jreEntry = entry;
+			} else if (entry.getClasspathProperty() == IRuntimeClasspathEntry.BOOTSTRAP_CLASSES) {
+				bootEntriesPrepend.add(entry);
 			}
 		}
 		IRuntimeClasspathEntry[] bootEntriesPrep = JavaRuntime
@@ -473,22 +470,27 @@
 		for (IRuntimeClasspathEntry entry : entries) {
 			String location = entry.getLocation();
 			if (location != null) {
-				if (entry.getClasspathProperty() == IRuntimeClasspathEntry.USER_CLASSES) {
+				switch (entry.getClasspathProperty()) {
+				case IRuntimeClasspathEntry.USER_CLASSES:
 					if (!classpathSet.contains(location)) {
 						classpathEntries.add(location);
 						classpathSet.add(location);
 					}
-				} else if (entry.getClasspathProperty() == IRuntimeClasspathEntry.CLASS_PATH) {
+					break;
+				case IRuntimeClasspathEntry.CLASS_PATH:
 					if (!classpathSet.contains(location)) {
 						classpathEntries.add(location);
 						classpathSet.add(location);
 					}
-
-				} else if (entry.getClasspathProperty() == IRuntimeClasspathEntry.MODULE_PATH) {
+					break;
+				case IRuntimeClasspathEntry.MODULE_PATH:
 					if (!modulepathSet.contains(location)) {
 						modulepathEntries.add(location);
 						modulepathSet.add(location);
 					}
+					break;
+				default:
+					break;
 				}
 
 			}
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaRuntime.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaRuntime.java
index d8ee60a..3da32e8 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaRuntime.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaRuntime.java
@@ -1565,14 +1565,19 @@
 		int property = -1;
 		switch (container.getKind()) {
 			case IClasspathContainer.K_APPLICATION:
-				if (entry.getClasspathProperty() == IRuntimeClasspathEntry.MODULE_PATH) {
-					property = IRuntimeClasspathEntry.MODULE_PATH;
-				} else if (entry.getClasspathProperty() == IRuntimeClasspathEntry.CLASS_PATH) {
-					property = IRuntimeClasspathEntry.CLASS_PATH;
-				} else {
-					property = IRuntimeClasspathEntry.USER_CLASSES;
+				switch (entry.getClasspathProperty()) {
+					case IRuntimeClasspathEntry.MODULE_PATH:
+						property = IRuntimeClasspathEntry.MODULE_PATH;
+						break;
+					case IRuntimeClasspathEntry.CLASS_PATH:
+						property = IRuntimeClasspathEntry.CLASS_PATH;
+						break;
+					default:
+						property = IRuntimeClasspathEntry.USER_CLASSES;
+						break;
 				}
 				break;
+
 			case IClasspathContainer.K_DEFAULT_SYSTEM:
 				property = IRuntimeClasspathEntry.STANDARD_CLASSES;
 				break;
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/sourcelookup/advanced/AdvancedSourceLookup.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/sourcelookup/advanced/AdvancedSourceLookup.java
index eefa06c..f0b3fba 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/sourcelookup/advanced/AdvancedSourceLookup.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/sourcelookup/advanced/AdvancedSourceLookup.java
@@ -93,9 +93,14 @@
 
 	private static void addWorkspaceLocation(Collection<File> locations, IPath workspacePath) {
 		IResource resource = root.findMember(workspacePath);
-		if (resource != null) {
-			locations.add(resource.getLocation().toFile());
+		if (resource == null) {
+			return;
 		}
+		IPath location = resource.getLocation();
+		if (location == null) {
+			return;
+		}
+		locations.add(location.toFile());
 	}
 
 	/**