From 5bab6cd4c74fc7409ae527b027b780bf98cf0e97 Mon Sep 17 00:00:00 2001 From: Gayan Perera Date: Sat, 9 Dec 2023 22:08:17 +0100 Subject: [PATCH] Add support for new headless quick fixes from upstream --- .../text/correction/QuickAssistProcessor.java | 360 ++++++------------ .../org.eclipse.jdt.ls.tp.target | 2 +- .../ConvertMethodReferenceToLambdaTest.java | 2 +- .../correction/LambdaQuickFixTest.java | 248 ++++++++++++ .../correction/VariableQuickFixTest.java | 30 ++ 5 files changed, 405 insertions(+), 237 deletions(-) diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/text/correction/QuickAssistProcessor.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/text/correction/QuickAssistProcessor.java index f70afbff59..db52208a48 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/text/correction/QuickAssistProcessor.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/text/correction/QuickAssistProcessor.java @@ -28,7 +28,6 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.util.stream.Collectors; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; @@ -106,7 +105,6 @@ import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving; import org.eclipse.jdt.internal.core.manipulation.util.Strings; import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext; -import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2Core; import org.eclipse.jdt.internal.corext.dom.ASTNodes; import org.eclipse.jdt.internal.corext.dom.Bindings; import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder; @@ -114,11 +112,17 @@ import org.eclipse.jdt.internal.corext.dom.JdtASTMatcher; import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer; import org.eclipse.jdt.internal.corext.dom.Selection; -import org.eclipse.jdt.internal.corext.fix.FixMessages; +import org.eclipse.jdt.internal.corext.fix.AddInferredLambdaParameterTypesFixCore; +import org.eclipse.jdt.internal.corext.fix.AddVarLambdaParameterTypesFixCore; +import org.eclipse.jdt.internal.corext.fix.ChangeLambdaBodyToBlockFixCore; +import org.eclipse.jdt.internal.corext.fix.ChangeLambdaBodyToExpressionFixCore; +import org.eclipse.jdt.internal.corext.fix.ConvertLambdaToMethodReferenceFixCore; import org.eclipse.jdt.internal.corext.fix.IProposableFix; +import org.eclipse.jdt.internal.corext.fix.InvertEqualsExpressionFixCore; import org.eclipse.jdt.internal.corext.fix.JoinVariableFixCore; import org.eclipse.jdt.internal.corext.fix.LambdaExpressionAndMethodRefFixCore; import org.eclipse.jdt.internal.corext.fix.LinkedProposalModelCore; +import org.eclipse.jdt.internal.corext.fix.RemoveVarOrInferredLambdaParameterTypesFixCore; import org.eclipse.jdt.internal.corext.fix.SplitVariableFixCore; import org.eclipse.jdt.internal.corext.fix.StringConcatToTextBlockFixCore; import org.eclipse.jdt.internal.corext.fix.SwitchExpressionsFixCore; @@ -209,6 +213,11 @@ public List getAssists(CodeActionParams params, IInvocation getConvertLambdaExpressionAndMethodRefCleanUpProposal(context, coveringNode, resultingCollections); getConvertMethodReferenceToLambdaProposal(context, coveringNode, resultingCollections); getConvertLambdaToMethodReferenceProposal(context, coveringNode, resultingCollections); + getAddInferredLambdaParameterTypesProposal(context, coveringNode, resultingCollections); + getAddVarLambdaParameterTypesProposal(context, coveringNode, resultingCollections); + getRemoveVarOrInferredLambdaParameterTypesProposal(context, coveringNode, resultingCollections); + getChangeLambdaBodyToBlockProposal(context, coveringNode, resultingCollections); + getChangeLambdaBodyToExpressionProposal(context, coveringNode, resultingCollections); // getFixParenthesesInLambdaExpression(context, coveringNode, resultingCollections); // if (!getConvertForLoopProposal(context, coveringNode, resultingCollections)) { // getConvertIterableLoopProposal(context, coveringNode, resultingCollections); @@ -231,6 +240,7 @@ public List getAssists(CodeActionParams params, IInvocation // Variable quick fixes getSplitVariableProposal(context, coveringNode, resultingCollections); getJoinVariableProposal(context, coveringNode, resultingCollections); + getInvertEqualsProposal(context, coveringNode, resultingCollections); return resultingCollections; } return Collections.emptyList(); @@ -909,238 +919,6 @@ private static boolean getConvertMethodReferenceToLambdaProposal(IInvocationCont return true; } - private static boolean getConvertLambdaToMethodReferenceProposal(IInvocationContextCore context, ASTNode coveringNode, Collection resultingCollections) { - // Don't calculate if lambda expression clean up quick assist exists - if (!resultingCollections.stream().filter(wrapper -> wrapper.getProposal().getName().equals(FixMessages.LambdaExpressionAndMethodRefFix_clean_up_expression_msg)).collect(Collectors.toList()).isEmpty()) { - return false; - } - LambdaExpression lambda; - if (coveringNode instanceof LambdaExpression lambdaExpr) { - lambda = lambdaExpr; - } else if (coveringNode.getLocationInParent() == LambdaExpression.BODY_PROPERTY) { - lambda = (LambdaExpression) coveringNode.getParent(); - } else { - lambda = ASTResolving.findEnclosingLambdaExpression(coveringNode); - if (lambda == null) { - return false; - } - } - - ASTNode lambdaBody = lambda.getBody(); - Expression exprBody; - if (lambdaBody instanceof Block block) { - exprBody = getSingleExpressionFromLambdaBody(block); - } else { - exprBody = (Expression) lambdaBody; - } - exprBody = ASTNodes.getUnparenthesedExpression(exprBody); - if (exprBody == null || !isValidLambdaReferenceToMethod(exprBody)) { - return false; - } - - if (!ASTNodes.isParent(exprBody, coveringNode) && !representsDefiningNode(coveringNode, exprBody)) { - return false; - } - - List lambdaParameters = new ArrayList<>(); - for (VariableDeclaration param : (List) lambda.parameters()) { - lambdaParameters.add(param.getName()); - } - if (exprBody instanceof ClassInstanceCreation cic) { - if (cic.getExpression() != null || cic.getAnonymousClassDeclaration() != null) { - return false; - } - if (!matches(lambdaParameters, cic.arguments())) { - return false; - } - } else if (exprBody instanceof ArrayCreation arrayCreation) { - List dimensions = arrayCreation.dimensions(); - if (dimensions.size() != 1) { - return false; - } - if (!matches(lambdaParameters, dimensions)) { - return false; - } - } else if (exprBody instanceof SuperMethodInvocation superMethodInvocation) { - IMethodBinding methodBinding = superMethodInvocation.resolveMethodBinding(); - if (methodBinding == null) { - return false; - } - if (Modifier.isStatic(methodBinding.getModifiers())) { - ITypeBinding invocationTypeBinding = ASTNodes.getInvocationType(superMethodInvocation, methodBinding, superMethodInvocation.getQualifier()); - if (invocationTypeBinding == null) { - return false; - } - } - if (!matches(lambdaParameters, superMethodInvocation.arguments())) { - return false; - } - } else { // MethodInvocation - MethodInvocation methodInvocation = (MethodInvocation) exprBody; - IMethodBinding methodBinding = methodInvocation.resolveMethodBinding(); - if (methodBinding == null) { - return false; - } - - Expression invocationExpr = methodInvocation.getExpression(); - if (Modifier.isStatic(methodBinding.getModifiers())) { - ITypeBinding invocationTypeBinding = ASTNodes.getInvocationType(methodInvocation, methodBinding, invocationExpr); - if (invocationTypeBinding == null) { - return false; - } - if (!matches(lambdaParameters, methodInvocation.arguments())) { - return false; - } - } else if ((lambda.parameters().size() - methodInvocation.arguments().size()) == 1) { - if (invocationExpr == null) { - return false; - } - ITypeBinding invocationTypeBinding = invocationExpr.resolveTypeBinding(); - if (invocationTypeBinding == null) { - return false; - } - IMethodBinding lambdaMethodBinding = lambda.resolveMethodBinding(); - if (lambdaMethodBinding == null) { - return false; - } - ITypeBinding firstParamType = lambdaMethodBinding.getParameterTypes()[0]; - if ((!Bindings.equals(invocationTypeBinding, firstParamType) && !Bindings.isSuperType(invocationTypeBinding, firstParamType)) || !JdtASTMatcher.doNodesMatch(lambdaParameters.get(0), invocationExpr) - || !matches(lambdaParameters.subList(1, lambdaParameters.size()), methodInvocation.arguments())) { - return false; - } - } else if (!matches(lambdaParameters, methodInvocation.arguments())) { - return false; - } - } - - if (resultingCollections == null) { - return true; - } - - AST ast = lambda.getAST(); - ASTRewrite rewrite = ASTRewrite.create(ast); - ImportRewrite importRewrite = null; - MethodReference replacement; - - if (exprBody instanceof ClassInstanceCreation cic) { - CreationReference creationReference = ast.newCreationReference(); - replacement = creationReference; - - Type type = cic.getType(); - if (type.isParameterizedType() && ((ParameterizedType) type).typeArguments().size() == 0) { - type = ((ParameterizedType) type).getType(); - } - creationReference.setType((Type) rewrite.createCopyTarget(type)); - creationReference.typeArguments().addAll(getCopiedTypeArguments(rewrite, cic.typeArguments())); - } else if (exprBody instanceof ArrayCreation arrayCreation) { - CreationReference creationReference = ast.newCreationReference(); - replacement = creationReference; - - ArrayType arrayType = arrayCreation.getType(); - Type copiedElementType = (Type) rewrite.createCopyTarget(arrayType.getElementType()); - creationReference.setType(ast.newArrayType(copiedElementType, arrayType.getDimensions())); - } else if (exprBody instanceof SuperMethodInvocation superMethodInvocation) { - IMethodBinding methodBinding = superMethodInvocation.resolveMethodBinding(); - Name superQualifier = superMethodInvocation.getQualifier(); - - if (Modifier.isStatic(methodBinding.getModifiers())) { - TypeMethodReference typeMethodReference = ast.newTypeMethodReference(); - replacement = typeMethodReference; - - typeMethodReference.setName((SimpleName) rewrite.createCopyTarget(superMethodInvocation.getName())); - importRewrite = StubUtility.createImportRewrite(context.getASTRoot(), true); - ITypeBinding invocationTypeBinding = ASTNodes.getInvocationType(superMethodInvocation, methodBinding, superQualifier); - typeMethodReference.setType(importRewrite.addImport(invocationTypeBinding.getTypeDeclaration(), ast)); - typeMethodReference.typeArguments().addAll(getCopiedTypeArguments(rewrite, superMethodInvocation.typeArguments())); - } else { - SuperMethodReference superMethodReference = ast.newSuperMethodReference(); - replacement = superMethodReference; - - if (superQualifier != null) { - superMethodReference.setQualifier((Name) rewrite.createCopyTarget(superQualifier)); - } - superMethodReference.setName((SimpleName) rewrite.createCopyTarget(superMethodInvocation.getName())); - superMethodReference.typeArguments().addAll(getCopiedTypeArguments(rewrite, superMethodInvocation.typeArguments())); - } - } else { // MethodInvocation - MethodInvocation methodInvocation = (MethodInvocation) exprBody; - IMethodBinding methodBinding = methodInvocation.resolveMethodBinding(); - Expression invocationQualifier = methodInvocation.getExpression(); - - boolean isStaticMethod = Modifier.isStatic(methodBinding.getModifiers()); - boolean isTypeRefToInstanceMethod = methodInvocation.arguments().size() != lambda.parameters().size(); - - if (isStaticMethod || isTypeRefToInstanceMethod) { - TypeMethodReference typeMethodReference = ast.newTypeMethodReference(); - replacement = typeMethodReference; - - typeMethodReference.setName((SimpleName) rewrite.createCopyTarget(methodInvocation.getName())); - importRewrite = StubUtility.createImportRewrite(context.getASTRoot(), true); - ITypeBinding invocationTypeBinding = ASTNodes.getInvocationType(methodInvocation, methodBinding, invocationQualifier); - invocationTypeBinding = StubUtility2Core.replaceWildcardsAndCaptures(invocationTypeBinding); - ImportRewriteContext importRewriteContext = new ContextSensitiveImportRewriteContext(lambda, importRewrite); - typeMethodReference.setType(importRewrite.addImport(invocationTypeBinding, ast, importRewriteContext, TypeLocation.OTHER)); - typeMethodReference.typeArguments().addAll(getCopiedTypeArguments(rewrite, methodInvocation.typeArguments())); - - } else { - ExpressionMethodReference exprMethodReference = ast.newExpressionMethodReference(); - replacement = exprMethodReference; - - exprMethodReference.setName((SimpleName) rewrite.createCopyTarget(methodInvocation.getName())); - if (invocationQualifier != null) { - exprMethodReference.setExpression((Expression) rewrite.createCopyTarget(invocationQualifier)); - } else { - // check if method is in class scope or in super/nested class scope - TypeDeclaration lambdaParentType = (TypeDeclaration) ASTResolving.findParentType(lambda); - ITypeBinding lambdaMethodInvokingClass = lambdaParentType.resolveBinding(); - ITypeBinding lambdaMethodDeclaringClass = methodBinding.getDeclaringClass(); - - ThisExpression newThisExpression = ast.newThisExpression(); - - ITypeBinding nestedRootClass = getNestedRootClass(lambdaMethodInvokingClass); - boolean isSuperClass = isSuperClass(lambdaMethodDeclaringClass, lambdaMethodInvokingClass); - boolean isNestedClass = isNestedClass(lambdaMethodDeclaringClass, lambdaMethodInvokingClass); - - if (lambdaMethodDeclaringClass == lambdaMethodInvokingClass) { - // use this:: - } else if (Modifier.isDefault(methodBinding.getModifiers())) { - boolean nestedInterfaceClass = isNestedInterfaceClass(ast, lambdaMethodDeclaringClass, lambdaMethodInvokingClass); - if (isNestedClass) { - // use this:: - } else if (nestedInterfaceClass && !isNestedClass && !isSuperClass) { - // use this:: - } else if (!nestedInterfaceClass || (nestedRootClass != lambdaMethodInvokingClass)) { - newThisExpression.setQualifier(ast.newName(nestedRootClass.getName())); - } - } else if (lambdaMethodDeclaringClass.isInterface()) { - if (isSuperClass) { - // use this:: - } else { - newThisExpression.setQualifier(ast.newName(nestedRootClass.getName())); - } - } else if (isSuperClass) { - // use this:: - } else { - newThisExpression.setQualifier(ast.newName(nestedRootClass.getName())); - } - exprMethodReference.setExpression(newThisExpression); - } - exprMethodReference.typeArguments().addAll(getCopiedTypeArguments(rewrite, methodInvocation.typeArguments())); - } - } - - rewrite.replace(lambda, replacement, null); - - // add correction proposal - String label = CorrectionMessages.QuickAssistProcessor_convert_to_method_reference; - ASTRewriteCorrectionProposalCore proposal = new ASTRewriteCorrectionProposalCore(label, context.getCompilationUnit(), rewrite, IProposalRelevance.CONVERT_TO_METHOD_REFERENCE); - if (importRewrite != null) { - proposal.setImportRewrite(importRewrite); - } - resultingCollections.add(CodeActionHandler.wrap(proposal, JavaCodeActionKind.QUICK_ASSIST)); - return true; - } - private static Expression getSingleExpressionFromLambdaBody(Block lambdaBody) { if (lambdaBody.statements().size() != 1) { return null; @@ -1875,4 +1653,116 @@ private boolean getSplitVariableProposal(IInvocationContextCore context, ASTNode } return false; } + + private boolean getInvertEqualsProposal(IInvocationContextCore context, ASTNode coveringNode, ArrayList resultingCollections) { + if (resultingCollections != null) { + var fix = InvertEqualsExpressionFixCore.createInvertEqualsFix(context.getASTRoot(), coveringNode); + if (fix != null) { + try { + var p = new ChangeCorrectionProposalCore(fix.getDisplayString(), fix.createChange(null), IProposalRelevance.INVERT_EQUALS); + resultingCollections.add(CodeActionHandler.wrap(p, JavaCodeActionKind.QUICK_ASSIST)); + return true; + } catch (CoreException e) { + // ignore + } + } + } + return false; + } + + private boolean getAddInferredLambdaParameterTypesProposal(IInvocationContextCore context, ASTNode coveringNode, ArrayList resultingCollections) { + if (resultingCollections != null) { + var fix = AddInferredLambdaParameterTypesFixCore.createAddInferredLambdaParameterTypesFix(context.getASTRoot(), coveringNode); + if (fix != null) { + try { + var p = new ChangeCorrectionProposalCore(fix.getDisplayString(), fix.createChange(null), IProposalRelevance.LAMBDA_EXPRESSION_AND_METHOD_REF_CLEANUP); + resultingCollections.add(CodeActionHandler.wrap(p, JavaCodeActionKind.QUICK_ASSIST)); + return true; + } catch (CoreException e) { + // ignore + } + } + } + return false; + } + + private boolean getAddVarLambdaParameterTypesProposal(IInvocationContextCore context, ASTNode coveringNode, ArrayList resultingCollections) { + if (resultingCollections != null) { + var fix = AddVarLambdaParameterTypesFixCore.createAddVarLambdaParameterTypesFix(context.getASTRoot(), coveringNode); + if (fix != null) { + try { + var p = new ChangeCorrectionProposalCore(fix.getDisplayString(), fix.createChange(null), IProposalRelevance.LAMBDA_EXPRESSION_AND_METHOD_REF_CLEANUP); + resultingCollections.add(CodeActionHandler.wrap(p, JavaCodeActionKind.QUICK_ASSIST)); + return true; + } catch (CoreException e) { + // ignore + } + } + } + return false; + } + + private boolean getChangeLambdaBodyToBlockProposal(IInvocationContextCore context, ASTNode coveringNode, ArrayList resultingCollections) { + if (resultingCollections != null) { + var fix = ChangeLambdaBodyToBlockFixCore.createChangeLambdaBodyToBlockFix(context.getASTRoot(), coveringNode); + if (fix != null) { + try { + var p = new ChangeCorrectionProposalCore(fix.getDisplayString(), fix.createChange(null), IProposalRelevance.LAMBDA_EXPRESSION_AND_METHOD_REF_CLEANUP); + resultingCollections.add(CodeActionHandler.wrap(p, JavaCodeActionKind.QUICK_ASSIST)); + return true; + } catch (CoreException e) { + // ignore + } + } + } + return false; + } + + private boolean getChangeLambdaBodyToExpressionProposal(IInvocationContextCore context, ASTNode coveringNode, ArrayList resultingCollections) { + if (resultingCollections != null) { + var fix = ChangeLambdaBodyToExpressionFixCore.createChangeLambdaBodyToBlockFix(context.getASTRoot(), coveringNode); + if (fix != null) { + try { + var p = new ChangeCorrectionProposalCore(fix.getDisplayString(), fix.createChange(null), IProposalRelevance.LAMBDA_EXPRESSION_AND_METHOD_REF_CLEANUP); + resultingCollections.add(CodeActionHandler.wrap(p, JavaCodeActionKind.QUICK_ASSIST)); + return true; + } catch (CoreException e) { + // ignore + } + } + } + return false; + } + + private boolean getRemoveVarOrInferredLambdaParameterTypesProposal(IInvocationContextCore context, ASTNode coveringNode, ArrayList resultingCollections) { + if (resultingCollections != null) { + var fix = RemoveVarOrInferredLambdaParameterTypesFixCore.createRemoveVarOrInferredLambdaParameterTypesFix(context.getASTRoot(), coveringNode); + if (fix != null) { + try { + var p = new ChangeCorrectionProposalCore(fix.getDisplayString(), fix.createChange(null), IProposalRelevance.LAMBDA_EXPRESSION_AND_METHOD_REF_CLEANUP); + resultingCollections.add(CodeActionHandler.wrap(p, JavaCodeActionKind.QUICK_ASSIST)); + return true; + } catch (CoreException e) { + // ignore + } + } + } + return false; + } + + private boolean getConvertLambdaToMethodReferenceProposal(IInvocationContextCore context, ASTNode coveringNode, ArrayList resultingCollections) { + if (resultingCollections != null) { + var fix = ConvertLambdaToMethodReferenceFixCore.createConvertLambdaToMethodReferenceFix(context.getASTRoot(), coveringNode); + if (fix != null) { + try { + var p = new ChangeCorrectionProposalCore(fix.getDisplayString(), fix.createChange(null), IProposalRelevance.LAMBDA_EXPRESSION_AND_METHOD_REF_CLEANUP); + resultingCollections.add(CodeActionHandler.wrap(p, JavaCodeActionKind.QUICK_ASSIST)); + return true; + } catch (CoreException e) { + // ignore + } + } + } + return false; + } } diff --git a/org.eclipse.jdt.ls.target/org.eclipse.jdt.ls.tp.target b/org.eclipse.jdt.ls.target/org.eclipse.jdt.ls.tp.target index a1c8e424e8..8c4d9e2f65 100644 --- a/org.eclipse.jdt.ls.target/org.eclipse.jdt.ls.tp.target +++ b/org.eclipse.jdt.ls.target/org.eclipse.jdt.ls.tp.target @@ -25,7 +25,7 @@ - + diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/ConvertMethodReferenceToLambdaTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/ConvertMethodReferenceToLambdaTest.java index d6f3d62465..0391acef05 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/ConvertMethodReferenceToLambdaTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/ConvertMethodReferenceToLambdaTest.java @@ -84,7 +84,7 @@ public void testMethodReferenceToLambda() throws Exception { @Test public void testLambdaToMethodReference() throws Exception { setIgnoredCommands("Assign statement to new field", "Extract to constant", "Extract to field", "Extract to local variable (replace all occurrences)", "Extract to local variable", "Introduce Parameter...", - ActionMessages.GenerateConstructorsAction_ellipsisLabel, ActionMessages.GenerateConstructorsAction_label, "Extract lambda body to method"); + ActionMessages.GenerateConstructorsAction_ellipsisLabel, ActionMessages.GenerateConstructorsAction_label, "Extract lambda body to method", "Convert to method reference"); IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null); StringBuilder buf = new StringBuilder(); buf.append("package test1;\n"); diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/LambdaQuickFixTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/LambdaQuickFixTest.java index cbafd242e7..4bf181181f 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/LambdaQuickFixTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/LambdaQuickFixTest.java @@ -19,6 +19,8 @@ import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.ls.core.internal.CodeActionUtil; import org.eclipse.jdt.ls.core.internal.JavaCodeActionKind; import org.eclipse.lsp4j.CodeAction; import org.eclipse.lsp4j.CodeActionKind; @@ -117,4 +119,250 @@ public void testCleanUpLambdaConvertLambdaBlockToExpressionAddParenthesis() thro Expected e1 = new Expected("Clean up lambda expression", expected, JavaCodeActionKind.QUICK_ASSIST); assertCodeActions(codeActions, e1); } + + @Test + public void testAddInferredLambdaParameterTypesExpectTypes() throws Exception { + setOnly(JavaCodeActionKind.QUICK_ASSIST); + IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null); + String contents = """ + package test1; + public class L { + public void foo() { + Func f = (a, b) -> System.out.println(a + b); + } + + public interface Func { + void foo(String a, String b); + } + }"""; + ICompilationUnit cu = pack1.createCompilationUnit("L.java", contents, false, null); + String expected = """ + package test1; + public class L { + public void foo() { + Func f = (String a, String b) -> System.out.println(a + b); + } + + public interface Func { + void foo(String a, String b); + } + }"""; + List> codeActions = evaluateCodeActions(cu, CodeActionUtil.getRange(cu, "(a, b)")); + Expected e1 = new Expected("Add inferred lambda parameter types", expected, JavaCodeActionKind.QUICK_ASSIST); + assertCodeActions(codeActions, e1); + } + + @Test + public void testAddVarLambdaParameterTypesExpectVarKeyword() throws Exception { + Hashtable options = TestOptions.getDefaultOptions(); + JavaCore.setComplianceOptions("11", options); + fJProject1.setOptions(options); + + setOnly(JavaCodeActionKind.QUICK_ASSIST); + IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null); + String contents = """ + package test1; + public class L { + public void foo() { + Func f = (a, b) -> System.out.println(a + b); + } + + public interface Func { + void foo(String a, String b); + } + }"""; + ICompilationUnit cu = pack1.createCompilationUnit("L.java", contents, false, null); + String expected = """ + package test1; + public class L { + public void foo() { + Func f = (var a, var b) -> System.out.println(a + b); + } + + public interface Func { + void foo(String a, String b); + } + }"""; + List> codeActions = evaluateCodeActions(cu, CodeActionUtil.getRange(cu, "(a, b)")); + Expected e1 = new Expected("Add 'var' lambda parameter types", expected, JavaCodeActionKind.QUICK_ASSIST); + assertCodeActions(codeActions, e1); + } + + @Test + public void testRemoveVarOrInferredLambdaParameterTypesExpectNoType() throws Exception { + setOnly(JavaCodeActionKind.QUICK_ASSIST); + IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null); + String contents = """ + package test1; + public class L { + public void foo() { + Func f = (String a, String b) -> System.out.println(a + b); + } + + public interface Func { + void foo(String a, String b); + } + }"""; + ICompilationUnit cu = pack1.createCompilationUnit("L.java", contents, false, null); + String expected = """ + package test1; + public class L { + public void foo() { + Func f = (a, b) -> System.out.println(a + b); + } + + public interface Func { + void foo(String a, String b); + } + }"""; + List> codeActions = evaluateCodeActions(cu, CodeActionUtil.getRange(cu, "(String a, String b) ->")); + Expected e1 = new Expected("Remove lambda parameter types", expected, JavaCodeActionKind.QUICK_ASSIST); + assertCodeActions(codeActions, e1); + } + + @Test + public void testRemoveVarOrInferredLambdaParameterTypesExpectNoVarKeyword() throws Exception { + setOnly(JavaCodeActionKind.QUICK_ASSIST); + IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null); + String contents = """ + package test1; + public class L { + public void foo() { + Func f = (var a, var b) -> System.out.println(a + b); + } + + public interface Func { + void foo(String a, String b); + } + }"""; + ICompilationUnit cu = pack1.createCompilationUnit("L.java", contents, false, null); + String expected = """ + package test1; + public class L { + public void foo() { + Func f = (a, b) -> System.out.println(a + b); + } + + public interface Func { + void foo(String a, String b); + } + }"""; + List> codeActions = evaluateCodeActions(cu, CodeActionUtil.getRange(cu, "(var a, var b) ->")); + Expected e1 = new Expected("Remove lambda parameter types", expected, JavaCodeActionKind.QUICK_ASSIST); + assertCodeActions(codeActions, e1); + } + + @Test + public void testChangeLambdaBodyToBlockExpectBlock() throws Exception { + setOnly(JavaCodeActionKind.QUICK_ASSIST); + IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null); + String contents = """ + package test1; + public class L { + public void foo() { + Func f = (a, b) -> System.out.println(a + b); + } + + public interface Func { + void foo(String a, String b); + } + }"""; + ICompilationUnit cu = pack1.createCompilationUnit("L.java", contents, false, null); + String expected = """ + package test1; + public class L { + public void foo() { + Func f = (a, b) -> { + System.out.println(a + b); + }; + } + + public interface Func { + void foo(String a, String b); + } + }"""; + List> codeActions = evaluateCodeActions(cu, CodeActionUtil.getRange(cu, "->")); + Expected e1 = new Expected("Change body expression to block", expected, JavaCodeActionKind.QUICK_ASSIST); + assertCodeActions(codeActions, e1); + } + + @Test + public void testChangeLambdaBodyToExpressionExpectExpression() throws Exception { + setOnly(JavaCodeActionKind.QUICK_ASSIST); + IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null); + String contents = """ + package test1; + public class L { + public void foo() { + Func f = (a, b) -> { + System.out.println(a + b); + }; + } + + public interface Func { + void foo(String a, String b); + } + }"""; + ICompilationUnit cu = pack1.createCompilationUnit("L.java", contents, false, null); + String expected = """ + package test1; + public class L { + public void foo() { + Func f = (a, b) -> System.out.println(a + b); + } + + public interface Func { + void foo(String a, String b); + } + }"""; + List> codeActions = evaluateCodeActions(cu, CodeActionUtil.getRange(cu, "->")); + Expected e1 = new Expected("Change body block to expression", expected, JavaCodeActionKind.QUICK_ASSIST); + assertCodeActions(codeActions, e1); + } + + @Test + public void testConvertLambdaToMethodReferenceExpectMethodRef() throws Exception { + setOnly(JavaCodeActionKind.QUICK_ASSIST); + IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null); + String contents = """ + package test1; + public class L { + public void foo() { + this.consume(a -> a.print()); + } + + public void consume(Func f) { + } + + public interface Func { + void foo(Obj a); + } + + public class Obj { + public void print() {} + } + }"""; + ICompilationUnit cu = pack1.createCompilationUnit("L.java", contents, false, null); + String expected = """ + package test1; + public class L { + public void foo() { + this.consume(Obj::print); + } + + public void consume(Func f) { + } + + public interface Func { + void foo(Obj a); + } + + public class Obj { + public void print() {} + } + }"""; + List> codeActions = evaluateCodeActions(cu, CodeActionUtil.getRange(cu, "->")); + Expected e1 = new Expected("Convert to method reference", expected, JavaCodeActionKind.QUICK_ASSIST); + assertCodeActions(codeActions, e1); + } } \ No newline at end of file diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/VariableQuickFixTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/VariableQuickFixTest.java index 74aa11fda1..6d89001356 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/VariableQuickFixTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/VariableQuickFixTest.java @@ -96,4 +96,34 @@ public void testJoinVariableExpectDeclarationAndAssignment() throws Exception { Expected e1 = new Expected("Join variable declaration", expected, JavaCodeActionKind.QUICK_ASSIST); assertCodeActions(codeActions, e1); } + + @Test + public void testInvertEqualsExpectVariablesSwapped() throws Exception { + setOnly(JavaCodeActionKind.QUICK_ASSIST); + IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null); + String contents = """ + package test1; + public class E { + public void foo() { + String name1 = "John"; + String name2 = "Doe"; + if (name1.equals(name2)) { + } + } + }"""; + ICompilationUnit cu = pack1.createCompilationUnit("E.java", contents, false, null); + String expected = """ + package test1; + public class E { + public void foo() { + String name1 = "John"; + String name2 = "Doe"; + if (name2.equals(name1)) { + } + } + }"""; + List> codeActions = evaluateCodeActions(cu, CodeActionUtil.getRange(cu, "name1.equals(name2)")); + Expected e1 = new Expected("Invert equals", expected, JavaCodeActionKind.QUICK_ASSIST); + assertCodeActions(codeActions, e1); + } } \ No newline at end of file