Skip to content

Extract lambda body to method #2044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ private CorrectionMessages() {
public static String CorrectPackageDeclarationProposal_remove_description;
public static String CorrectPackageDeclarationProposal_add_description;
public static String CorrectPackageDeclarationProposal_change_description;
public static String QuickAssistProcessor_extractmethod_from_lambda_description;

public static String ChangeCorrectionProposal_error_title;
public static String ChangeCorrectionProposal_error_message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ QuickAssistProcessor_exceptiontothrows_description=Replace exception with throws
QuickAssistProcessor_extract_to_local_all_description=Extract to local variable (replace all occurrences)
QuickAssistProcessor_extract_to_local_description=Extract to local variable
QuickAssistProcessor_extractmethod_description=Extract to method
QuickAssistProcessor_extractmethod_from_lambda_description=Extract lambda body to method
QuickAssistProcessor_extract_to_constant_description=Extract to constant
QuickAssistProcessor_extract_to_field_description=Extract to field
QuickAssistProcessor_joindeclaration_description=Join variable declaration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ public interface IProposalRelevance {
public static final int REMOVE_BLOCK_FIX= 2;
public static final int CONVERT_TO_ANONYMOUS_CLASS_CREATION= 2;
public static final int CONVERT_TO_SWITCH_EXPRESSION = 2;
public static final int EXTRACT_LAMBDA_BODY_TO_METHOD = 3;

public static final int JOIN_VARIABLE_DECLARATION= 1;
public static final int INVERT_EQUALS= 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.List;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IMethod;
Expand Down Expand Up @@ -118,13 +119,15 @@
import org.eclipse.jdt.internal.ui.text.correction.QuickAssistProcessorUtil;
import org.eclipse.jdt.ls.core.internal.JavaCodeActionKind;
import org.eclipse.jdt.ls.core.internal.Messages;
import org.eclipse.jdt.ls.core.internal.corext.refactoring.code.ExtractMethodRefactoring;
import org.eclipse.jdt.ls.core.internal.corrections.CorrectionMessages;
import org.eclipse.jdt.ls.core.internal.corrections.IInvocationContext;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.ASTRewriteCorrectionProposal;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.AssignToVariableAssistProposal;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.ChangeCorrectionProposal;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.IProposalRelevance;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.LinkedCorrectionProposal;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.RefactoringCorrectionProposal;
import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager;
import org.eclipse.jface.text.link.LinkedPositionGroup;
import org.eclipse.lsp4j.CodeActionKind;
Expand Down Expand Up @@ -172,7 +175,7 @@ public List<ChangeCorrectionProposal> getAssists(CodeActionParams params, IInvoc

// boolean noErrorsAtLocation = noErrorsAtLocation(locations);
// if (noErrorsAtLocation) {
// boolean problemsAtLocation = locations.length != 0;
boolean problemsAtLocation = locations.length != 0;
// getCatchClauseToThrowsProposals(context, coveringNode, resultingCollections);
// getPickoutTypeFromMulticatchProposals(context, coveringNode, coveredNodes, resultingCollections);
// getConvertToMultiCatchProposals(context, coveringNode, resultingCollections);
Expand All @@ -190,6 +193,7 @@ public List<ChangeCorrectionProposal> getAssists(CodeActionParams params, IInvoc
// getChangeLambdaBodyToBlockProposal(context, coveringNode, resultingCollections);
// getChangeLambdaBodyToExpressionProposal(context, coveringNode, resultingCollections);
// getAddInferredLambdaParameterTypes(context, coveringNode, resultingCollections);
getExtractMethodFromLambdaProposal(context, coveringNode, problemsAtLocation, resultingCollections);
getConvertMethodReferenceToLambdaProposal(context, coveringNode, resultingCollections);
getConvertLambdaToMethodReferenceProposal(context, coveringNode, resultingCollections);
// getFixParenthesesInLambdaExpression(context, coveringNode, resultingCollections);
Expand All @@ -209,6 +213,37 @@ public List<ChangeCorrectionProposal> getAssists(CodeActionParams params, IInvoc
return Collections.emptyList();
}

private static boolean getExtractMethodFromLambdaProposal(IInvocationContext context, ASTNode coveringNode, boolean problemsAtLocation, Collection<ChangeCorrectionProposal> proposals) throws CoreException {
if (coveringNode instanceof Block && coveringNode.getLocationInParent() == LambdaExpression.BODY_PROPERTY) {
return false;
}
ASTNode node = ASTNodes.getFirstAncestorOrNull(coveringNode, LambdaExpression.class, BodyDeclaration.class);
if (!(node instanceof LambdaExpression)) {
return false;
}
ASTNode body = ((LambdaExpression) node).getBody();
final ICompilationUnit cu = context.getCompilationUnit();
final ExtractMethodRefactoring extractMethodRefactoring = new ExtractMethodRefactoring(context.getASTRoot(), body.getStartPosition(), body.getLength());
String uniqueMethodName = RefactorProposalUtility.getUniqueMethodName(coveringNode, "extracted"); // $NON-NLS-1$
extractMethodRefactoring.setMethodName(uniqueMethodName);
if (extractMethodRefactoring.checkInitialConditions(new NullProgressMonitor()).isOK()) {
if (proposals == null) {
return true;
}
String label = CorrectionMessages.QuickAssistProcessor_extractmethod_from_lambda_description;
LinkedProposalModelCore linkedProposalModel = new LinkedProposalModelCore();
extractMethodRefactoring.setLinkedProposalModel(linkedProposalModel);

// Image image= JavaPluginImages.get(JavaPluginImages.IMG_MISC_PUBLIC);
int relevance = problemsAtLocation ? IProposalRelevance.EXTRACT_METHOD_ERROR : IProposalRelevance.EXTRACT_LAMBDA_BODY_TO_METHOD;
RefactoringCorrectionProposal proposal = new RefactoringCorrectionProposal(label, JavaCodeActionKind.QUICK_ASSIST, cu, extractMethodRefactoring, relevance/*, image*/);
proposal.setLinkedProposalModel(linkedProposalModel);
proposals.add(proposal);
return true;
}
return false;
}

private static boolean getAssignParamToFieldProposals(IInvocationContext context, ASTNode node, Collection<ChangeCorrectionProposal> resultingCollections) {
node = ASTNodes.getNormalizedNode(node);
ASTNode parent = node.getParent();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ public static CUCorrectionProposal getIntroduceParameterRefactoringProposals(Cod
return null;
}

private static String getUniqueMethodName(ASTNode astNode, String suggestedName) throws JavaModelException {
public static String getUniqueMethodName(ASTNode astNode, String suggestedName) throws JavaModelException {
while (astNode != null && !(astNode instanceof TypeDeclaration || astNode instanceof AnonymousClassDeclaration)) {
astNode = astNode.getParent();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
ActionMessages.GenerateConstructorsAction_ellipsisLabel, ActionMessages.GenerateConstructorsAction_label, "Extract lambda body to method");
IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null);
StringBuilder buf = new StringBuilder();
buf.append("package test1;\n");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,55 @@ public void testExtractMethodLambdaExpression() throws Exception {
assertCodeActions(cu, e1);
}

@Test
public void testExtractLambdaBodyToMethod() throws Exception {
IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null);
setOnly(JavaCodeActionKind.QUICK_ASSIST);
//@formatter:off
String contents = "package test1;\r\n"
+ "interface F1 {\r\n"
+ " int foo1(int a);\r\n"
+ "}\r\n"
+ "public class E {\r\n"
+ " public void foo(int a) {\r\n"
+ " F1 k = (e) -> {\r\n"
+ " int x = e + 3;\r\n"
+ " if (x > 3) {\r\n"
+ " return a;\r\n"
+ " }\r\n"
+ " return x;\r\n"
+ " };\r\n"
+ " k.foo1(4);\r\n"
+ " }\r\n"
+ "}";
//@formatter:on
ICompilationUnit cu = pack1.createCompilationUnit("E.java", contents, false, null);
//@formatter:off
String expected = "package test1;\r\n"
+ "interface F1 {\r\n"
+ " int foo1(int a);\r\n"
+ "}\r\n"
+ "public class E {\r\n"
+ " public void foo(int a) {\r\n"
+ " F1 k = (e) -> extracted(a, e);\r\n"
+ " k.foo1(4);\r\n"
+ " }\r\n"
+ "\r\n"
+ " private int extracted(int a, int e) {\r\n"
+ " int x = e + 3;\r\n"
+ " if (x > 3) {\r\n"
+ " return a;\r\n"
+ " }\r\n"
+ " return x;\r\n"
+ " }\r\n"
+ "}";
//@formatter:on
Range range = new Range(new Position(7, 26), new Position(7, 26));
List<Either<Command, CodeAction>> codeActions = evaluateCodeActions(cu, range);
Expected e1 = new Expected("Extract lambda body to method", expected, JavaCodeActionKind.QUICK_ASSIST);
assertCodeActions(codeActions, e1);
}

@Test
public void testExtractMethodGeneric() throws Exception {
IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null);
Expand Down