Bug 573521 : Merge remote-tracking branch 'origin/master' into BETA_JAVA17

Change-Id: I7eda581a1e0ec7ccb9ebb11d233b7d8db2da4cff
diff --git a/org.eclipse.jdt.debug.tests/java8/Bug573547.java b/org.eclipse.jdt.debug.tests/java8/Bug573547.java
new file mode 100644
index 0000000..806dc9a
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/java8/Bug573547.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+
+import java.util.stream.Stream;
+
+public class Bug573547 {
+	private String payload;
+	
+	private String[] payloads;
+
+	private static String[] PAYLOADS = new String[] {"1"};
+
+	public Bug573547(String payload) {
+		this.payload = payload;
+		this.payloads = new String[]{payload};
+	}
+	
+	public void hoverOverLocal(String[] names) {
+		char[] name = new char[] {'n', 'a', 'm', 'e'};
+		Bug573547 object = new Bug573547("p");
+
+		System.out.println(name.length);
+		System.out.println(object.payload);
+		System.out.println(names.length);
+		/*Root*/System.out.println(object.payloads.length);
+		System.out.println(this.payloads.length);
+		System.out.println(payloads.length);
+
+		Stream.of(name).forEach(a -> {
+			 System.out.println(a.length);			 
+		});
+		nestedHover();
+	}
+	
+	public void nestedHover() {
+		String object = "1234";
+		/*Nested1*/System.out.println(object);
+		(new Nest()).nestedHover();
+	}
+	public static void main(String[] args) {
+		new Bug573547("p").hoverOverLocal(new String[] {"name"});
+	}
+
+	private class Nest {
+		/*Nested2*/private String payload = "np";
+		
+		public void nestedHover() {
+			String object = "1234n";
+			/*Nested2*/System.out.println(object); 
+		}
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.debug.tests/java9/Bug575039.java b/org.eclipse.jdt.debug.tests/java9/Bug575039.java
new file mode 100644
index 0000000..26168b1
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/java9/Bug575039.java
@@ -0,0 +1,6 @@
+public class Bug575039 {
+	public static void main(String[] args) {
+		Thread t = new Thread("Hello bug 575039");
+		t.start();
+	}
+}
\ No newline at end of file
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 685087a..b879fab 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
@@ -498,6 +498,7 @@
 				cfgs.add(createLaunchConfiguration(jp, "Bug573589"));
 				cfgs.add(createLaunchConfiguration(jp, "Bug574395"));
 				cfgs.add(createLaunchConfiguration(jp, "Bug571310"));
+				cfgs.add(createLaunchConfiguration(jp, "Bug573547"));
 	    		loaded18 = true;
 	    		waitForBuild();
 	        }
@@ -528,6 +529,7 @@
 			if (!loaded9) {
 				jp = createProject(NINE_PROJECT_NAME, JavaProjectHelper.TEST_9_SRC_DIR.toString(), JavaProjectHelper.JAVA_SE_9_EE_NAME, false);
 				cfgs.add(createLaunchConfiguration(jp, "LogicalStructures"));
+				cfgs.add(createLaunchConfiguration(jp, "Bug575039"));
 				loaded9 = true;
 				waitForBuild();
 			}
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 7f93c69..08d2977 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
@@ -96,6 +96,7 @@
 import org.eclipse.jdt.debug.tests.eval.GeneralEvalTests;
 import org.eclipse.jdt.debug.tests.eval.GenericsEval17Test;
 import org.eclipse.jdt.debug.tests.eval.GenericsEvalTests;
+import org.eclipse.jdt.debug.tests.eval.Java9Tests;
 import org.eclipse.jdt.debug.tests.eval.LambdaVariableTest;
 import org.eclipse.jdt.debug.tests.eval.SyntheticVariableTests;
 import org.eclipse.jdt.debug.tests.launching.ClasspathShortenerTests;
@@ -339,6 +340,9 @@
 			addTest(new TestSuite(LambdaVariableTest.class));
 		}
 		//addTest(EvalTestSuite.suite());
+		if (JavaProjectHelper.isJava9Compatible()) {
+			addTest(new TestSuite(Java9Tests.class));
+		}
 
 		// long classpath tests
 		addTest(new TestSuite(ClasspathShortenerTests.class));
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/Java9Tests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/Java9Tests.java
new file mode 100644
index 0000000..1b1784f
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/Java9Tests.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * 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.debug.core.model.IValue;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.debug.core.IJavaThread;
+import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+
+public class Java9Tests extends AbstractDebugTest {
+
+	private IJavaThread thread;
+
+	public Java9Tests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected IJavaProject getProjectContext() {
+		return super.get9Project();
+	}
+
+	public void testBug575039_methodBreakpointOnJavaBaseModuleClass_expectSuccessfulEval() throws Exception {
+		String type = "Bug575039";
+		createMethodBreakpoint("java.lang.Thread", "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;Ljava/lang/String;JLjava/security/AccessControlContext;Z)V",
+				true, false);
+		thread = launchToBreakpoint(type);
+		assertNotNull("The program did not suspend", thread);
+
+		String snippet = "name != null";
+		IValue value = doEval(thread, snippet);
+
+		assertNotNull("value is null", value);
+		assertEquals("true", value.getValueString());
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		removeAllBreakpoints();
+		terminateAndRemove(thread);
+		super.tearDown();
+	}
+}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/DebugHoverTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/DebugHoverTests.java
index f21e89c..50f7248 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/DebugHoverTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/DebugHoverTests.java
@@ -25,6 +25,8 @@
 import org.eclipse.debug.core.model.IStackFrame;
 import org.eclipse.debug.core.model.IVariable;
 import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
+import org.eclipse.debug.internal.ui.views.launch.LaunchView;
+import org.eclipse.debug.ui.IDebugUIConstants;
 import org.eclipse.jdi.internal.StringReferenceImpl;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.debug.core.IJavaArray;
@@ -43,6 +45,8 @@
 import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.text.ITextSelection;
 import org.eclipse.jface.text.Region;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.TreeSelection;
 import org.eclipse.test.OrderedTestSuite;
 
 import junit.framework.Test;
@@ -954,6 +958,434 @@
 		}
 	}
 
+	public void testBug573547_insideLambda_onOuterScopeLocalVariableChain() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+
+		final String typeName = "Bug573547";
+		final String expectedMethod = "lambda$0";
+		final int frameNumber = 6;
+		final int bpLine = 41;
+		final int hoverLine = 34;
+
+		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
+		IFile file = (IFile) bp.getMarker().getResource();
+		assertEquals(typeName + ".java", file.getName());
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+			CompilationUnitEditor part = openEditorAndValidateStack(expectedMethod, frameNumber, file, thread);
+
+			JavaDebugHover hover = new JavaDebugHover();
+			hover.setEditor(part);
+
+			String variableName = "payload";
+			int offset = part.getViewer().getDocument().get().indexOf("System.out.println(object.payload")
+					+ "System.out.println(object.".length();
+			IRegion region = new Region(offset, "payload".length());
+			String text = selectAndReveal(part, hoverLine, region);
+			assertEquals(variableName, text);
+			IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region));
+
+			assertNotNull(info);
+			assertEquals("object.payload", info.getName());
+			assertEquals("p", info.getValue().getValueString());
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testBug573547_insideLambda_onOuterScopeMemberVariable() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+		final String typeName = "Bug573547";
+		final String expectedMethod = "lambda$0";
+		final int frameNumber = 6;
+		final int bpLine = 41;
+		final int hoverLine = 38;
+
+		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
+		IFile file = (IFile) bp.getMarker().getResource();
+		assertEquals(typeName + ".java", file.getName());
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+			CompilationUnitEditor part = openEditorAndValidateStack(expectedMethod, frameNumber, file, thread);
+
+			JavaDebugHover hover = new JavaDebugHover();
+			hover.setEditor(part);
+
+			String variableName = "payloads";
+			int offset = part.getViewer().getDocument().get().lastIndexOf("System.out.println(payloads") + "System.out.println(".length();
+			IRegion region = new Region(offset, "payloads".length());
+			String text = selectAndReveal(part, hoverLine, region);
+			assertEquals(variableName, text);
+			IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region));
+
+			assertNotNull(info);
+			assertEquals("payloads", info.getName());
+			assertTrue("Not an array variable", info.getValue() instanceof IJavaArray);
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testBug573547_insideLambda_onOuterScopeMemberVariable_withThis() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+		final String typeName = "Bug573547";
+		final String expectedMethod = "lambda$0";
+		final int frameNumber = 6;
+		final int bpLine = 41;
+		final int hoverLine = 37;
+
+		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
+		IFile file = (IFile) bp.getMarker().getResource();
+		assertEquals(typeName + ".java", file.getName());
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+			CompilationUnitEditor part = openEditorAndValidateStack(expectedMethod, frameNumber, file, thread);
+
+			JavaDebugHover hover = new JavaDebugHover();
+			hover.setEditor(part);
+
+			String variableName = "payloads";
+			int offset = part.getViewer().getDocument().get().lastIndexOf("System.out.println(this.payloads") + "System.out.println(this.".length();
+			IRegion region = new Region(offset, "payloads".length());
+			String text = selectAndReveal(part, hoverLine, region);
+			assertEquals(variableName, text);
+			IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region));
+
+			assertNotNull(info);
+			assertEquals("payloads", info.getName());
+			assertTrue("Not an array variable", info.getValue() instanceof IJavaArray);
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testBug573547_insideLambda_onOuterScopeStaticVariable() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+		final String typeName = "Bug573547";
+		final String expectedMethod = "lambda$0";
+		final int frameNumber = 6;
+		final int bpLine = 41;
+		final int hoverLine = 22;
+
+		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
+		IFile file = (IFile) bp.getMarker().getResource();
+		assertEquals(typeName + ".java", file.getName());
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+			CompilationUnitEditor part = openEditorAndValidateStack(expectedMethod, frameNumber, file, thread);
+
+			JavaDebugHover hover = new JavaDebugHover();
+			hover.setEditor(part);
+
+			String variableName = "PAYLOADS";
+			int offset = part.getViewer().getDocument().get().lastIndexOf("private static String[] PAYLOADS") + "private static String[] ".length();
+			IRegion region = new Region(offset, "payloads".length());
+			String text = selectAndReveal(part, hoverLine, region);
+			assertEquals(variableName, text);
+			IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region));
+
+			assertNotNull(info);
+			assertEquals("PAYLOADS", info.getName());
+			assertTrue("Not an array variable", info.getValue() instanceof IJavaArray);
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testBug573547_insideLambda_onOuterScopeMemberVariable_onLength() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+		final String typeName = "Bug573547";
+		final String expectedMethod = "lambda$0";
+		final int frameNumber = 6;
+		final int bpLine = 41;
+		final int hoverLine = 38;
+
+		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
+		IFile file = (IFile) bp.getMarker().getResource();
+		assertEquals(typeName + ".java", file.getName());
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+			CompilationUnitEditor part = openEditorAndValidateStack(expectedMethod, frameNumber, file, thread);
+
+			JavaDebugHover hover = new JavaDebugHover();
+			hover.setEditor(part);
+
+			String variableName = "length";
+			int offset = part.getViewer().getDocument().get().lastIndexOf("System.out.println(payloads.length")
+					+ "System.out.println(payloads.".length();
+			IRegion region = new Region(offset, "length".length());
+			String text = selectAndReveal(part, hoverLine, region);
+			assertEquals(variableName, text);
+			IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region));
+
+			assertNotNull(info);
+			assertEquals("payloads.length", info.getName());
+			assertEquals("1", info.getValue().getValueString());
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testBug573547_insideLambda_onOuterScopeMemberVariable_withThis_onLength() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+		final String typeName = "Bug573547";
+		final String expectedMethod = "lambda$0";
+		final int frameNumber = 6;
+		final int bpLine = 41;
+		final int hoverLine = 37;
+
+		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
+		IFile file = (IFile) bp.getMarker().getResource();
+		assertEquals(typeName + ".java", file.getName());
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+			CompilationUnitEditor part = openEditorAndValidateStack(expectedMethod, frameNumber, file, thread);
+
+			JavaDebugHover hover = new JavaDebugHover();
+			hover.setEditor(part);
+
+			String variableName = "length";
+			int offset = part.getViewer().getDocument().get().lastIndexOf("System.out.println(this.payloads.length")
+					+ "System.out.println(this.payloads.".length();
+			IRegion region = new Region(offset, "length".length());
+			String text = selectAndReveal(part, hoverLine, region);
+			assertEquals(variableName, text);
+			IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region));
+
+			assertNotNull(info);
+			assertEquals("this.payloads.length", info.getName());
+			assertEquals("1", info.getValue().getValueString());
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testBug573547_insideLambda_onOuterScopeLocalVariable_onLength() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+		final String typeName = "Bug573547";
+		final String expectedMethod = "lambda$0";
+		final int frameNumber = 6;
+		final int bpLine = 41;
+		final int hoverLine = 36;
+
+		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
+		IFile file = (IFile) bp.getMarker().getResource();
+		assertEquals(typeName + ".java", file.getName());
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+			CompilationUnitEditor part = openEditorAndValidateStack(expectedMethod, frameNumber, file, thread);
+
+			JavaDebugHover hover = new JavaDebugHover();
+			hover.setEditor(part);
+
+			String variableName = "length";
+			int offset = part.getViewer().getDocument().get().lastIndexOf("System.out.println(object.payloads.length")
+					+ "System.out.println(object.payloads.".length();
+			IRegion region = new Region(offset, "length".length());
+			String text = selectAndReveal(part, hoverLine, region);
+			assertEquals(variableName, text);
+			IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region));
+
+			assertNotNull(info);
+			assertEquals("object.payloads.length", info.getName());
+			assertEquals("1", info.getValue().getValueString());
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testBug573547_insideLambda_onOuterScopeVariable_whileOnPreviousFrame() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+		final String typeName = "Bug573547";
+		final String expectedMethod = "lambda$0";
+		final int frameNumber = 6;
+		final int bpLine = 41;
+		final int hoverLine = 36;
+
+		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
+		IFile file = (IFile) bp.getMarker().getResource();
+		assertEquals(typeName + ".java", file.getName());
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+			CompilationUnitEditor part = openEditorAndValidateStack(expectedMethod, frameNumber, file, thread);
+
+			selectFrame(thread.getStackFrames()[4]);
+
+			JavaDebugHover hover = new JavaDebugHover();
+			hover.setEditor(part);
+
+			String variableName = "object";
+			int offset = part.getViewer().getDocument().get().lastIndexOf("/*Root*/System.out.println(object")
+					+ "/*Root*/System.out.println(".length();
+			IRegion region = new Region(offset, "object".length());
+			String text = selectAndReveal(part, hoverLine, region);
+			assertEquals(variableName, text);
+			IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region));
+
+			assertNotNull(info);
+			assertEquals("object", info.getName());
+			assertEquals("Bug573547", info.getValue().getReferenceTypeName());
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testBug573547_inNestedMethodInvocation_useCorrectFrameForSelectedVariable() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+		final String typeName = "Bug573547";
+		final String expectedMethod = "nestedHover";
+		final int frameNumber = 3;
+		final int bpLine = 48;
+		final int hoverLine = 48;
+
+		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
+		IFile file = (IFile) bp.getMarker().getResource();
+		assertEquals(typeName + ".java", file.getName());
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+			CompilationUnitEditor part = openEditorAndValidateStack(expectedMethod, frameNumber, file, thread);
+			JavaDebugHover hover = new JavaDebugHover();
+			hover.setEditor(part);
+
+			String variableName = "object";
+			int offset = part.getViewer().getDocument().get().lastIndexOf("/*Nested1*/System.out.println(object")
+					+ "/*Nested1*/System.out.println(".length();
+			IRegion region = new Region(offset, "object".length());
+			String text = selectAndReveal(part, hoverLine, region);
+			assertEquals(variableName, text);
+			IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region));
+
+			assertNotNull(info);
+			assertEquals("object", info.getName());
+			assertEquals("1234", info.getValue().getValueString());
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testBug573547_onVariableOutOfExecutionStack_expectNoHoverInfo() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+		final String typeName = "Bug573547";
+		final String expectedMethod = "nestedHover";
+		final int frameNumber = 3;
+		final int bpLine = 48;
+		final int hoverLine = 60;
+
+		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
+		IFile file = (IFile) bp.getMarker().getResource();
+		assertEquals(typeName + ".java", file.getName());
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+			CompilationUnitEditor part = openEditorAndValidateStack(expectedMethod, frameNumber, file, thread);
+			JavaDebugHover hover = new JavaDebugHover();
+			hover.setEditor(part);
+
+			String variableName = "object";
+			int offset = part.getViewer().getDocument().get().lastIndexOf("/*Nested2*/System.out.println(object")
+					+ "/*Nested2*/System.out.println(".length();
+			IRegion region = new Region(offset, "object".length());
+			String text = selectAndReveal(part, hoverLine, region);
+			assertEquals(variableName, text);
+			IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region));
+
+			assertNull(info);
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testBug573547_inNestedMethodInvocation_inNestedClasses_useCorrectFrameForSelectedVariables() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+		final String typeName = "Bug573547";
+		final String expectedMethod = "nestedHover";
+		final int frameNumber = 4;
+		final int bpLine = 60;
+		final int hoverLineVar = 60;
+		final int hoverLineField = 56;
+
+		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
+		IFile file = (IFile) bp.getMarker().getResource();
+		assertEquals(typeName + ".java", file.getName());
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+			CompilationUnitEditor part = openEditorAndValidateStack(expectedMethod, frameNumber, file, thread);
+			JavaDebugHover hover = new JavaDebugHover();
+			hover.setEditor(part);
+
+			// local variable
+			String variableNameVar = "object";
+			int offsetVar = part.getViewer().getDocument().get().lastIndexOf("/*Nested2*/System.out.println(object")
+					+ "/*Nested1*/System.out.println(".length();
+			IRegion regionVar = new Region(offsetVar, "object".length());
+			String textVar = selectAndReveal(part, hoverLineVar, regionVar);
+			assertEquals(variableNameVar, textVar);
+			IVariable infoVar = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), regionVar));
+
+			assertNotNull(infoVar);
+			assertEquals("object", infoVar.getName());
+			assertEquals("1234n", infoVar.getValue().getValueString());
+
+			// field
+			String variableNameField = "payload";
+			int offsetField = part.getViewer().getDocument().get().lastIndexOf("/*Nested2*/private String payload")
+					+ "/*Nested2*/private String ".length();
+			IRegion regionField = new Region(offsetField, "payload".length());
+			String textField = selectAndReveal(part, hoverLineField, regionField);
+			assertEquals(variableNameField, textField);
+			IVariable infoField = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), regionField));
+
+			assertNotNull(infoField);
+			assertEquals("payload", infoField.getName());
+			assertEquals("np", infoField.getValue().getValueString());
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
 	private CompilationUnitEditor openEditorAndValidateStack(final String expectedMethod, final int expectedFramesNumber, IFile file, IJavaThread thread) throws Exception, DebugException {
 		// Let now all pending jobs proceed, ignore console jobs
 		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
@@ -1021,6 +1453,23 @@
 		return sync(() -> selection.getText());
 	}
 
+	private void selectFrame(IStackFrame frame) throws Exception {
+		LaunchView debugView = sync(() -> (LaunchView) getActivePage().findView(IDebugUIConstants.ID_DEBUG_VIEW));
+		assertNotNull("expected Debug View to be open", debugView);
+
+		TreeSelection selection = sync(() -> (TreeSelection) debugView.getViewer().getSelection());
+		TreePath path = selection.getPaths()[0];
+		TreePath newPath = path.getParentPath().createChildPath(frame);
+		TreeSelection newSelection = new TreeSelection(newPath);
+		sync(() -> debugView.getViewer().setSelection(newSelection, true));
+		processUiEvents(100);
+	}
+
+	@Override
+	protected boolean enableUIEventLoopProcessingInWaiter() {
+		return true;
+	}
+
 	public void testResolveIn2Lambdas() throws Exception {
 		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
 
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugHover.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugHover.java
index 32ccf16..3a1b530 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugHover.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugHover.java
@@ -19,11 +19,13 @@
 import java.util.StringJoiner;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
+import java.util.function.Predicate;
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.debug.core.DebugEvent;
 import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.model.IStackFrame;
 import org.eclipse.debug.core.model.IVariable;
 import org.eclipse.debug.ui.DebugUITools;
 import org.eclipse.debug.ui.IDebugUIConstants;
@@ -63,6 +65,7 @@
 import org.eclipse.jdt.debug.eval.IEvaluationResult;
 import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
 import org.eclipse.jdt.internal.debug.core.logicalstructures.JDIPlaceholderVariable;
+import org.eclipse.jdt.internal.debug.core.model.JDIThisVariable;
 import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTEvaluationEngine;
 import org.eclipse.jdt.ui.JavaUI;
 import org.eclipse.jdt.ui.text.java.hover.IJavaEditorTextHover;
@@ -80,7 +83,8 @@
 
 public class JavaDebugHover implements IJavaEditorTextHover, ITextHoverExtension, ITextHoverExtension2 {
 
-    private IEditorPart fEditor;
+	private static final String THIS = "this"; //$NON-NLS-1$
+	private IEditorPart fEditor;
 
 	/* (non-Javadoc)
 	 * @see org.eclipse.jdt.ui.text.java.hover.IJavaEditorTextHover#setEditor(org.eclipse.ui.IEditorPart)
@@ -267,7 +271,7 @@
 			if (document != null) {
 			    try {
                     String variableName= document.get(hoverRegion.getOffset(), hoverRegion.getLength());
-                    if (variableName.equals("this")) { //$NON-NLS-1$
+					if (variableName.equals(THIS)) {
                         try {
                             IJavaVariable variable = frame.findVariable(variableName);
                             if (variable != null) {
@@ -373,15 +377,15 @@
 								StructuralPropertyDescriptor locationInParent = node.getLocationInParent();
 								if (locationInParent == FieldAccess.NAME_PROPERTY) {
 									FieldAccess fieldAccess = (FieldAccess) node.getParent();
-									if (fieldAccess.getExpression() instanceof ThisExpression) {
-										variable = evaluateField(frame, field);
+									if (fieldAccess.getExpression() instanceof ThisExpression && !onArrayLength) {
+										variable = evaluateField(findFirstFrameForVariable(frame, forField(field)), field);
 									} else {
-										variable = evaluateQualifiedNode(fieldAccess, frame, typeRoot.getJavaProject());
+										variable = evaluateQualifiedNode(fieldAccess, frame, typeRoot.getJavaProject(), forField(field));
 									}
 								} else if (locationInParent == QualifiedName.NAME_PROPERTY) {
-									variable = evaluateQualifiedNode(node.getParent(), frame, typeRoot.getJavaProject());
+									variable = evaluateQualifiedNode(node.getParent(), frame, typeRoot.getJavaProject(), forField(field));
 								} else {
-									variable = evaluateField(frame, field);
+									variable = evaluateField(findFirstFrameForVariable(frame, forField(field)), field);
 								}
             		    	}
             		    }
@@ -391,6 +395,7 @@
             			break;
             		}
             		if (javaElement instanceof ILocalVariable) {
+						ILocalVariable var = (ILocalVariable) javaElement;
 						// if we are on a array, regardless where we are send it to evaluation engine
 						if (onArrayLength) {
 							if (!(codeAssist instanceof ITypeRoot)) {
@@ -401,10 +406,9 @@
 							if (node == null) {
 								return null;
 							}
-							return evaluateQualifiedNode(node.getParent(), frame, typeRoot.getJavaProject());
+							return evaluateQualifiedNode(node.getParent(), frame, typeRoot.getJavaProject(), forLocalVariable(var));
 						}
 
-            		    ILocalVariable var = (ILocalVariable)javaElement;
             		    IJavaElement parent = var.getParent();
 						while (!(parent instanceof IMethod) && !(parent instanceof IInitializer) && parent != null) {
             		    	parent = parent.getParent();
@@ -462,7 +466,7 @@
             				}
             				// find variable if equal or method is a Lambda Method
             				if (equal || method.isLambdaMethod()) {
-            					return findLocalVariable(frame, var.getElementName());
+								return findLocalVariable(findFirstFrameForVariable(frame, forLocalVariable(var)), var.getElementName());
             				}
             			}
             		    break;
@@ -530,7 +534,7 @@
 		return null;
 	}
 
-	private IJavaVariable evaluateQualifiedNode(ASTNode node, IJavaStackFrame frame, IJavaProject project) {
+	private IJavaVariable evaluateQualifiedNode(ASTNode node, IJavaStackFrame frame, IJavaProject project, Predicate<IJavaStackFrame> framePredicate) {
 		StringBuilder snippetBuilder = new StringBuilder();
 		if (node instanceof QualifiedName) {
 			snippetBuilder.append(((QualifiedName) node).getFullyQualifiedName());
@@ -545,7 +549,7 @@
 
 				@Override
 				public boolean visit(ThisExpression node) {
-					segments.add("this"); //$NON-NLS-1$
+					segments.add(THIS);
 					return true;
 				}
 
@@ -556,6 +560,7 @@
 		}
 
 		final String snippet = snippetBuilder.toString();
+
 		class Evaluator implements IEvaluationListener {
 			private CompletableFuture<IEvaluationResult> result = new CompletableFuture<>();
 
@@ -566,7 +571,7 @@
 
 			public void run() throws DebugException {
 				IAstEvaluationEngine engine = JDIDebugPlugin.getDefault().getEvaluationEngine(project, (IJavaDebugTarget) frame.getDebugTarget());
-				engine.evaluate(snippet, frame, this, DebugEvent.EVALUATION_IMPLICIT, false);
+				engine.evaluate(snippet, findFirstFrameForVariable(frame, framePredicate), this, DebugEvent.EVALUATION_IMPLICIT, false);
 			}
 
 			public Optional<IEvaluationResult> getResult() {
@@ -593,4 +598,64 @@
 	public IInformationControlCreator getInformationPresenterControlCreator() {
 		return new ExpressionInformationControlCreator();
 	}
+
+	private static IJavaStackFrame findFirstFrameForVariable(IJavaStackFrame currentFrame, Predicate<IJavaStackFrame> framePredicate) throws DebugException {
+		// check the current frame first
+		if (framePredicate.test(currentFrame)) {
+			return currentFrame;
+		}
+
+		for (IStackFrame stackFrame : currentFrame.getThread().getStackFrames()) {
+			IJavaStackFrame javaStackFrame = (IJavaStackFrame) stackFrame;
+			if (currentFrame != javaStackFrame && framePredicate.test(javaStackFrame)) {
+				return javaStackFrame;
+			}
+		}
+
+		// we couldn't find a frame, so return the current frame, this is highly unlikely we endup here.
+		return currentFrame;
+	}
+
+	private static boolean containsVariable(IStackFrame frame, String variableName) throws DebugException {
+		for (IVariable variable : frame.getVariables()) {
+			if (variable instanceof JDIThisVariable) {
+				for (IVariable fieldVar : variable.getValue().getVariables()) {
+					if (variableName.equals(fieldVar.getName())) {
+						return true;
+					}
+				}
+			} else if (variableName.equals(variable.getName())) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	// the following two predicates will make sure to find correct frame according the java element's enclosing parent.
+	private static Predicate<IJavaStackFrame> forLocalVariable(ILocalVariable variable) {
+		return frame -> {
+			try {
+				return variable.getDeclaringMember() != null && variable.getDeclaringMember().getElementName().equals(frame.getMethodName())
+						&& containsVariable(frame, variable.getElementName());
+			} catch (DebugException e) {
+				JDIDebugUIPlugin.log(e);
+				return false;
+			}
+		};
+
+	}
+
+	private static Predicate<IJavaStackFrame> forField(IField field) {
+		return frame -> {
+			try {
+				return frame.getThis() != null && frame.getThis().getJavaType().getName().equals(field.getDeclaringType().getFullyQualifiedName())
+						&& containsVariable(frame, field.getElementName());
+			} catch (DebugException e) {
+				JDIDebugUIPlugin.log(e);
+				return false;
+			}
+		};
+
+	}
+
 }
diff --git a/org.eclipse.jdt.debug/.settings/.api_filters b/org.eclipse.jdt.debug/.settings/.api_filters
new file mode 100644
index 0000000..87ceb52
--- /dev/null
+++ b/org.eclipse.jdt.debug/.settings/.api_filters
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jdt.debug" version="2">
+    <resource path="META-INF/MANIFEST.MF">
+        <filter comment="Reverted bug 574170" id="926941240">
+            <message_arguments>
+                <message_argument value="3.18.0"/>
+                <message_argument value="3.17.200"/>
+            </message_arguments>
+        </filter>
+    </resource>
+</component>
diff --git a/org.eclipse.jdt.debug/META-INF/MANIFEST.MF b/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
index d7c6bff..ad977cf 100644
--- a/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.debug; singleton:=true
-Bundle-Version: 3.17.300.qualifier
+Bundle-Version: 3.18.0.qualifier
 Bundle-ClassPath: jdimodel.jar
 Bundle-Activator: org.eclipse.jdt.internal.debug.core.JDIDebugPlugin
 Bundle-Vendor: %providerName
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 d9dc4ae..dc3a3ee 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
@@ -41,6 +41,7 @@
 import org.eclipse.debug.core.model.IThread;
 import org.eclipse.debug.core.model.IVariable;
 import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.compiler.IProblem;
@@ -62,6 +63,7 @@
 import org.eclipse.jdt.debug.eval.ICompiledExpression;
 import org.eclipse.jdt.debug.eval.IEvaluationListener;
 import org.eclipse.jdt.debug.eval.IEvaluationResult;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.debug.core.JDIDebugOptions;
 import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
 import org.eclipse.jdt.internal.debug.core.logicalstructures.JDILambdaVariable;
@@ -384,10 +386,16 @@
 			// frame.getThis().getJavaType();
 			// }
 
+			Map<String, String> extraOptions = Collections.emptyMap();
+			// if target runtime is above java 1.8 then switch the compiler to debug mode to ignore java 9 module system
+			if (JavaCore.compareJavaVersions(((IJavaDebugTarget) frame.getDebugTarget()).getVersion(), JavaCore.VERSION_1_8) > 0) {
+				extraOptions = Collections.singletonMap(CompilerOptions.OPTION_JdtDebugCompileMode, JavaCore.ENABLED);
+			}
+
 			unit = parseCompilationUnit(
 					mapper.getSource(receivingType, frame.getLineNumber(), javaProject,
 							frame.isStatic()).toCharArray(),
-					mapper.getCompilationUnitName(), javaProject);
+					mapper.getCompilationUnitName(), javaProject, extraOptions);
 		} catch (CoreException e) {
 			InstructionSequence expression = new InstructionSequence(snippet);
 			expression.addError(e.getStatus().getMessage());
diff --git a/org.eclipse.jdt.debug/pom.xml b/org.eclipse.jdt.debug/pom.xml
index 99fb860..b184853 100644
--- a/org.eclipse.jdt.debug/pom.xml
+++ b/org.eclipse.jdt.debug/pom.xml
@@ -18,6 +18,6 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.debug</artifactId>
-  <version>3.17.300-SNAPSHOT</version>
+  <version>3.18.0-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 </project>
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 b9f2d8a..1cd9863 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
@@ -1679,13 +1679,13 @@
 		} else {
 			// Add all entries except the one from JRE itself
 			IPackageFragmentRoot jreContainer = findJreContainer(project);
-			IPath canonicalJrePath = jreContainer != null ? JavaProject.canonicalizedPath(jreContainer.getPath()) : null;
+			IPath jrePath = jreContainer != null ? jreContainer.getPath() : null;
 
 			for (IRuntimeClasspathEntry entry : entries1) {
 				switch (entry.getClasspathEntry().getEntryKind()) {
 					case IClasspathEntry.CPE_LIBRARY:
 						if (!entry.getPath().lastSegment().contains("jrt-fs.jar") //$NON-NLS-1$
-								&& (canonicalJrePath == null || !canonicalJrePath.equals(JavaProject.canonicalizedPath(entry.getPath())))) {
+								&& (jrePath == null || !jrePath.equals(entry.getPath()))) {
 							entries2.add(entry);
 						}
 						break;
diff --git a/pom.xml b/pom.xml
index 7daf160..8308b92 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
   <packaging>pom</packaging>
 
   <properties>
-    <tycho.scmUrl>scm:git:git://git.eclipse.org/gitroot/jdt/eclipse.jdt.debug.git</tycho.scmUrl>
+    <tycho.scmUrl>scm:git:https://git.eclipse.org/r/jdt/eclipse.jdt.debug.git</tycho.scmUrl>
   </properties>
 
   <!--