Fixed bug 458613 - [1.8] lambda not shown in quick type hierarchy

Change-Id: Ia588b0a081e75ed79e4b15a018d3046a996ec500
Signed-off-by: Stephan Herrmann <stephan.herrmann@berlin.de>
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/TypeResolveTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/TypeResolveTests.java
index b762765..557fd82 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/TypeResolveTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/TypeResolveTests.java
@@ -1044,4 +1044,84 @@
 		deleteProject("P");
 	}
 }
+//https://bugs.eclipse.org/bugs/show_bug.cgi?id=458613
+public void testBug458613() throws CoreException, IOException {
+	IJavaProject prj = null;
+	try {
+		prj = createJavaProject("Bug458613", new String[] {"src"}, new String[] {"JCL_LIB"}, "bin", "1.8");
+		createFolder("/Bug458613/src/p");
+		String source = "package p;\n" +
+				"interface I9<T> {\n" +
+				"  void foo(T x);\n" +
+				"}\n" +
+				"public class X {\n" +
+				"  public static void main(String[] args) {\n" +
+				"    A.sort(new String[2], x_ -> { // not shown in Ctrl+T\n" +
+				"    });\n" +
+				"  }\n" +
+				"}\n" +
+				"class A {\n" +
+				"  static <T> void sort(T[] t, I9<? super T> i9b) {}\n" +
+				"}\n";
+		createFile("/Bug458613/src/p/X.java", source);
+		waitForAutoBuild();
+
+		ICompilationUnit unit = getCompilationUnit("/Bug458613/src/p/X.java");
+		String lambdaString = "x_";
+		IJavaElement[] elements = unit.codeSelect(source.indexOf(lambdaString), lambdaString.length());
+		assertEquals("Array size should be 1", 1, elements.length);
+		ILocalVariable variable = (ILocalVariable) elements[0];
+		LambdaMethod method = (LambdaMethod) variable.getParent();
+		LambdaExpression lambda = (LambdaExpression) method.getParent();
+			assertEquals(
+					"Incorrect handle",
+					"=Bug458613/src<p{X.java[X~main~\\[QString;=)=\"Lp.I9\\<Ljava.lang.String;>;!134!169!138=&foo!1=\"Ljava.lang.String;=\"x_=\"V=\"Lp\\/X\\~I9\\"
+					+ "<Ljava\\/lang\\/String;>;.foo\\(Ljava\\/lang\\/String;)V@x_!134!135!134!135!Ljava\\/lang\\/String;!0!true=)",
+					lambda.getHandleMemento());
+	} finally {
+		if (prj != null)
+			deleteProject(prj);
+	}
+}
+//https://bugs.eclipse.org/bugs/show_bug.cgi?id=458613
+public void testBug458613b() throws CoreException, IOException {
+	IJavaProject prj = null;
+	try {
+		prj = createJavaProject("Bug458613", new String[] {"src"}, new String[] {"JCL_LIB"}, "bin", "1.8");
+		createFolder("/Bug458613/src/p");
+		String source = "package p;\n" +
+				"interface I9<U, T> {\n" +
+				"  void foo(T x);\n" +
+				"}\n" +
+				"interface I10<T> extends I9<Number,T> {}\n" +
+				"public class X {\n" +
+				"	I9<Number,String> i9a = x -> {};\n" +
+				"  public static void main(String[] args) {\n" +
+				"    B.sort(new String[2], x_ -> {\n" +
+				"    });\n" +
+				"  }\n" +
+				"}\n" +
+				"class B {\n" +
+				"  static <T> void sort(T[] t, I10<? super T> i10) {} \n" +
+				"}\n";
+		createFile("/Bug458613/src/p/X.java", source);
+		waitForAutoBuild();
+
+		ICompilationUnit unit = getCompilationUnit("/Bug458613/src/p/X.java");
+		String lambdaString = "x_";
+		IJavaElement[] elements = unit.codeSelect(source.indexOf(lambdaString), lambdaString.length());
+		assertEquals("Array size should be 1", 1, elements.length);
+		ILocalVariable variable = (ILocalVariable) elements[0];
+		LambdaMethod method = (LambdaMethod) variable.getParent();
+		LambdaExpression lambda = (LambdaExpression) method.getParent();
+			assertEquals(
+					"Incorrect handle",
+					"=Bug458613/src<p{X.java[X~main~\\[QString;=)=\"Lp.I10\\<Ljava.lang.String;>;!212!224!216=&foo!1=\"Ljava.lang.String;=\"x_=\"V=\"Lp\\/X\\"
+					+ "~I9\\<LNumber;Ljava\\/lang\\/String;>;.foo\\(Ljava\\/lang\\/String;)V@x_!212!213!212!213!Ljava\\/lang\\/String;!0!true=)",
+					lambda.getHandleMemento());
+	} finally {
+		if (prj != null)
+			deleteProject(prj);
+	}
+}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaExpression.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaExpression.java
index 327b07b..45e8580 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaExpression.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2014 IBM Corporation and others.
+ * Copyright (c) 2014, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -7,6 +7,8 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Stephan Herrmann - Contribution for
+ *							Bug 458613 - [1.8] lambda not shown in quick type hierarchy
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
@@ -20,6 +22,12 @@
 import org.eclipse.jdt.core.WorkingCopyOwner;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Scope;
+import org.eclipse.jdt.internal.compiler.lookup.Substitution;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
 import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Util;
 
@@ -41,11 +49,50 @@
 		this.sourceStart = lambdaExpression.sourceStart;
 		this.sourceEnd = lambdaExpression.sourceEnd;
 		this.arrowPosition = lambdaExpression.arrowPosition;
-		this.interphase = new String(CharOperation.replaceOnCopy(lambdaExpression.resolvedType.genericTypeSignature(), '/', '.'));
+		
+		TypeBinding supertype = findLambdaSuperType(lambdaExpression);
+		this.interphase = new String(CharOperation.replaceOnCopy(supertype.genericTypeSignature(), '/', '.'));
 		this.elementInfo = makeTypeElementInfo(this, this.interphase, this.sourceStart, this.sourceEnd, this.arrowPosition); 
 		this.lambdaMethod = LambdaFactory.createLambdaMethod(this, lambdaExpression);
 		this.elementInfo.children = new IJavaElement[] { this.lambdaMethod };
 	}
+
+	public TypeBinding findLambdaSuperType(org.eclipse.jdt.internal.compiler.ast.LambdaExpression lambdaExpression) {
+		// start from the specific type, ignoring type arguments:
+		TypeBinding original = lambdaExpression.resolvedType.original();
+		// infer type arguments from here:
+		final TypeBinding descType = lambdaExpression.descriptor.declaringClass;
+		if (descType instanceof ParameterizedTypeBinding) {
+			final ParameterizedTypeBinding descPTB = (ParameterizedTypeBinding) descType;
+			// intermediate type: original pulled up to the level of descType:
+			final TypeBinding originalSuper = original.findSuperTypeOriginatingFrom(descType);
+			return Scope.substitute(new Substitution() {
+							@Override
+							public TypeBinding substitute(TypeVariableBinding typeVariable) {
+								if (originalSuper instanceof ParameterizedTypeBinding) {
+									ParameterizedTypeBinding originalSuperPTB = (ParameterizedTypeBinding) originalSuper;
+									TypeBinding[] superArguments = originalSuperPTB.arguments;
+									for (int i = 0; i < superArguments.length; i++) {
+										// if originalSuper holds typeVariable as it i'th argument, then the i'th argument of descType is our answer:
+										if (TypeBinding.equalsEquals(superArguments[i], typeVariable))
+											return descPTB.arguments[i];
+									}
+								}
+								// regular substitution:
+								return descPTB.substitute(typeVariable);
+							}
+							@Override
+							public boolean isRawSubstitution() {
+								return descPTB.isRawType();
+							}
+							@Override
+							public LookupEnvironment environment() {
+								return descPTB.environment;
+							}
+						}, original);
+		}
+		return original;
+	}
 	
 	// Construction from memento
 	LambdaExpression(JavaElement parent, String interphase, int sourceStart, int sourceEnd, int arrowPosition) {