Bug 573553 - Support for Hovering over deep chain on this reference

Previously only array length chain expressions are passed to evaluation
engine which were on this object. Now all chain expression on this
reference are passed to evaluation engine.

Change-Id: I7e0257ccffd1a2304b27d833515f30e0a1ee5e17
Signed-off-by: Gayan Perera <gayanper@gmail.com>
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.debug/+/180634
Tested-by: JDT Bot <jdt-bot@eclipse.org>
Tested-by: Sarika Sinha <sarika.sinha@in.ibm.com>
Reviewed-by: Sarika Sinha <sarika.sinha@in.ibm.com>
diff --git a/org.eclipse.jdt.debug.tests/java8/Bug572629.java b/org.eclipse.jdt.debug.tests/java8/Bug572629.java
index b83892b..84c5fb4 100644
--- a/org.eclipse.jdt.debug.tests/java8/Bug572629.java
+++ b/org.eclipse.jdt.debug.tests/java8/Bug572629.java
@@ -19,6 +19,8 @@
 	private String[] payloads;
 
 	private static String[] PAYLOADS = new String[] {"1"};
+	
+	private Parent parent = new Parent();
 
 	public Bug572629(String payload) {
 		this.payload = payload;
@@ -46,8 +48,28 @@
 			 System.out.println(a.length);			 
 		});
 	}
+
+	private void hoverOnThis() {
+		System.out.println(this.parent.child.age);
+		System.out.println(this.parent.child.name);
+		System.out.println(parent.child.age);
+		System.out.println(parent.child.name);
+	}
+	
 	public static void main(String[] args) {
 		new Bug572629("p").equals(new Bug572629("r"));
 		new Bug572629("p").hoverOverLocal(new String[] {"name"});
+		new Bug572629("p").hoverOnThis();
 	}
+
+	public static class Parent {
+		public Child child = new Child();
+	}
+
+	public static class Child {
+		public int age = 5;
+		
+		public String name = "name";
+	}
+	
 }
\ No newline at end of file
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 3f2105a..037fc01 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
@@ -290,7 +290,7 @@
 		final String typeName = "Bug572629";
 		final String expectedMethod = "equals";
 		final int frameNumber = 2;
-		final int bpLine = 35;
+		final int bpLine = 37;
 
 		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
 		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
@@ -327,7 +327,7 @@
 		final String typeName = "Bug572629";
 		final String expectedMethod = "equals";
 		final int frameNumber = 2;
-		final int bpLine = 35;
+		final int bpLine = 37;
 
 		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
 		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
@@ -364,7 +364,7 @@
 		final String typeName = "Bug572629";
 		final String expectedMethod = "equals";
 		final int frameNumber = 2;
-		final int bpLine = 35;
+		final int bpLine = 37;
 
 		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
 		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
@@ -401,7 +401,7 @@
 		final String typeName = "Bug572629";
 		final String expectedMethod = "equals";
 		final int frameNumber = 2;
-		final int bpLine = 35;
+		final int bpLine = 37;
 
 		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
 		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
@@ -437,7 +437,7 @@
 		final String typeName = "Bug572629";
 		final String expectedMethod = "equals";
 		final int frameNumber = 2;
-		final int bpLine = 35;
+		final int bpLine = 37;
 
 		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
 		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
@@ -474,7 +474,7 @@
 		final String typeName = "Bug572629";
 		final String expectedMethod = "equals";
 		final int frameNumber = 2;
-		final int bpLine = 34;
+		final int bpLine = 36;
 
 		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
 		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
@@ -511,7 +511,7 @@
 		final String typeName = "Bug572629";
 		final String expectedMethod = "hoverOverLocal";
 		final int frameNumber = 2;
-		final int bpLine = 42;
+		final int bpLine = 44;
 
 		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
 		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
@@ -548,7 +548,7 @@
 		final String typeName = "Bug572629";
 		final String expectedMethod = "hoverOverLocal";
 		final int frameNumber = 2;
-		final int bpLine = 44;
+		final int bpLine = 46;
 
 		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
 		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
@@ -585,7 +585,7 @@
 		final String typeName = "Bug572629";
 		final String expectedMethod = "hoverOverLocal";
 		final int frameNumber = 2;
-		final int bpLine = 43;
+		final int bpLine = 45;
 
 		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
 		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
@@ -622,7 +622,7 @@
 		final String typeName = "Bug572629";
 		final String expectedMethod = "lambda$0";
 		final int frameNumber = 6;
-		final int bpLine = 46;
+		final int bpLine = 48;
 
 		IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
 		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
@@ -653,6 +653,154 @@
 		}
 	}
 
+	public void testBug573553_ChainFieldHover_DeepChain_OnThisObjectPrimitive_ExpectValue() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+
+		final String typeName = "Bug572629";
+		final String expectedMethod = "hoverOnThis";
+		final int frameNumber = 2;
+		final int bpLine = 53;
+
+		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 = "age";
+			int offset = part.getViewer().getDocument().get().indexOf("this.parent.child.age") + "this.parent.child.".length();
+			IRegion region = new Region(offset, "age".length());
+			String text = selectAndReveal(part, bpLine, region);
+			assertEquals(variableName, text);
+			IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region));
+
+			assertNotNull(info);
+			assertEquals("this.parent.child.age", info.getName());
+			assertEquals("5", info.getValue().getValueString());
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testBug573553_ChainFieldHover_DeepChain_OnThisObject_ExpectValue() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+
+		final String typeName = "Bug572629";
+		final String expectedMethod = "hoverOnThis";
+		final int frameNumber = 2;
+		final int bpLine = 54;
+
+		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 = "name";
+			int offset = part.getViewer().getDocument().get().indexOf("this.parent.child.name") + "this.parent.child.".length();
+			IRegion region = new Region(offset, "name".length());
+			String text = selectAndReveal(part, bpLine, region);
+			assertEquals(variableName, text);
+			IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region));
+
+			assertNotNull(info);
+			assertEquals("this.parent.child.name", info.getName());
+			assertEquals("name", info.getValue().getValueString());
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testBug573553_ChainFieldHover_DeepChain_Primitive_ExpectValue() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+
+		final String typeName = "Bug572629";
+		final String expectedMethod = "hoverOnThis";
+		final int frameNumber = 2;
+		final int bpLine = 55;
+
+		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 = "age";
+			int offset = part.getViewer().getDocument().get().lastIndexOf("parent.child.age") + "parent.child.".length();
+			IRegion region = new Region(offset, "age".length());
+			String text = selectAndReveal(part, bpLine, region);
+			assertEquals(variableName, text);
+			IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region));
+
+			assertNotNull(info);
+			assertEquals("parent.child.age", info.getName());
+			assertEquals("5", info.getValue().getValueString());
+		} finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testBug573553_ChainFieldHover_DeepChain_Object_ExpectValue() throws Exception {
+		sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
+
+		final String typeName = "Bug572629";
+		final String expectedMethod = "hoverOnThis";
+		final int frameNumber = 2;
+		final int bpLine = 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);
+
+			String variableName = "name";
+			int offset = part.getViewer().getDocument().get().lastIndexOf("parent.child.name") + "parent.child.".length();
+			IRegion region = new Region(offset, "name".length());
+			String text = selectAndReveal(part, bpLine, region);
+			assertEquals(variableName, text);
+			IVariable info = (IVariable) sync(() -> hover.getHoverInfo2(part.getViewer(), region));
+
+			assertNotNull(info);
+			assertEquals("parent.child.name", info.getName());
+			assertEquals("name", info.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));
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 3c076f5..88742e1 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
@@ -374,7 +374,7 @@
 									FieldAccess fieldAccess = (FieldAccess) node.getParent();
 									if (fieldAccess.getExpression() instanceof ThisExpression) {
 										variable = evaluateField(frame, field);
-									} else if (onArrayLength) {
+									} else {
 										variable = evaluateQualifiedNode(fieldAccess, frame, typeRoot.getJavaProject());
 									}
 								} else if (locationInParent == QualifiedName.NAME_PROPERTY) {