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) {