diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest18.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest18.java index 945474e..83b63a2 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest18.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest18.java @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Jerome Cambon - [1.8][clean up][quick assist] Convert lambda to anonymous must qualify references to 'this'/'super' - https://bugs.eclipse.org/430573 *******************************************************************************/ package org.eclipse.jdt.ui.tests.quickfix; @@ -1304,6 +1305,162 @@ public class AssistQuickFixTest18 extends QuickFixTest { assertExpectedExistInProposals(proposals, new String[] { expected1 }); } + public void testConvertToAnonymousClassCreation8() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + StringBuffer buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("import java.util.function.IntSupplier;\n"); + buf.append("public class B extends C {\n"); + buf.append(" private int var;\n"); + buf.append(" B() {\n"); + buf.append(" IntSupplier i = () -> {\n"); + buf.append(" int j = this.var;\n"); + buf.append(" super.o();\n"); + buf.append(" int k = super.varC;\n"); + buf.append(" return this.m();\n"); + buf.append(" };\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" public int m() {\n"); + buf.append(" return 7;\n"); + buf.append(" }\n"); + buf.append("}\n"); + buf.append("\n"); + buf.append("class C {\n"); + buf.append(" int varC;\n"); + buf.append(" public void o() {}\n"); + buf.append("}\n"); + + ICompilationUnit cu= pack1.createCompilationUnit("B.java", buf.toString(), false, null); + + int offset= buf.toString().indexOf("->"); + AssistContext context= getCorrectionContext(cu, offset, 0); + assertNoErrors(context); + List proposals= collectAssists(context, false); + + assertNumberOfProposals(proposals, 3); + assertCorrectLabels(proposals); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("import java.util.function.IntSupplier;\n"); + buf.append("public class B extends C {\n"); + buf.append(" private int var;\n"); + buf.append(" B() {\n"); + buf.append(" IntSupplier i = new IntSupplier() {\n"); + buf.append(" @Override\n"); + buf.append(" public int getAsInt() {\n"); + buf.append(" int j = B.this.var;\n"); + buf.append(" B.super.o();\n"); + buf.append(" int k = B.super.varC;\n"); + buf.append(" return B.this.m();\n"); + buf.append(" }\n"); + buf.append(" };\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" public int m() {\n"); + buf.append(" return 7;\n"); + buf.append(" }\n"); + buf.append("}\n"); + buf.append("\n"); + buf.append("class C {\n"); + buf.append(" int varC;\n"); + buf.append(" public void o() {}\n"); + buf.append("}\n"); + + + String expected1= buf.toString(); + + assertExpectedExistInProposals(proposals, new String[] { expected1 }); + } + + public void testConvertToAnonymousClassCreation9() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + StringBuffer buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("import java.util.function.IntSupplier;\n"); + buf.append("public class D {\n"); + buf.append(" D() {\n"); + buf.append(" F f = new F() {\n"); + buf.append(" int x= 10;\n"); + buf.append(" @Override\n"); + buf.append(" public void run() {\n"); + buf.append(" IntSupplier i = () -> {\n"); + buf.append(" class CX {\n"); + buf.append(" int n=10;\n"); + buf.append(" {\n"); + buf.append(" this.n= 0;\n"); + buf.append(" }\n"); + buf.append(" }\n"); + buf.append(" D.this.n();\n"); + buf.append(" return this.x;\n"); + buf.append(" };\n"); + buf.append(" }\n"); + buf.append(" };\n"); + buf.append(" }\n"); + buf.append(" public int n() {\n"); + buf.append(" return 7;\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" @FunctionalInterface\n"); + buf.append(" public interface F {\n"); + buf.append(" void run();\n"); + buf.append(" }\n"); + buf.append("}\n"); + + ICompilationUnit cu= pack1.createCompilationUnit("D.java", buf.toString(), false, null); + + int offset= buf.toString().indexOf("->"); + AssistContext context= getCorrectionContext(cu, offset, 0); + assertNoErrors(context); + List proposals= collectAssists(context, false); + + assertNumberOfProposals(proposals, 3); + assertCorrectLabels(proposals); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("import java.util.function.IntSupplier;\n"); + buf.append("\n"); + buf.append("import test1.D.F;\n"); + buf.append("public class D {\n"); + buf.append(" D() {\n"); + buf.append(" F f = new F() {\n"); + buf.append(" int x= 10;\n"); + buf.append(" @Override\n"); + buf.append(" public void run() {\n"); + buf.append(" IntSupplier i = new IntSupplier() {\n"); + buf.append(" @Override\n"); + buf.append(" public int getAsInt() {\n"); + buf.append(" class CX {\n"); + buf.append(" int n=10;\n"); + buf.append(" {\n"); + buf.append(" this.n= 0;\n"); + buf.append(" }\n"); + buf.append(" }\n"); + buf.append(" D.this.n();\n"); + buf.append(" return F.this.x;\n"); + buf.append(" }\n"); + buf.append(" };\n"); + buf.append(" }\n"); + buf.append(" };\n"); + buf.append(" }\n"); + buf.append(" public int n() {\n"); + buf.append(" return 7;\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" @FunctionalInterface\n"); + buf.append(" public interface F {\n"); + buf.append(" void run();\n"); + buf.append(" }\n"); + buf.append("}\n"); + + + String expected1= buf.toString(); + + assertExpectedExistInProposals(proposals, new String[] { expected1 }); + } + public void testConvertToAnonymousClassCreationWithParameterName() throws Exception { IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); StringBuffer buf= new StringBuffer(); diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFix.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFix.java index 2d6b1ea..62a28d0 100644 --- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFix.java +++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFix.java @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Jerome Cambon - [1.8][clean up][quick assist] Convert lambda to anonymous must qualify references to 'this'/'super' - https://bugs.eclipse.org/430573 *******************************************************************************/ package org.eclipse.jdt.internal.corext.fix; @@ -39,6 +40,7 @@ import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.LambdaExpression; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.ReturnStatement; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; @@ -69,6 +71,7 @@ import org.eclipse.jdt.internal.corext.util.JdtFlags; import org.eclipse.jdt.ui.cleanup.ICleanUpFix; import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings; +import org.eclipse.jdt.internal.ui.text.correction.ASTResolving; public class LambdaExpressionsFix extends CompilationUnitRewriteOperationsFix { @@ -110,6 +113,58 @@ public class LambdaExpressionsFix extends CompilationUnitRewriteOperationsFix { return true; } } + + private static final class ThisOrSuperQualifier extends HierarchicalASTVisitor { + + private ITypeBinding fType; + private CompilationUnitRewrite fCuRewrite; + + public static void perform(LambdaExpression lambdaExpression, ITypeBinding type, CompilationUnitRewrite cuRewrite) { + ThisOrSuperQualifier qualifier= new ThisOrSuperQualifier(); + qualifier.fType= type; + qualifier.fCuRewrite= cuRewrite; + lambdaExpression.accept(qualifier); + } + + @Override + public boolean visit(ThisExpression node) { + if (node.getQualifier() == null) { + fCuRewrite.getASTRewrite().set(node, ThisExpression.QUALIFIER_PROPERTY, getNewDeclaringClass(), null); + } + return true; + } + + @Override + public boolean visit(SuperFieldAccess node) { + if (node.getQualifier() == null) { + fCuRewrite.getASTRewrite().set(node, SuperFieldAccess.QUALIFIER_PROPERTY, getNewDeclaringClass(), null); + } + return true; + } + + @Override + public boolean visit(SuperMethodInvocation node) { + if (node.getQualifier() == null) { + fCuRewrite.getASTRewrite().set(node, SuperMethodInvocation.QUALIFIER_PROPERTY, getNewDeclaringClass(), null); + } + return true; + } + + @Override + public boolean visit(AnonymousClassDeclaration node) { + return false; + } + + @Override + public boolean visit(BodyDeclaration node) { + return false; + } + + private Name getNewDeclaringClass() { + String typeName= fCuRewrite.getImportRewrite().addImport(Bindings.normalizeTypeBinding(fType).getTypeDeclaration()); + return fCuRewrite.getASTRewrite().getAST().newSimpleName(typeName); + } + } private static class AbortSearchException extends RuntimeException { private static final long serialVersionUID= 1L; @@ -397,6 +452,18 @@ public class LambdaExpressionsFix extends CompilationUnitRewriteOperationsFix { MethodDeclaration methodDeclaration= StubUtility2.createImplementationStub(cuRewrite.getCu(), rewrite, importRewrite, importContext, methodBinding, parameterNames, lambdaTypeBinding.getName(), settings, false); + // Qualify reference to this or super + ASTNode parentType= ASTResolving.findParentType(lambdaExpression); + ITypeBinding typeBinding= null; + if (parentType instanceof AbstractTypeDeclaration) { + typeBinding= ((AbstractTypeDeclaration) parentType).resolveBinding(); + } else if (parentType instanceof AnonymousClassDeclaration) { + typeBinding= ((AnonymousClassDeclaration) parentType).resolveBinding(); + } + if (typeBinding != null) { + ThisOrSuperQualifier.perform(lambdaExpression, typeBinding, cuRewrite); + } + Block block; ASTNode lambdaBody= lambdaExpression.getBody(); if (lambdaBody instanceof Block) { @@ -549,7 +616,7 @@ public class LambdaExpressionsFix extends CompilationUnitRewriteOperationsFix { return methodBinding.getReturnType().getFunctionalInterfaceMethod() != null; } - //TODO: should also check whether variable is of a functional type + //TODO: should also check whether variable is of a functional type return locationInParent == SingleVariableDeclaration.INITIALIZER_PROPERTY || locationInParent == VariableDeclarationFragment.INITIALIZER_PROPERTY || locationInParent == Assignment.RIGHT_HAND_SIDE_PROPERTY