diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFixCore.java index 844c6ce9b1d..29d5a5c3f15 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFixCore.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFixCore.java @@ -945,7 +945,7 @@ public boolean visit(final ThisExpression node) { } ITypeBinding targetTypeBinding= ASTNodes.getTargetType(classInstanceCreation); - if (ASTNodes.isTargetAmbiguous(classInstanceCreation, ASTNodes.isExplicitlyTypedLambda(cicReplacement)) || targetTypeBinding.getFunctionalInterfaceMethod() == null) { + if (needCastForWildcardArgument(classInstanceCreation) || ASTNodes.isTargetAmbiguous(classInstanceCreation, ASTNodes.isExplicitlyTypedLambda(cicReplacement)) || targetTypeBinding.getFunctionalInterfaceMethod() == null) { CastExpression cast= ast.newCastExpression(); cast.setExpression(cicReplacement); ImportRewrite importRewrite= cuRewrite.getImportRewrite(); @@ -962,6 +962,49 @@ public boolean visit(final ThisExpression node) { } } + private boolean needCastForWildcardArgument(ClassInstanceCreation classInstanceCreation) { + if (classInstanceCreation.getLocationInParent() == MethodInvocation.ARGUMENTS_PROPERTY) { + MethodInvocation parent= (MethodInvocation)classInstanceCreation.getParent(); + List arguments= parent.arguments(); + IMethodBinding methodBinding= parent.resolveMethodBinding(); + if (methodBinding != null) { + ITypeBinding[] parameterTypes= methodBinding.getParameterTypes(); + int index= -1; + for (int i= 0; i < arguments.size(); ++i) { + if (arguments.get(i) == classInstanceCreation) { + index= i; + break; + } + } + if (index >= 0) { + ITypeBinding parameterTypeBinding= null; + if (index < parameterTypes.length) { + parameterTypeBinding= parameterTypes[index]; + } else { + parameterTypeBinding= parameterTypes[parameterTypes.length - 1].getComponentType(); + } + ITypeBinding classInstanceParameterizedType= classInstanceCreation.getType().resolveBinding(); + ITypeBinding[] classInstanceTypeArguments= classInstanceParameterizedType.getTypeArguments(); + ITypeBinding[] typeArguments= parameterTypeBinding.getTypeArguments(); + for (int i= 0; i < typeArguments.length; ++i) { + ITypeBinding typeArgument= typeArguments[i]; + if (typeArgument.isWildcardType()) { + ITypeBinding bound= typeArgument.getBound(); + if (bound == null) { + bound= typeArgument.getErasure(); + } + ITypeBinding classInstanceTypeArgument= classInstanceTypeArguments[i]; + if (!bound.isSubTypeCompatible(classInstanceTypeArgument)) { + return true; + } + } + } + } + } + } + return false; + } + private Expression castMethodRefIfNeeded(final CompilationUnitRewrite cuRewrite, AST ast, Expression methodRef, Expression visited) { boolean needCast= false; Expression replacementNode= methodRef; diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java index 62f2a0eaf1e..605b63d4a4e 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java @@ -6925,4 +6925,132 @@ public String get() { assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected1 }, null); } + @Test + public void testConvertToLambdaIssue1535_1() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String original= """ + package test1; + + import java.util.Iterator; + import java.util.List; + + public class E { + private void func(Iterable a, Iterable b) {} + private void assertIteratorProducesExpectedList( + List expectedList, + Iterator rankedListIterator) { + func(expectedList, new Iterable() { + @Override + public Iterator iterator() { + return rankedListIterator; + } + }); + } + } + """; + ICompilationUnit cu1= pack1.createCompilationUnit("E.java", original, false, null); + + enable(CleanUpConstants.CONVERT_FUNCTIONAL_INTERFACES); + enable(CleanUpConstants.USE_LAMBDA); + + String expected= """ + package test1; + + import java.util.Iterator; + import java.util.List; + + public class E { + private void func(Iterable a, Iterable b) {} + private void assertIteratorProducesExpectedList( + List expectedList, + Iterator rankedListIterator) { + func(expectedList, (Iterable) () -> rankedListIterator); + } + } + """; + + assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected }, null); + + } + + @Test + public void testConvertToLambdaIssue1535_2() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String original= """ + package test1; + + import java.util.Iterator; + import java.util.List; + + public class E { + private void func(Iterable a, Iterable b) {} + + private Iterator myfunc() { + class K implements Iterator { + @Override + public boolean hasNext() { + return false; + } + + @Override + public String next() { + return null; + } + } + return new K(); + } + + private void assertIteratorProducesExpectedList( + List expectedList, + Iterator rankedListIterator) { + func(expectedList, new Iterable() { + @Override + public Iterator iterator() { + return myfunc(); + } + }); + } + } + """; + ICompilationUnit cu1= pack1.createCompilationUnit("E.java", original, false, null); + + enable(CleanUpConstants.CONVERT_FUNCTIONAL_INTERFACES); + enable(CleanUpConstants.USE_LAMBDA); + enable(CleanUpConstants.ALSO_SIMPLIFY_LAMBDA); + + String expected= """ + package test1; + + import java.util.Iterator; + import java.util.List; + + public class E { + private void func(Iterable a, Iterable b) {} + + private Iterator myfunc() { + class K implements Iterator { + @Override + public boolean hasNext() { + return false; + } + + @Override + public String next() { + return null; + } + } + return new K(); + } + + private void assertIteratorProducesExpectedList( + List expectedList, + Iterator rankedListIterator) { + func(expectedList, (Iterable) this::myfunc); + } + } + """; + + assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected }, null); + + } }