Bug570988 : Fix no completions on DebuShell for inner type variables

When invoking content assist on variables which are type of inner class
types the, completions are empty. This is due to the inner class
separator not being resolved properly. The given fix also resolves
Bug571066.

Change-Id: I6018ec5b044b3029a81902418dcbc9a3ae481c3e
Signed-off-by: Gayan Perera <gayanper@gmail.com>
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 4f3e8fd..b6c7744 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
@@ -402,6 +402,7 @@
 				cfgs.add(createLaunchConfiguration(jp, "a.b.c.bug484686"));
 				cfgs.add(createLaunchConfiguration(jp, "a.b.c.GenericMethodEntryTest"));
 				cfgs.add(createLaunchConfiguration(jp, "org.eclipse.debug.tests.targets.HcrClass", true));
+				cfgs.add(createLaunchConfiguration(jp, "a.b.c.Bug570988"));
 				loaded15 = true;
 				waitForBuild();
 	        }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/EvalTestSuite.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/EvalTestSuite.java
index 923bad8..aca0228 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/EvalTestSuite.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/EvalTestSuite.java
@@ -25,6 +25,7 @@
 import org.eclipse.jdt.debug.tests.eval.ByteOperatorsTests;
 import org.eclipse.jdt.debug.tests.eval.CharAssignmentOperatorsTests;
 import org.eclipse.jdt.debug.tests.eval.CharOperatorsTests;
+import org.eclipse.jdt.debug.tests.eval.DebugShellVariableTests;
 import org.eclipse.jdt.debug.tests.eval.DoubleAssignmentOperatorsTests;
 import org.eclipse.jdt.debug.tests.eval.DoubleOperatorsTests;
 import org.eclipse.jdt.debug.tests.eval.FieldValueTests;
@@ -233,6 +234,8 @@
 
 		addTest(new TestSuite(TestsBreakpointConditions.class));
 
+		addTest(new TestSuite(DebugShellVariableTests.class));
+
 	}
 
 	/**
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/DebugShellVariableTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/DebugShellVariableTests.java
new file mode 100644
index 0000000..0b8955b
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/DebugShellVariableTests.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * 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 java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.eclipse.debug.core.DebugException;
+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.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 DebugShellVariableTests extends AbstractDebugUiTests {
+
+	private IJavaThread javaThread;
+	private IDebugContextProvider debugContextProvider;
+
+	public DebugShellVariableTests(String name) {
+		super(name);
+		debugContextProvider = new IDebugContextProvider() {
+			@Override
+			public void removeDebugContextListener(IDebugContextListener listener) {
+			}
+
+			@Override
+			public IWorkbenchPart getPart() {
+				return null;
+			}
+
+			@Override
+			public ISelection getActiveContext() {
+				try {
+					if (javaThread == null) {
+						return StructuredSelection.EMPTY;
+					}
+
+					return new StructuredSelection(javaThread.getTopStackFrame());
+				} catch (DebugException e) {
+					return StructuredSelection.EMPTY;
+				}
+			}
+
+			@Override
+			public void addDebugContextListener(IDebugContextListener listener) {
+			}
+		};
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		registerContextProvider();
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		unregisterContextProvider();
+		super.tearDown();
+	}
+
+	public void testComplete_OnInnerClassTypeVariable_ExpectTypeMemberCompletions() throws Exception {
+		try {
+			debugWithBreakpoint("a.b.c.Bug570988", 27);
+
+			List<ICompletionProposal> proposals = computeCompletionProposals("entry.", 6);
+
+			assertFalse("proposals are empty : ", proposals.isEmpty());
+			assertTrue("expected method[getKey() : String - Entry] is not in proposals :", proposals.stream().anyMatch(p -> p.getDisplayString().equals("getKey() : String - Entry")));
+		} finally {
+			terminateAndRemove(javaThread);
+			removeAllBreakpoints();
+		}
+	}
+
+	public void testComplete_OnGenericClassTypeVariable_ExpectTypeMemberWithCompletionsTypeArguments() throws Exception {
+		try {
+			debugWithBreakpoint("a.b.c.Bug570988", 27);
+
+			List<ICompletionProposal> proposals = computeCompletionProposals("entry.", 6);
+
+			assertFalse("proposals are empty : ", proposals.isEmpty());
+			assertTrue("expected method[getKey() : String - Entry] is not in proposals :", proposals.stream().anyMatch(p -> p.getDisplayString().equals("getKey() : String - Entry")));
+			assertTrue("expected method [getValue() : Long - Entry] is not in proposals :", proposals.stream().anyMatch(p -> p.getDisplayString().equals("getKey() : String - Entry")));
+		} finally {
+			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 debugWithBreakpoint(String testClass, int lineNumber) throws Exception {
+		createLineBreakpoint(lineNumber, testClass);
+		javaThread = launchToBreakpoint(testClass);
+		assertNotNull("The program did not suspend", javaThread);
+	}
+
+	@Override
+	protected IJavaProject getProjectContext() {
+		return get15Project();
+	}
+
+	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);
+	}
+}
diff --git a/org.eclipse.jdt.debug.tests/testsource-j2se-1.5/a/b/c/Bug570988.java b/org.eclipse.jdt.debug.tests/testsource-j2se-1.5/a/b/c/Bug570988.java
new file mode 100644
index 0000000..596c409
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testsource-j2se-1.5/a/b/c/Bug570988.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * 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 a.b.c;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.AbstractMap.SimpleEntry;
+
+public class Bug570988 {
+
+	public static void main(String[] args) {
+		print(new SimpleEntry<String,Long>("Name", 12L));
+	}
+
+	private static void print(Entry<String, Long> entry) {
+		System.out.println(entry.toString());
+	}
+}
\ No newline at end of file
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 671e782..8b32b6f 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
@@ -22,6 +22,7 @@
 import org.eclipse.debug.core.model.IVariable;
 import org.eclipse.debug.ui.DebugUITools;
 import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.debug.core.IJavaStackFrame;
 import org.eclipse.jdt.debug.core.IJavaVariable;
 import org.eclipse.jdt.internal.debug.core.JavaDebugUtils;
@@ -79,7 +80,7 @@
                 IJavaVariable var = (IJavaVariable) variables[index];
 				locals[0][i] = resolveVarName(var);
                 try {
-                	locals[1][i] = var.getJavaType().getName();
+					locals[1][i] = Signature.toString(var.getGenericSignature()).replace('/', '.');
                 }
                 catch(DebugException de) {
                 	locals[1][i] = var.getReferenceTypeName();
@@ -110,7 +111,7 @@
 		return name;
 	}
 
-	
+
 	/* (non-Javadoc)
 	 * @see org.eclipse.jdt.internal.debug.ui.contentassist.IJavaDebugContentAssistContext#isStatic()
 	 */