diff options
author | Jeff Johnston | 2020-09-15 20:26:54 +0000 |
---|---|---|
committer | Jeff Johnston | 2020-09-29 22:44:51 +0000 |
commit | 64e66d61391c45fd9ebc2921120651a0935f145d (patch) | |
tree | 8b8cad3c9800daafe7c955687081f3beda2253d9 | |
parent | 098aa010a398197676d7e25dd7d203b05d02482c (diff) | |
download | eclipse.jdt.ui-64e66d61391c45fd9ebc2921120651a0935f145d.tar.gz eclipse.jdt.ui-64e66d61391c45fd9ebc2921120651a0935f145d.tar.xz eclipse.jdt.ui-64e66d61391c45fd9ebc2921120651a0935f145d.zip |
Bug 545342 - Convert switch statement to switch expression
Change-Id: Id6e7de6a8921bc166e6c985e69760183f19082c6
21 files changed, 1877 insertions, 25 deletions
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java index 2188eff2b0..415378e23c 100644 --- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java @@ -91,6 +91,8 @@ public class MultiFixMessages extends NLS { public static String ControlStatementsCleanUp_RemoveUnnecessaryBlocks_description; public static String ControlStatementsCleanUp_RemoveUnnecessaryBlocksWithReturnOrThrow_description; + public static String SwitchExpressionsCleanUp_ConvertToSwitchExpressions_description; + public static String UnimplementedCodeCleanUp_AddUnimplementedMethods_description; public static String UnimplementedCodeCleanUp_MakeAbstract_description; diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties index 336e2b2462..e32967f27e 100644 --- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties @@ -115,4 +115,5 @@ RedundantSemicolonsCleanup_description= Remove redundant semicolons UnnecessaryArrayCreationCleanup_description=Remove unnecessary array creation for varargs UselessReturnCleanUp_description=Remove useless return ObjectsEqualsCleanup_description=Use Objects.equals() in the equals method implementation -CheckSignOfBitwiseOperation_description=Use != 0 instead of > 0 when comparing the result of a bitwise expression
\ No newline at end of file +CheckSignOfBitwiseOperation_description=Use != 0 instead of > 0 when comparing the result of a bitwise expression +SwitchExpressionsCleanUp_ConvertToSwitchExpressions_description=Convert to switch expression where possible diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/SwitchExpressionsCleanUpCore.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/SwitchExpressionsCleanUpCore.java new file mode 100644 index 0000000000..c51bdf2f32 --- /dev/null +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/SwitchExpressionsCleanUpCore.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2020 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Red Hat Inc. - created by modifying LambdaExpresionsCleanUpCore + *******************************************************************************/ +package org.eclipse.jdt.internal.ui.fix; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.manipulation.CleanUpContextCore; +import org.eclipse.jdt.core.manipulation.CleanUpRequirementsCore; +import org.eclipse.jdt.core.manipulation.ICleanUpFixCore; + +import org.eclipse.jdt.internal.corext.fix.CleanUpConstants; +import org.eclipse.jdt.internal.corext.fix.SwitchExpressionsFixCore; + +public class SwitchExpressionsCleanUpCore extends AbstractCleanUpCore { + + public SwitchExpressionsCleanUpCore(Map<String, String> options) { + super(options); + } + + public SwitchExpressionsCleanUpCore() { + super(); + } + + @Override + public CleanUpRequirementsCore getRequirementsCore() { + return new CleanUpRequirementsCore(requireAST(), false, false, null); + } + + public boolean requireAST() { + return isEnabled(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS); + } + + @Override + public ICleanUpFixCore createFixCore(CleanUpContextCore context) throws CoreException { + CompilationUnit compilationUnit= context.getAST(); + if (compilationUnit == null) + return null; + + boolean convertToSwitchExpressions= isEnabled(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS); + if (!convertToSwitchExpressions) + return null; + + return SwitchExpressionsFixCore.createCleanUp(compilationUnit); + } + + @Override + public String[] getStepDescriptions() { + List<String> result= new ArrayList<>(); + if (isEnabled(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS)) + result.add(MultiFixMessages.SwitchExpressionsCleanUp_ConvertToSwitchExpressions_description); + + return result.toArray(new String[result.size()]); + } + + @Override + public String getPreview() { + StringBuilder buf= new StringBuilder(); + + boolean convert= isEnabled(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS); + + if (convert) { + buf.append("int i = switch(j) {\n"); //$NON-NLS-1$ + buf.append(" case 1 -> 3;\n"); //$NON-NLS-1$ + buf.append(" case 2 -> 4;\n"); //$NON-NLS-1$ + buf.append(" default -> 0;\n"); //$NON-NLS-1$ + buf.append("};\n"); //$NON-NLS-1$ + buf.append("\n"); //$NON-NLS-1$ + } else { + buf.append("int i;\n"); //$NON-NLS-1$ + buf.append("switch(j) {\n"); //$NON-NLS-1$ + buf.append(" case 1:\n"); //$NON-NLS-1$ + buf.append(" i = 3;\n"); //$NON-NLS-1$ + buf.append(" break;\n"); //$NON-NLS-1$ + buf.append(" case 2:\n"); //$NON-NLS-1$ + buf.append(" i = 4;\n"); //$NON-NLS-1$ + buf.append(" break;\n"); //$NON-NLS-1$ + buf.append(" default:\n"); //$NON-NLS-1$ + buf.append(" i = 0;\n"); //$NON-NLS-1$ + buf.append(" break;\n"); //$NON-NLS-1$ + buf.append("}\n"); //$NON-NLS-1$ + buf.append("\n"); //$NON-NLS-1$ + } + return buf.toString(); + } + +} diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java index 6a6fcaf42e..82e8a468fa 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java @@ -73,6 +73,7 @@ import org.eclipse.jdt.core.dom.CastExpression; import org.eclipse.jdt.core.dom.CharacterLiteral; import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; import org.eclipse.jdt.core.dom.ClassInstanceCreation; +import org.eclipse.jdt.core.dom.Comment; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.ConditionalExpression; import org.eclipse.jdt.core.dom.ConstructorInvocation; @@ -3269,4 +3270,45 @@ public class ASTNodes { return type == null ? false : type.isVar(); } + + /** + * Return a list of leading comments for a specified node + * + * @param node - ASTNode in a CompilationUnit + * @return list of Comment nodes + */ + public static List<Comment> getLeadingComments(ASTNode node) { + List<Comment> comments= new ArrayList<>(); + CompilationUnit cu= (CompilationUnit)node.getRoot(); + List<Comment> commentList= cu.getCommentList(); + for (Comment comment : commentList) { + if (comment.getStartPosition() >= cu.getExtendedStartPosition(node) + && comment.getStartPosition() + comment.getLength() < node.getStartPosition()) { + comments.add(comment); + } + } + return comments; + } + + /** + * Return a list of trailing comments for a specified node + * + * @param node - ASTNode in a CompilationUnit + * @return list of Comment nodes + */ + public static List<Comment> getTrailingComments(ASTNode node) { + List<Comment> comments= new ArrayList<>(); + CompilationUnit cu= (CompilationUnit)node.getRoot(); + List<Comment> commentList= cu.getCommentList(); + int extendedStart= cu.getExtendedStartPosition(node); + int extendedLength= cu.getExtendedLength(node); + for (Comment comment : commentList) { + if (comment.getStartPosition() > node.getStartPosition() + && comment.getStartPosition() < extendedStart + extendedLength) { + comments.add(comment); + } + } + return comments; + } + } diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java index c8fde3d92d..c8bb7ca7a3 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java @@ -529,6 +529,25 @@ public class CleanUpConstants { public static String CONTROL_STATMENTS_CONVERT_FOR_LOOP_ONLY_IF_LOOP_VAR_USED= "cleanup.convert_to_enhanced_for_loop_if_loop_var_used"; //$NON-NLS-1$ /** + * Convert switch statements to switch expressions.IF_LOOP_VAR_USED}<br> + * <p> + * Example: + * + * <pre> + * int i; switch(j) {case 1: i = 2; break; default: i = 3;} -> int i = switch(j) {case 1 -> 2; default -> 3;}; + * </pre> + * + * Possible values: {TRUE, FALSE}<br> + * + * <br> + * + * @see CleanUpOptionsCore#TRUE + * @see CleanUpOptionsCore#FALSE + * @since 4.18 + */ + public static final String CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS= "cleanup.convert_to_switch_expressions"; //$NON-NLS-1$ + + /** * Controls the usage of parentheses in expressions. For detailed settings use<br> * {@link #EXPRESSIONS_USE_PARENTHESES_ALWAYS}<br> {@link #EXPRESSIONS_USE_PARENTHESES_NEVER}<br> * <br> diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java index 885a271893..727f323d48 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java @@ -149,6 +149,7 @@ public final class FixMessages extends NLS { public static String LambdaExpressionsFix_convert_to_anonymous_class_creation; public static String LambdaExpressionsFix_convert_to_lambda_expression; public static String LambdaExpressionsFix_convert_to_lambda_expression_removes_annotations; + public static String SwitchExpressionsFix_convert_to_switch_expression; public static String TypeParametersFix_insert_inferred_type_arguments_description; public static String TypeParametersFix_insert_inferred_type_arguments_name; diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties index 1c501d58d6..850817ac67 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties @@ -136,6 +136,7 @@ PatternFix_convert_string_to_pattern_object=Convert string to pattern object LambdaExpressionsFix_convert_to_anonymous_class_creation=Convert to anonymous class creation LambdaExpressionsFix_convert_to_lambda_expression=Convert to lambda expression LambdaExpressionsFix_convert_to_lambda_expression_removes_annotations=Convert to lambda expression (removes annotations on method) +SwitchExpressionsFix_convert_to_switch_expression=Convert to switch expression TypeParametersFix_insert_inferred_type_arguments_description=Insert inferred type arguments TypeParametersFix_insert_inferred_type_arguments_name=Insert inferred type arguments TypeParametersFix_remove_redundant_type_arguments_description=Remove redundant type arguments diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchExpressionsFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchExpressionsFixCore.java new file mode 100644 index 0000000000..77f8cd01a9 --- /dev/null +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchExpressionsFixCore.java @@ -0,0 +1,445 @@ +/******************************************************************************* + * Copyright (c) 2020 Red Hat Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.corext.fix; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.text.edits.TextEditGroup; + +import org.eclipse.jdt.core.IBuffer; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTMatcher; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.Assignment; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.BreakStatement; +import org.eclipse.jdt.core.dom.Comment; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ContinueStatement; +import org.eclipse.jdt.core.dom.DoStatement; +import org.eclipse.jdt.core.dom.EnhancedForStatement; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.ForStatement; +import org.eclipse.jdt.core.dom.IBinding; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.IVariableBinding; +import org.eclipse.jdt.core.dom.IfStatement; +import org.eclipse.jdt.core.dom.Name; +import org.eclipse.jdt.core.dom.ReturnStatement; +import org.eclipse.jdt.core.dom.Statement; +import org.eclipse.jdt.core.dom.SwitchCase; +import org.eclipse.jdt.core.dom.SwitchExpression; +import org.eclipse.jdt.core.dom.SwitchStatement; +import org.eclipse.jdt.core.dom.ThrowStatement; +import org.eclipse.jdt.core.dom.TryStatement; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; +import org.eclipse.jdt.core.dom.VariableDeclarationStatement; +import org.eclipse.jdt.core.dom.WhileStatement; +import org.eclipse.jdt.core.dom.YieldStatement; +import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; +import org.eclipse.jdt.core.dom.rewrite.ListRewrite; +import org.eclipse.jdt.core.manipulation.ICleanUpFixCore; + +import org.eclipse.jdt.internal.corext.dom.ASTNodes; +import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; +import org.eclipse.jdt.internal.corext.util.JavaModelUtil; + +public class SwitchExpressionsFixCore extends CompilationUnitRewriteOperationsFixCore { + + public static final class SwitchStatementsFinder extends ASTVisitor { + + private List<SwitchExpressionsFixOperation> fResult; + + public SwitchStatementsFinder(List<SwitchExpressionsFixOperation> ops) { + fResult= ops; + } + + @Override + public boolean visit(SwitchStatement node) { + SwitchExpressionsFixOperation operation= getOperation(node); + if (operation != null) { + fResult.add(operation); + } + return true; + } + + private boolean isInvalidStatement(Statement statement) { + return statement instanceof ContinueStatement + || statement instanceof ForStatement + || statement instanceof ReturnStatement + || statement instanceof IfStatement + || statement instanceof DoStatement + || statement instanceof EnhancedForStatement + || statement instanceof SwitchStatement + || statement instanceof YieldStatement + || statement instanceof TryStatement + || statement instanceof WhileStatement; + } + private SwitchExpressionsFixOperation getOperation(SwitchStatement switchStatement) { + final List<SwitchCase> throwList= new ArrayList<>(); + boolean defaultFound= false; + List<Statement> currentBlock= null; + SwitchCase currentCase= null; + Map<SwitchCase, List<Statement>> caseMap= new LinkedHashMap<>(); + for (Iterator<Statement> iter= switchStatement.statements().iterator(); iter.hasNext();) { + Statement statement= iter.next(); + if (statement instanceof SwitchCase) { + SwitchCase switchCase= (SwitchCase)statement; + if (switchCase.isDefault()) { + defaultFound= true; + } + if (currentBlock != null && !currentBlock.isEmpty()) { + return null; + } + if (currentCase != null) { + caseMap.put(currentCase, currentBlock); + } + currentBlock= new ArrayList<>(); + currentCase= switchCase; + } else if (isInvalidStatement(statement)) { + return null; + } else if (statement instanceof BreakStatement) { + if (currentBlock != null && currentBlock.isEmpty()) { + return null; + } + if (currentCase != null) { + caseMap.put(currentCase, currentBlock); + } + currentBlock= null; + currentCase= null; + } else if (statement instanceof ThrowStatement) { + throwList.add(currentCase); + if (currentBlock == null) { + return null; + } + currentBlock.add(statement); + caseMap.put(currentCase, currentBlock); + currentBlock= null; + currentCase= null; + } else { + if (currentBlock == null) { + return null; + } + if (statement instanceof Block) { + Block block= (Block)statement; + // allow one level of block with no invalid statements inside + for (Iterator<Statement> blockIter= block.statements().iterator(); blockIter.hasNext();) { + Statement blockStatement= blockIter.next(); + if (isInvalidStatement(blockStatement) || blockStatement instanceof Block) { + return null; + } + if (blockStatement instanceof ThrowStatement) { + throwList.add(currentCase); + } + } + } + currentBlock.add(statement); + } + } + + String commonAssignmentName= null; + IBinding assignmentBinding= null; + for (Map.Entry<SwitchCase, List<Statement>> entry : caseMap.entrySet()) { + SwitchCase entryCase= entry.getKey(); + List<Statement> entryStatements= entry.getValue(); + if (throwList.contains(entryCase) || entryStatements.size() == 0) { + continue; + } + Statement lastStatement= entryStatements.get(entryStatements.size() - 1); + if (lastStatement instanceof Block) { + @SuppressWarnings("rawtypes") + List blockStatements= ((Block)lastStatement).statements(); + if (blockStatements.isEmpty()) { + continue; + } + lastStatement= (Statement)(blockStatements.get(blockStatements.size() - 1)); + } + // case must end in an assignment + if (!(lastStatement instanceof ExpressionStatement) || !(((ExpressionStatement)lastStatement).getExpression() instanceof Assignment)) { + return null; + } + Assignment assignment= (Assignment)((ExpressionStatement) lastStatement).getExpression(); + // must be simple assign operator + if (assignment.getOperator() != Assignment.Operator.ASSIGN) { + return null; + } + if (commonAssignmentName == null) { + Expression exp= assignment.getLeftHandSide(); + if (exp instanceof Name) { + commonAssignmentName= ((Name)exp).getFullyQualifiedName(); + assignmentBinding= ((Name) exp).resolveBinding(); + } + } else { + Expression exp= assignment.getLeftHandSide(); + if (exp instanceof Name) { + Name name= (Name)exp; + if (!name.getFullyQualifiedName().equals(commonAssignmentName)) { + return null; + } + } + } + } + if (assignmentBinding == null) { + return null; + } + // ensure either we have default case or else expression is enum and all constants specified + ITypeBinding binding= switchStatement.getExpression().resolveTypeBinding(); + if (binding != null && binding.isEnum()) { + IVariableBinding[] fields= binding.getDeclaredFields(); + int enumCount= 0; + for (IVariableBinding field : fields) { + if (field.isEnumConstant()) { + ++enumCount; + } + } + if (enumCount != caseMap.size() && !defaultFound) { + return null; + } + } else if (!defaultFound) { + return null; + } + return new SwitchExpressionsFixOperation(switchStatement, caseMap, commonAssignmentName, assignmentBinding); + } + } + + public static class SwitchExpressionsFixOperation extends CompilationUnitRewriteOperation { + + private final SwitchStatement switchStatement; + private final Map<SwitchCase, List<Statement>> caseMap; + private final String varName; + private final IBinding assignmentBinding; + + public SwitchExpressionsFixOperation(SwitchStatement switchStatement, Map<SwitchCase, List<Statement>> caseMap, + String varName, IBinding assignmentBinding) { + this.switchStatement= switchStatement; + this.caseMap= caseMap; + this.varName= varName; + this.assignmentBinding= assignmentBinding; + } + + @SuppressWarnings("rawtypes") + @Override + public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModelCore linkedModel) throws CoreException { + + final ASTRewrite rewrite= cuRewrite.getASTRewrite(); + final AST ast= rewrite.getAST(); + + TextEditGroup group= createTextEditGroup(FixMessages.SwitchExpressionsFix_convert_to_switch_expression, cuRewrite); + SwitchExpression newSwitchExpression= ast.newSwitchExpression(); + Expression newSwitchExpressionExpression= (Expression)rewrite.createCopyTarget(switchStatement.getExpression()); + newSwitchExpression.setExpression(newSwitchExpressionExpression); + SwitchCase lastSwitchCase= null; + // build switch expression + for (Map.Entry<SwitchCase, List<Statement>> entry : caseMap.entrySet()) { + SwitchCase oldSwitchCase= entry.getKey(); + List<Statement> oldStatements= entry.getValue(); + if (oldStatements.isEmpty()) { + // fall-through, want all fall-through labels in single case + if (lastSwitchCase == null) { + lastSwitchCase= ast.newSwitchCase(); + lastSwitchCase.setSwitchLabeledRule(true); + newSwitchExpression.statements().add(lastSwitchCase); + } + for (Object obj : oldSwitchCase.expressions()) { + Expression oldExpression= (Expression)obj; + Expression newExpression= (Expression)rewrite.createCopyTarget(oldExpression); + lastSwitchCase.expressions().add(newExpression); + } + continue; + } + SwitchCase switchCase= null; + if (lastSwitchCase == null) { + SwitchCase newSwitchCase= ast.newSwitchCase(); + newSwitchExpression.statements().add(newSwitchCase); + newSwitchCase.setSwitchLabeledRule(true); + switchCase= newSwitchCase; + } else { + switchCase= lastSwitchCase; + } + lastSwitchCase= null; + for (Object obj : oldSwitchCase.expressions()) { + Expression oldExpression= (Expression)obj; + Expression newExpression= (Expression)rewrite.createCopyTarget(oldExpression); + switchCase.expressions().add(newExpression); + } + if (oldStatements.size() == 1 && oldStatements.get(0) instanceof Block) { + oldStatements= ((Block)oldStatements.get(0)).statements(); + } + if (oldStatements.size() == 1) { + Statement oldStatement= oldStatements.get(0); + Statement newStatement= null; + if (oldStatement instanceof ThrowStatement) { + ThrowStatement throwStatement= (ThrowStatement)oldStatement; + newStatement= (Statement)rewrite.createCopyTarget(throwStatement); + } else { + ExpressionStatement oldExpStatement= (ExpressionStatement)oldStatement; + Assignment oldAssignment= (Assignment)oldExpStatement.getExpression(); + Expression rhs= oldAssignment.getRightHandSide(); + // Ugly hack to tack on trailing comments + IBuffer buffer= cuRewrite.getCu().getBuffer(); + StringBuffer b= new StringBuffer(); + b.append(buffer.getText(rhs.getStartPosition(), rhs.getLength()) + ";"); //$NON-NLS-1$ + List<Comment> trailingComments= ASTNodes.getTrailingComments(oldExpStatement); + for (Comment comment : trailingComments) { + b.append(" " + buffer.getText(comment.getStartPosition(), comment.getLength())); //$NON-NLS-1$ + } + newStatement= (Statement) rewrite.createStringPlaceholder(b.toString(), ASTNode.EXPRESSION_STATEMENT); + } + newSwitchExpression.statements().add(newStatement); + } else { + Block newBlock= ast.newBlock(); + int statementsLen= oldStatements.size(); + for (int i= 0; i < statementsLen - 1; ++i) { + Statement oldSwitchCaseStatement= oldStatements.get(i); + newBlock.statements().add(rewrite.createCopyTarget(oldSwitchCaseStatement)); + } + ExpressionStatement oldExpStatement= (ExpressionStatement)oldStatements.get(statementsLen - 1); + Assignment oldAssignment= (Assignment)oldExpStatement.getExpression(); + Expression rhs= oldAssignment.getRightHandSide(); + Expression newYieldExpression= null; + YieldStatement newYield= null; + IBuffer buffer= cuRewrite.getCu().getBuffer(); + StringBuffer b= new StringBuffer(); + List<Comment> leadingComments= ASTNodes.getLeadingComments(oldExpStatement); + for (Comment comment : leadingComments) { + b.append(buffer.getText(comment.getStartPosition(), comment.getLength()) + "\n"); //$NON-NLS-1$ + } + b.append("yield "); //$NON-NLS-1$ + List<Comment> trailingComments= ASTNodes.getTrailingComments(oldExpStatement); + b.append(buffer.getText(rhs.getStartPosition(), rhs.getLength()) + ";"); //$NON-NLS-1$ + for (Comment comment : trailingComments) { + b.append(" " + buffer.getText(comment.getStartPosition(), comment.getLength())); //$NON-NLS-1$ + } + + newYield = (YieldStatement)rewrite.createStringPlaceholder(b.toString(), ASTNode.YIELD_STATEMENT); + newYieldExpression= (Expression) rewrite.createStringPlaceholder(b.toString(), rhs.getNodeType()); + newYield.setExpression(newYieldExpression); + newBlock.statements().add(newYield); + newSwitchExpression.statements().add(newBlock); + } + } + + // see if we can make new switch expression the initializer of assignment variable + if (assignmentBinding instanceof IVariableBinding) { + VariableDeclarationStatement varDeclarationStatement= null; + int varIndex= -2; + IVariableBinding binding= (IVariableBinding)assignmentBinding; + if (!binding.isField() && !binding.isParameter() && !binding.isSynthetic()) { + ASTNode parent= switchStatement.getParent(); + if (parent instanceof Block) { + Block block= (Block)parent; + List statements= block.statements(); + ListRewrite listRewrite= rewrite.getListRewrite(block, Block.STATEMENTS_PROPERTY); + for (int i= 0; i < statements.size(); ++i) { + Statement statement= (Statement)statements.get(i); + if (statement instanceof VariableDeclarationStatement) { + VariableDeclarationStatement decl= (VariableDeclarationStatement)statement; + List fragments= decl.fragments(); + if (fragments.size() == 1) { // must be single var declaration + VariableDeclarationFragment fragment= (VariableDeclarationFragment)fragments.get(0); + if (fragment.getInitializer() == null) { // must not already be initialized + IVariableBinding fragBinding= fragment.resolveBinding(); + if (fragBinding != null && fragBinding.isEqualTo(binding)) { + varDeclarationStatement= decl; + varIndex= i; + } + } + } + } else if (statement instanceof SwitchStatement) { + if (statement.subtreeMatch(new ASTMatcher(), switchStatement)) { + // if previous statement declares assignment variable, we can set initializer + if (varIndex == i - 1) { + VariableDeclarationFragment newVarFragment= ast.newVariableDeclarationFragment(); + newVarFragment.setName(ast.newSimpleName(varName)); + newVarFragment.setInitializer(newSwitchExpression); + VariableDeclarationStatement newVar= ast.newVariableDeclarationStatement(newVarFragment); + replaceWithLeadingComments(cuRewrite, listRewrite, varDeclarationStatement, group, newVar); + listRewrite.remove(switchStatement, group); + return; + } + break; + } + } + } + } + } + } + // otherwise just assign new switch expression to varName + Assignment newAssignment= ast.newAssignment(); + ExpressionStatement newExpressionStatement= ast.newExpressionStatement(newAssignment); + newAssignment.setLeftHandSide(ast.newName(varName)); + newAssignment.setRightHandSide(newSwitchExpression); + + ASTNode parent= switchStatement.getParent(); + if (parent instanceof Block) { + ListRewrite listRewrite= rewrite.getListRewrite(parent, Block.STATEMENTS_PROPERTY); + replaceWithLeadingComments(cuRewrite, listRewrite, switchStatement, group, newExpressionStatement); + } else { + rewrite.replace(switchStatement, newExpressionStatement, group); + } + } + + private void replaceWithLeadingComments(CompilationUnitRewrite cuRewrite, ListRewrite listRewrite, + ASTNode oldNode, TextEditGroup group, ASTNode newNode) throws JavaModelException { + ASTRewrite rewrite= cuRewrite.getASTRewrite(); + List<Comment> comments= ASTNodes.getLeadingComments(oldNode); + if (!comments.isEmpty()) { + Comment firstComment= comments.get(0); + String commentString= cuRewrite.getCu().getBuffer().getText(firstComment.getStartPosition(), firstComment.getLength()); + ASTNode lastComment= rewrite.createStringPlaceholder(commentString, firstComment.isBlockComment() ? ASTNode.BLOCK_COMMENT : ASTNode.LINE_COMMENT); + listRewrite.replace(oldNode, lastComment, group); + for (int j= 1; j < comments.size(); ++j) { + Comment comment= comments.get(j); + commentString= cuRewrite.getCu().getBuffer().getText(comment.getStartPosition(), comment.getLength()); + ASTNode newComment= rewrite.createStringPlaceholder(commentString, comment.isBlockComment() ? ASTNode.BLOCK_COMMENT : ASTNode.LINE_COMMENT); + listRewrite.insertAfter(newComment, lastComment, group); + lastComment= newComment; + } + listRewrite.insertAfter(newNode, lastComment, group); + } else { + listRewrite.replace(oldNode, newNode, group); + } + } + + } + + + public static ICleanUpFixCore createCleanUp(CompilationUnit compilationUnit) { + if (!JavaModelUtil.is14OrHigher(compilationUnit.getJavaElement().getJavaProject())) + return null; + + List<SwitchExpressionsFixOperation> operations= new ArrayList<>(); + SwitchStatementsFinder finder= new SwitchStatementsFinder(operations); + compilationUnit.accept(finder); + if (operations.isEmpty()) + return null; + + CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] ops= operations.toArray(new CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[operations.size()]); + return new SwitchExpressionsFixCore(FixMessages.SwitchExpressionsFix_convert_to_switch_expression, compilationUnit, ops); + } + + protected SwitchExpressionsFixCore(String name, CompilationUnit compilationUnit, CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] fixRewriteOperations) { + super(name, compilationUnit, fixRewriteOperations); + } + +} diff --git a/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java b/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java index c10d616c1b..d354ce4cd2 100644 --- a/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java +++ b/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java @@ -264,7 +264,7 @@ public class JavaProjectHelper { } /** - * Sets the compiler options to 13 for the given project. + * Sets the compiler options to 14 for the given project. * * @param project the java project * @param enable_preview_feature sets enable-preview compliance project option based on the @@ -282,7 +282,7 @@ public class JavaProjectHelper { } /** - * Sets the compiler options to 13 for the given project. + * Sets the compiler options to 15 for the given project. * * @param project the java project * @param enable_preview_feature sets enable-preview compliance project option based on the diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest14.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest14.java new file mode 100644 index 0000000000..2dae527f47 --- /dev/null +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest14.java @@ -0,0 +1,575 @@ +/******************************************************************************* + * Copyright (c) 2020 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Red Hat Inc. - modified to test Java 14 quickfixes + *******************************************************************************/ +package org.eclipse.jdt.ui.tests.quickfix; + +import java.util.ArrayList; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import org.eclipse.jdt.testplugin.JavaProjectHelper; + +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IPackageFragmentRoot; + +import org.eclipse.jdt.internal.corext.fix.FixMessages; + +import org.eclipse.jdt.ui.tests.core.rules.Java14ProjectTestSetup; +import org.eclipse.jdt.ui.tests.core.rules.ProjectTestSetup; +import org.eclipse.jdt.ui.text.java.IInvocationContext; +import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal; +import org.eclipse.jdt.ui.text.java.correction.CUCorrectionProposal; + +public class AssistQuickFixTest14 extends QuickFixTest { + + @Rule + public ProjectTestSetup projectSetup = new Java14ProjectTestSetup(true); + + private IJavaProject fJProject1; + + private IPackageFragmentRoot fSourceFolder; + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + if (fJProject1 != null) { + JavaProjectHelper.delete(fJProject1); + } + + } + + @Test + public void testConvertToSwitchExpression1() throws Exception { + fJProject1= JavaProjectHelper.createJavaProject("TestProject1", "bin"); + fJProject1.setRawClasspath(projectSetup.getDefaultClasspath(), null); + JavaProjectHelper.set14CompilerOptions(fJProject1, false); + fSourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src"); + + StringBuffer buf= new StringBuffer(); + buf.append("module test {\n"); + buf.append("}\n"); + IPackageFragment def= fSourceFolder.createPackageFragment("", false, null); + def.createCompilationUnit("module-info.java", buf.toString(), false, null); + + IPackageFragment pack= fSourceFolder.createPackageFragment("test", false, null); + buf= new StringBuffer(); + buf.append("package test;\n"); + buf.append("public class Cls {\n"); + buf.append(" public int foo(Day day) {\n"); + buf.append(" // return variable\n"); + buf.append(" int i;\n"); + buf.append(" switch (day) {\n"); + buf.append(" case SATURDAY:\n"); + buf.append(" case SUNDAY: i = 5; break;\n"); + buf.append(" case MONDAY:\n"); + buf.append(" case TUESDAY, WEDNESDAY: i = 7; break;\n"); + buf.append(" case THURSDAY:\n"); + buf.append(" case FRIDAY: i = 14; break;\n"); + buf.append(" default :\n"); + buf.append(" i = 22;\n"); + buf.append(" break;\n"); + buf.append(" }\n"); + buf.append(" return i;\n"); + buf.append(" }\n"); + buf.append("}\n"); + buf.append("\n"); + buf.append("enum Day {\n"); + buf.append(" MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;\n"); + buf.append("}\n"); + ICompilationUnit cu= pack.createCompilationUnit("Cls.java", buf.toString(), false, null); + + int index= buf.indexOf("switch"); + IInvocationContext ctx= getCorrectionContext(cu, index, 0); + assertNoErrors(ctx); + ArrayList<IJavaCompletionProposal> proposals= collectAssists(ctx, false); + + CUCorrectionProposal proposal= (CUCorrectionProposal) proposals.get(0); + String preview= getPreviewContent(proposal); + + buf= new StringBuffer(); + buf= new StringBuffer(); + buf.append("package test;\n"); + buf.append("public class Cls {\n"); + buf.append(" public int foo(Day day) {\n"); + buf.append(" // return variable\n"); + buf.append(" int i = switch (day) {\n"); + buf.append(" case SATURDAY, SUNDAY -> 5;\n"); + buf.append(" case MONDAY, TUESDAY, WEDNESDAY -> 7;\n"); + buf.append(" case THURSDAY, FRIDAY -> 14;\n"); + buf.append(" default -> 22;\n"); + buf.append(" };\n"); + buf.append(" return i;\n"); + buf.append(" }\n"); + buf.append("}\n"); + buf.append("\n"); + buf.append("enum Day {\n"); + buf.append(" MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;\n"); + buf.append("}\n"); + String expected= buf.toString(); + + assertEqualStringsIgnoreOrder(new String[] { preview }, new String[] { expected }); + } + + @Test + public void testConvertToSwitchExpression2() throws Exception { + fJProject1= JavaProjectHelper.createJavaProject("TestProject1", "bin"); + fJProject1.setRawClasspath(projectSetup.getDefaultClasspath(), null); + JavaProjectHelper.set14CompilerOptions(fJProject1, false); + fSourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src"); + + StringBuffer buf= new StringBuffer(); + buf.append("module test {\n"); + buf.append("}\n"); + IPackageFragment def= fSourceFolder.createPackageFragment("", false, null); + def.createCompilationUnit("module-info.java", buf.toString(), false, null); + + IPackageFragment pack= fSourceFolder.createPackageFragment("test", false, null); + buf= new StringBuffer(); + buf.append("package test;\n"); + buf.append("public class Cls {\n"); + buf.append(" public int foo(Day day) {\n"); + buf.append(" // return variable\n"); + buf.append(" int i;\n"); + buf.append(" int j = 4;\n"); + buf.append(" // logic comment\n"); + buf.append(" switch (day) {\n"); + buf.append(" case SATURDAY:\n"); + buf.append(" case SUNDAY: i = 5; break;\n"); + buf.append(" case MONDAY:\n"); + buf.append(" case TUESDAY:\n"); + buf.append(" case WEDNESDAY: System.out.println(\"here\"); i = 7; break;\n"); + buf.append(" case THURSDAY:\n"); + buf.append(" case FRIDAY: i = 14; break;\n"); + buf.append(" default: i = 22; break;\n"); + buf.append(" }\n"); + buf.append(" return i;\n"); + buf.append(" }\n"); + buf.append("}\n"); + buf.append("\n"); + buf.append("enum Day {\n"); + buf.append(" MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;\n"); + buf.append("}\n"); + ICompilationUnit cu= pack.createCompilationUnit("Cls.java", buf.toString(), false, null); + + int index= buf.indexOf("switch"); + IInvocationContext ctx= getCorrectionContext(cu, index, 0); + assertNoErrors(ctx); + ArrayList<IJavaCompletionProposal> proposals= collectAssists(ctx, false); + + CUCorrectionProposal proposal= (CUCorrectionProposal) proposals.get(0); + String preview= getPreviewContent(proposal); + + buf= new StringBuffer(); + buf= new StringBuffer(); + buf.append("package test;\n"); + buf.append("public class Cls {\n"); + buf.append(" public int foo(Day day) {\n"); + buf.append(" // return variable\n"); + buf.append(" int i;\n"); + buf.append(" int j = 4;\n"); + buf.append(" // logic comment\n"); + buf.append(" i = switch (day) {\n"); + buf.append(" case SATURDAY, SUNDAY -> 5;\n"); + buf.append(" case MONDAY, TUESDAY, WEDNESDAY -> {\n"); + buf.append(" System.out.println(\"here\");\n"); + buf.append(" yield 7;\n"); + buf.append(" }\n"); + buf.append(" case THURSDAY, FRIDAY -> 14;\n"); + buf.append(" default -> 22;\n"); + buf.append(" };\n"); + buf.append(" return i;\n"); + buf.append(" }\n"); + buf.append("}\n"); + buf.append("\n"); + buf.append("enum Day {\n"); + buf.append(" MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;\n"); + buf.append("}\n"); + String expected= buf.toString(); + + assertEqualStringsIgnoreOrder(new String[] { preview }, new String[] { expected }); + } + + @Test + public void testConvertToSwitchExpression3() throws Exception { + fJProject1= JavaProjectHelper.createJavaProject("TestProject1", "bin"); + fJProject1.setRawClasspath(projectSetup.getDefaultClasspath(), null); + JavaProjectHelper.set14CompilerOptions(fJProject1, false); + fSourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src"); + + StringBuffer buf= new StringBuffer(); + buf.append("module test {\n"); + buf.append("}\n"); + IPackageFragment def= fSourceFolder.createPackageFragment("", false, null); + def.createCompilationUnit("module-info.java", buf.toString(), false, null); + + IPackageFragment pack= fSourceFolder.createPackageFragment("test", false, null); + buf= new StringBuffer(); + buf.append("package test;\n"); + buf.append("public class Cls {\n"); + buf.append(" static int i;\n"); + buf.append(" static {\n"); + buf.append(" // var comment\n"); + buf.append(" int j = 4;\n"); + buf.append(" // logic comment\n"); + buf.append(" switch (j) {\n"); + buf.append(" case 0:\n"); + buf.append(" case 1: i = 5; break;\n"); + buf.append(" case 2:\n"); + buf.append(" case 3:\n"); + buf.append(" case 4:\n"); + buf.append(" System.out.println(\"here\"); // comment 1\n"); + buf.append(" // comment 2\n"); + buf.append(" i = 7; // comment 3\n"); + buf.append(" break;\n"); + buf.append(" case 5:\n"); + buf.append(" case 6: i = 14; break;\n"); + buf.append(" default: i = 22; break;\n"); + buf.append(" }\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu= pack.createCompilationUnit("Cls.java", buf.toString(), false, null); + + int index= buf.indexOf("switch"); + IInvocationContext ctx= getCorrectionContext(cu, index, 0); + assertNoErrors(ctx); + ArrayList<IJavaCompletionProposal> proposals= collectAssists(ctx, false); + + CUCorrectionProposal proposal= (CUCorrectionProposal) proposals.get(0); + String preview= getPreviewContent(proposal); + + buf= new StringBuffer(); + buf= new StringBuffer(); + buf.append("package test;\n"); + buf.append("public class Cls {\n"); + buf.append(" static int i;\n"); + buf.append(" static {\n"); + buf.append(" // var comment\n"); + buf.append(" int j = 4;\n"); + buf.append(" // logic comment\n"); + buf.append(" i = switch (j) {\n"); + buf.append(" case 0, 1 -> 5;\n"); + buf.append(" case 2, 3, 4 -> {\n"); + buf.append(" System.out.println(\"here\"); // comment 1\n"); + buf.append(" // comment 2\n"); + buf.append(" yield 7; // comment 3\n"); + buf.append(" }\n"); + buf.append(" case 5, 6 -> 14;\n"); + buf.append(" default -> 22;\n"); + buf.append(" };\n"); + buf.append(" }\n"); + buf.append("}\n"); + String expected= buf.toString(); + + assertEqualStringsIgnoreOrder(new String[] { preview }, new String[] { expected }); + } + + @Test + public void testConvertToSwitchExpression4() throws Exception { + fJProject1= JavaProjectHelper.createJavaProject("TestProject1", "bin"); + fJProject1.setRawClasspath(projectSetup.getDefaultClasspath(), null); + JavaProjectHelper.set14CompilerOptions(fJProject1, false); + fSourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src"); + + StringBuffer buf= new StringBuffer(); + buf.append("module test {\n"); + buf.append("}\n"); + IPackageFragment def= fSourceFolder.createPackageFragment("", false, null); + def.createCompilationUnit("module-info.java", buf.toString(), false, null); + + IPackageFragment pack= fSourceFolder.createPackageFragment("test", false, null); + buf= new StringBuffer(); + buf.append("package test;\n"); + buf.append("public class Cls {\n"); + buf.append(" public int foo(int j, int k) {\n"); + buf.append(" // var comment\n"); + buf.append(" int i;\n"); + buf.append(" // logic comment\n"); + buf.append(" switch (j) {\n"); + buf.append(" case 0:\n"); + buf.append(" case 1: i = k > 7 ? 5 : 6; break;\n"); + buf.append(" case 2:\n"); + buf.append(" case 3:\n"); + buf.append(" case 4: System.out.println(\"here\"); i = 7; break;\n"); + buf.append(" case 5:\n"); + buf.append(" case 6: i = 14; break;\n"); + buf.append(" default: i = 22; break;\n"); + buf.append(" }\n"); + buf.append(" return i;\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu= pack.createCompilationUnit("Cls.java", buf.toString(), false, null); + + int index= buf.indexOf("switch"); + IInvocationContext ctx= getCorrectionContext(cu, index, 0); + assertNoErrors(ctx); + ArrayList<IJavaCompletionProposal> proposals= collectAssists(ctx, false); + + CUCorrectionProposal proposal= (CUCorrectionProposal) proposals.get(0); + String preview= getPreviewContent(proposal); + + buf= new StringBuffer(); + buf= new StringBuffer(); + buf.append("package test;\n"); + buf.append("public class Cls {\n"); + buf.append(" public int foo(int j, int k) {\n"); + buf.append(" // var comment\n"); + buf.append(" int i = switch (j) {\n"); + buf.append(" case 0, 1 -> k > 7 ? 5 : 6;\n"); + buf.append(" case 2, 3, 4 -> {\n"); + buf.append(" System.out.println(\"here\");\n"); + buf.append(" yield 7;\n"); + buf.append(" }\n"); + buf.append(" case 5, 6 -> 14;\n"); + buf.append(" default -> 22;\n"); + buf.append(" };\n"); + buf.append(" return i;\n"); + buf.append(" }\n"); + buf.append("}\n"); + String expected= buf.toString(); + + assertEqualStringsIgnoreOrder(new String[] { preview }, new String[] { expected }); + } + + @Test + public void testNoConvertToSwitchExpression1() throws Exception { + fJProject1= JavaProjectHelper.createJavaProject("TestProject1", "bin"); + fJProject1.setRawClasspath(projectSetup.getDefaultClasspath(), null); + JavaProjectHelper.set14CompilerOptions(fJProject1, false); + fSourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src"); + + StringBuffer buf= new StringBuffer(); + buf.append("module test {\n"); + buf.append("}\n"); + IPackageFragment def= fSourceFolder.createPackageFragment("", false, null); + def.createCompilationUnit("module-info.java", buf.toString(), false, null); + + IPackageFragment pack= fSourceFolder.createPackageFragment("test", false, null); + buf= new StringBuffer(); + buf.append("package test;\n"); + buf.append("public class Cls {\n"); + buf.append(" static int i;\n"); + buf.append(" static {\n"); + buf.append(" // var comment\n"); + buf.append(" int j = 4;\n"); + buf.append(" // logic comment\n"); + buf.append(" switch (j) {\n"); + buf.append(" case 0: break; // no statements\n"); + buf.append(" case 1: i = 5; break;\n"); + buf.append(" case 2:\n"); + buf.append(" case 3:\n"); + buf.append(" case 4: System.out.println(\"here\"); i = 7; break;\n"); + buf.append(" case 5:\n"); + buf.append(" case 6: i = 14; break;\n"); + buf.append(" default: i = 22; break;\n"); + buf.append(" }\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu= pack.createCompilationUnit("Cls.java", buf.toString(), false, null); + + int index= buf.indexOf("switch"); + IInvocationContext ctx= getCorrectionContext(cu, index, 0); + assertNoErrors(ctx); + ArrayList<IJavaCompletionProposal> proposals= collectAssists(ctx, false); + assertProposalDoesNotExist(proposals, FixMessages.SwitchExpressionsFix_convert_to_switch_expression); + + } + + @Test + public void testNoConvertToSwitchExpression2() throws Exception { + fJProject1= JavaProjectHelper.createJavaProject("TestProject1", "bin"); + fJProject1.setRawClasspath(projectSetup.getDefaultClasspath(), null); + JavaProjectHelper.set14CompilerOptions(fJProject1, false); + fSourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src"); + + StringBuffer buf= new StringBuffer(); + buf.append("module test {\n"); + buf.append("}\n"); + IPackageFragment def= fSourceFolder.createPackageFragment("", false, null); + def.createCompilationUnit("module-info.java", buf.toString(), false, null); + + IPackageFragment pack= fSourceFolder.createPackageFragment("test", false, null); + buf= new StringBuffer(); + buf.append("package test;\n"); + buf.append("public class Cls {\n"); + buf.append(" public int foo(int k) {\n"); + buf.append(" int i;\n"); + buf.append(" // var comment\n"); + buf.append(" int j = 4;\n"); + buf.append(" // logic comment\n"); + buf.append(" switch (j) {\n"); + buf.append(" case 0: System.out.println(\"here\"); // fall-through with statements\n"); + buf.append(" case 1: i = 5; break;\n"); + buf.append(" case 2:\n"); + buf.append(" case 3:\n"); + buf.append(" case 4: System.out.println(\"here\"); i = 7; break;\n"); + buf.append(" case 5:\n"); + buf.append(" case 6: i = 14; break;\n"); + buf.append(" default: i = 22; break;\n"); + buf.append(" }\n"); + buf.append(" return i;\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu= pack.createCompilationUnit("Cls.java", buf.toString(), false, null); + + int index= buf.indexOf("switch"); + IInvocationContext ctx= getCorrectionContext(cu, index, 0); + assertNoErrors(ctx); + ArrayList<IJavaCompletionProposal> proposals= collectAssists(ctx, false); + assertProposalDoesNotExist(proposals, FixMessages.SwitchExpressionsFix_convert_to_switch_expression); + + } + + @Test + public void testNoConvertToSwitchExpression3() throws Exception { + fJProject1= JavaProjectHelper.createJavaProject("TestProject1", "bin"); + fJProject1.setRawClasspath(projectSetup.getDefaultClasspath(), null); + JavaProjectHelper.set14CompilerOptions(fJProject1, false); + fSourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src"); + + StringBuffer buf= new StringBuffer(); + buf.append("module test {\n"); + buf.append("}\n"); + IPackageFragment def= fSourceFolder.createPackageFragment("", false, null); + def.createCompilationUnit("module-info.java", buf.toString(), false, null); + + IPackageFragment pack= fSourceFolder.createPackageFragment("test", false, null); + buf= new StringBuffer(); + buf.append("package test;\n"); + buf.append("public class Cls {\n"); + buf.append(" public int foo(int k) {\n"); + buf.append(" int i;\n"); + buf.append(" // var comment\n"); + buf.append(" int j = 4;\n"); + buf.append(" // logic comment\n"); + buf.append(" switch (j) {\n"); + buf.append(" case 0:\n"); + buf.append(" case 1: i = 5; return i; // return statement\n"); + buf.append(" case 2:\n"); + buf.append(" case 3:\n"); + buf.append(" case 4: System.out.println(\"here\"); i = 7; break;\n"); + buf.append(" case 5:\n"); + buf.append(" case 6: i = 14; break;\n"); + buf.append(" default: i = 22; break;\n"); + buf.append(" }\n"); + buf.append(" return i;\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu= pack.createCompilationUnit("Cls.java", buf.toString(), false, null); + + int index= buf.indexOf("switch"); + IInvocationContext ctx= getCorrectionContext(cu, index, 0); + assertNoErrors(ctx); + ArrayList<IJavaCompletionProposal> proposals= collectAssists(ctx, false); + assertProposalDoesNotExist(proposals, FixMessages.SwitchExpressionsFix_convert_to_switch_expression); + + } + + @Test + public void testNoConvertToSwitchExpression4() throws Exception { + fJProject1= JavaProjectHelper.createJavaProject("TestProject1", "bin"); + fJProject1.setRawClasspath(projectSetup.getDefaultClasspath(), null); + JavaProjectHelper.set14CompilerOptions(fJProject1, false); + fSourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src"); + + StringBuffer buf= new StringBuffer(); + buf.append("module test {\n"); + buf.append("}\n"); + IPackageFragment def= fSourceFolder.createPackageFragment("", false, null); + def.createCompilationUnit("module-info.java", buf.toString(), false, null); + + IPackageFragment pack= fSourceFolder.createPackageFragment("test", false, null); + buf= new StringBuffer(); + buf.append("package test;\n"); + buf.append("public class Cls {\n"); + buf.append(" public int foo(int k) {\n"); + buf.append(" int i;\n"); + buf.append(" // var comment\n"); + buf.append(" int j = 4;\n"); + buf.append(" // logic comment\n"); + buf.append(" switch (j) {\n"); + buf.append(" case 0:\n"); + buf.append(" case 1: i = 5; j = 5; break; // last statement not common assignment\n"); + buf.append(" case 2:\n"); + buf.append(" case 3:\n"); + buf.append(" case 4: System.out.println(\"here\"); i = 7; break;\n"); + buf.append(" case 5:\n"); + buf.append(" case 6: i = 14; break;\n"); + buf.append(" default: i = 22; break;\n"); + buf.append(" }\n"); + buf.append(" return i;\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu= pack.createCompilationUnit("Cls.java", buf.toString(), false, null); + + int index= buf.indexOf("switch"); + IInvocationContext ctx= getCorrectionContext(cu, index, 0); + assertNoErrors(ctx); + ArrayList<IJavaCompletionProposal> proposals= collectAssists(ctx, false); + assertProposalDoesNotExist(proposals, FixMessages.SwitchExpressionsFix_convert_to_switch_expression); + + } + + @Test + public void testNoConvertToSwitchExpression5() throws Exception { + fJProject1= JavaProjectHelper.createJavaProject("TestProject1", "bin"); + fJProject1.setRawClasspath(projectSetup.getDefaultClasspath(), null); + JavaProjectHelper.set14CompilerOptions(fJProject1, false); + fSourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src"); + + StringBuffer buf= new StringBuffer(); + buf.append("module test {\n"); + buf.append("}\n"); + IPackageFragment def= fSourceFolder.createPackageFragment("", false, null); + def.createCompilationUnit("module-info.java", buf.toString(), false, null); + + IPackageFragment pack= fSourceFolder.createPackageFragment("test", false, null); + buf= new StringBuffer(); + buf.append("package test;\n"); + buf.append("public class Cls {\n"); + buf.append(" public int foo(int k) {\n"); + buf.append(" int i;\n"); + buf.append(" // var comment\n"); + buf.append(" int j = 4;\n"); + buf.append(" // logic comment\n"); + buf.append(" switch (j) {\n"); + buf.append(" case 0:\n"); + buf.append(" case 1: i = 5; break;\n"); + buf.append(" case 2:\n"); + buf.append(" case 3:\n"); + buf.append(" case 4: System.out.println(\"here\"); i = 7; break;\n"); + buf.append(" case 5:\n"); + buf.append(" case 6: i = 14; break;\n"); + buf.append(" // no default\n"); + buf.append(" }\n"); + buf.append(" return i;\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu= pack.createCompilationUnit("Cls.java", buf.toString(), false, null); + + int index= buf.indexOf("switch"); + IInvocationContext ctx= getCorrectionContext(cu, index, 0); + ArrayList<IJavaCompletionProposal> proposals= collectAssists(ctx, false); + assertProposalDoesNotExist(proposals, FixMessages.SwitchExpressionsFix_convert_to_switch_expression); + + } +} + diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d14.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d14.java index 579bfeb2a3..fd32484fb3 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d14.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d14.java @@ -34,7 +34,7 @@ import org.eclipse.jdt.ui.tests.core.rules.ProjectTestSetup; public class CleanUpTest1d14 extends CleanUpTestCase { @Rule - public ProjectTestSetup projectSetup = new Java14ProjectTestSetup(true); + public ProjectTestSetup projectSetup = new Java14ProjectTestSetup(false); @Override protected IJavaProject getProject() { @@ -46,40 +46,213 @@ public class CleanUpTest1d14 extends CleanUpTestCase { return projectSetup.getDefaultClasspath(); } + public void testConvertToSwitchExpressionMethod() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String sample= "" // + + "package test1;\n" // + + "\n" // + + "public class E {\n" // + + " public int foo(int j) {\n" // + + " // return value\n" // + + " int i;\n" // + + " // logic comment\n" // + + " switch (j) {\n" // + + " case 1:\n" // + + " case 2:\n" // + + " System.out.println(\"here\"); // comment 1\n" // + + " // comment 2\n" // + + " i = 7; // comment 3\n" // + + " break;\n" // + + " case 3: throw new RuntimeException(); // throw comment\n" // + + " default:\n" // + + " i = 8; // value 8\n" // + + " break;\n" // + + " }\n" // + + " return i;\n" // + + " }\n" // + + "}\n"; + + ICompilationUnit cu1= pack1.createCompilationUnit("E.java", sample, false, null); + enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS); + + sample= "" // + + "package test1;\n" // + + "\n" // + + "public class E {\n" // + + " public int foo(int j) {\n" // + + " // return value\n" // + + " int i = switch (j) {\n" // + + " case 1, 2 -> {\n" + + " System.out.println(\"here\"); // comment 1\n" // + + " // comment 2\n" // + + " yield 7; // comment 3\n" // + + " }\n" // + + " case 3 -> throw new RuntimeException(); // throw comment\n" // + + " default -> 8; // value 8\n" // + + " };\n" // + + " return i;\n" // + + " }\n" // + + "}\n"; + String expected1= sample; + + assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected1 }); + } + @Test - public void testRegexPatternForRecord() throws Exception { + public void testConvertToSwitchExpressionField() throws Exception { IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); String sample= "" // + "package test1;\n" // + "\n" // - + "public record E(int width, int height) {\n" // - + " public void foo() {\n" // - + " String k = \"bcd\";\n" // - + " String m = \"abcdef\";\n" // - + " String n = \"bcdefg\";\n" // - + " String[] a = m.split(k);\n" // - + " String[] b = n.split(k);\n" // + + "public class E {\n" // + + " private int i;\n" // + + " public void foo(int j) {\n" // + + " // logic comment\n" // + + " switch (j) {\n" // + + " case 1:\n" // + + " case 2:\n" // + + " System.out.println(\"here\");\n" // + + " // comment 1\n" // + + " i = 7; // comment 2\n" // + + " break;\n" // + + " default:\n" // + + " i = 8; // value 8\n" // + + " break;\n" // + + " }\n" // + " }\n" // + "}\n"; ICompilationUnit cu1= pack1.createCompilationUnit("E.java", sample, false, null); - enable(CleanUpConstants.PRECOMPILE_REGEX); - enable(CleanUpConstants.FORMAT_CORRECT_INDENTATION); + enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS); sample= "" // + "package test1;\n" // + "\n" // - + "import java.util.regex.Pattern;\n" // + + "public class E {\n" // + + " private int i;\n" // + + " public void foo(int j) {\n" // + + " // logic comment\n" // + + " i = switch (j) {\n" // + + " case 1, 2 -> {\n" + + " System.out.println(\"here\");\n" // + + " // comment 1\n" // + + " yield 7; // comment 2\n" // + + " }\n" // + + " default -> 8; // value 8\n" // + + " };\n" // + + " }\n" // + + "}\n"; + String expected1= sample; + + assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected1 }); + } + + @Test + public void testConvertToSwitchExpressionStaticInitializer() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String sample= "" // + + "package test1;\n" // + + "import java.util.Random;\n" // + + "public class E {\n" // + + " private static int i;\n" // + + " static {\n" // + + " Random rand= new Random();\n" // + + " int j = rand.nextInt(10);\n" // + + " // logic comment\n" // + + " switch (j) {\n" // + + " case 1:\n" // + + " case 2:\n" // + + " System.out.println(\"here\");\n" // + + " // comment 2\n" // + + " i = 7; // comment 3\n" // + + " break;\n" // + + " default:\n" // + + " i = 8; // value 8\n" // + + " break;\n" // + + " }\n" // + + " }\n" // + + "}\n"; + ICompilationUnit cu1= pack1.createCompilationUnit("E.java", sample, false, null); + + enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS); + + sample= "" // + + "package test1;\n" // + + "import java.util.Random;\n" // + + "public class E {\n" // + + " private static int i;\n" // + + " static {\n" // + + " Random rand= new Random();\n" // + + " int j = rand.nextInt(10);\n" // + + " // logic comment\n" // + + " i = switch (j) {\n" // + + " case 1, 2 -> {\n" + + " System.out.println(\"here\");\n" // + + " // comment 2\n" // + + " yield 7; // comment 3\n" // + + " }\n" // + + " default -> 8; // value 8\n" // + + " };\n" // + + " }\n" // + + "}\n"; + String expected1= sample; + + assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected1 }); + } + + @Test + public void testConvertToSwitchExpressionEnumsNoDefault() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String sample= "" // + + "package test1;\n" // + "\n" // - + "public record E(int width, int height) {\n" // - + " private static final Pattern k_pattern = Pattern.compile(\"bcd\");\n" // + + "public class E {\n" // + + " public enum Day {\n" // + + " MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;\n" // + + " }\n" // + + " public int foo(Day day) {\n" // + + " // return value\n" // + + " int i = 0;\n" // + + " // logic comment\n" // + + " switch (day) {\n" // + + " case SATURDAY:\n" // + + " case SUNDAY:\n" // + + " i = 5;\n" // + + " break;\n" // + + " case MONDAY:\n" // + + " case TUESDAY:\n" // + + " case WEDNESDAY:\n" // + + " i = 7;\n" // + + " break;\n" // + + " case THURSDAY:\n" // + + " case FRIDAY:\n" // + + " i = 14;\n" // + + " break;\n" // + + " }\n" // + + " return i;\n" // + + " }\n" // + + "}\n"; + ICompilationUnit cu1= pack1.createCompilationUnit("E.java", sample, false, null); + + enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS); + + sample= "" // + + "package test1;\n" // + "\n" // - + " public void foo() {\n" // - + " Pattern k = k_pattern;\n" // - + " String m = \"abcdef\";\n" // - + " String n = \"bcdefg\";\n" // - + " String[] a = k.split(m);\n" // - + " String[] b = k.split(n);\n" // + + "public class E {\n" // + + " public enum Day {\n" // + + " MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;\n" // + + " }\n" // + + " public int foo(Day day) {\n" // + + " // return value\n" // + + " int i = 0;\n" // + + " // logic comment\n" // + + " i = switch (day) {\n" // + + " case SATURDAY, SUNDAY -> 5;\n" // + + " case MONDAY, TUESDAY, WEDNESDAY -> 7;\n" // + + " case THURSDAY, FRIDAY -> 14;\n" // + + " };\n" // + + " return i;\n" // + " }\n" // + "}\n"; String expected1= sample; @@ -87,4 +260,227 @@ public class CleanUpTest1d14 extends CleanUpTestCase { assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected1 }); } + @Test + public void testDoNotConvertToSwitchExpressionNoBreak() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String sample= "" // + + "package test1;\n" // + + "\n" // + + "public class E1 {\n" // + + " public int foo(int j) {\n" // + + " // return value\n" // + + " int i;\n" // + + " switch (j) {\n" // + + " case 1:\n" // + + " i = 8; // can't refactor with no break\n" // + + " case 2:\n" // + + " i = 7; // value 7\n" // + + " break;\n" // + + " default:\n" // + + " i = 8; // value 8\n" // + + " break;\n" // + + " }\n" // + + " return i;\n" // + + " }\n" // + + "}\n"; + ICompilationUnit cu1= pack1.createCompilationUnit("E1.java", sample, false, null); + + enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS); + + assertRefactoringHasNoChange(new ICompilationUnit[] { cu1 }); + } + + @Test + public void testDoNotConvertToSwitchExpressionNoStatements() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String sample= "" // + + "package test1;\n" // + + "\n" // + + "public class E1 {\n" // + + " public int foo(int j) {\n" // + + " // return value\n" // + + " int i = 0;\n" // + + " switch (j) {\n" // + + " case 1:\n" // + + " break; // can't refactor with no statements\n" // + + " case 2:\n" // + + " i = 7; // value 7\n" // + + " break;\n" // + + " default:\n" // + + " i = 8; // value 8\n" // + + " break;\n" // + + " }\n" // + + " return i;\n" // + + " }\n" // + + "}\n"; + ICompilationUnit cu1= pack1.createCompilationUnit("E1.java", sample, false, null); + + enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS); + + assertRefactoringHasNoChange(new ICompilationUnit[] { cu1 }); + } + + @Test + public void testDoNotConvertToSwitchExpressionNoAssignment() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String sample= "" // + + "package test1;\n" // + + "\n" // + + "public class E1 {\n" // + + " public int foo(int j) {\n" // + + " // return value\n" // + + " int i = 0;\n" // + + " switch (j) {\n" // + + " case 1:\n" // + + " System.out.println(\"here\");\n" // + + " break; // can't refactor with no assignment to i\n" // + + " case 2:\n" // + + " i = 7; // value 7\n" // + + " break;\n" // + + " default:\n" // + + " i = 8; // value 8\n" // + + " break;\n" // + + " }\n" // + + " return i;\n" // + + " }\n" // + + "}\n"; + ICompilationUnit cu1= pack1.createCompilationUnit("E1.java", sample, false, null); + + enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS); + + assertRefactoringHasNoChange(new ICompilationUnit[] { cu1 }); + } + + @Test + public void testDoNotConvertToSwitchExpressionNoLastAssignment() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String sample= "" // + + "package test1;\n" // + + "\n" // + + "public class E1 {\n" // + + " public int foo(int j) {\n" // + + " // return value\n" // + + " int i = 0;\n" // + + " switch (j) {\n" // + + " case 1:\n" // + + " i = 6; // assignment not last statement\n" // + + " System.out.println(\"here\");\n" // + + " break;\n" // + + " case 2:\n" // + + " i = 7; // value 7\n" // + + " break;\n" // + + " default:\n" // + + " i = 8; // value 8\n" // + + " break;\n" // + + " }\n" // + + " return i;\n" // + + " }\n" // + + "}\n"; + ICompilationUnit cu1= pack1.createCompilationUnit("E1.java", sample, false, null); + + enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS); + + assertRefactoringHasNoChange(new ICompilationUnit[] { cu1 }); + } + + @Test + public void testDoNotConvertToSwitchExpressionIfElse() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String sample= "" // + + "package test1;\n" // + + "\n" // + + "public class E1 {\n" // + + " public int foo(int j, int k) {\n" // + + " // return value\n" // + + " int i;\n" // + + " switch (j) {\n" // + + " case 1:\n" // + + " if (k < 4) { // we don't delve into control statements\n" // + + " i = 6;\n" // + + " } else {\n" // + + " i = 9;\n" // + + " }\n" // + + " break;\n" // + + " case 2:\n" // + + " i = 7; // value 7\n" // + + " break;\n" // + + " default:\n" // + + " i = 8; // value 8\n" // + + " break;\n" // + + " }\n" // + + " return i;\n" // + + " }\n" // + + "}\n"; + ICompilationUnit cu1= pack1.createCompilationUnit("E1.java", sample, false, null); + + enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS); + + assertRefactoringHasNoChange(new ICompilationUnit[] { cu1 }); + } + + @Test + public void testDoNotConvertToSwitchExpressionWithTry() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String sample= "" // + + "package test1;\n" // + + "\n" // + + "public class E1 {\n" // + + " public int foo(int j, int k) {\n" // + + " // return value\n" // + + " int i;\n" // + + " switch (j) {\n" // + + " case 1:\n" // + + " try { // we don't delve into try statements\n" // + + " i = 6;\n" // + + " } finally {\n" // + + " i = 9;\n" // + + " }\n" // + + " break;\n" // + + " case 2:\n" // + + " i = 7; // value 7\n" // + + " break;\n" // + + " default:\n" // + + " i = 8; // value 8\n" // + + " break;\n" // + + " }\n" // + + " return i;\n" // + + " }\n" // + + "}\n"; + ICompilationUnit cu1= pack1.createCompilationUnit("E1.java", sample, false, null); + + enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS); + + assertRefactoringHasNoChange(new ICompilationUnit[] { cu1 }); + } + + @Test + public void testDoNotConvertToSwitchExpressionReturn() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String sample= "" // + + "package test1;\n" // + + "\n" // + + "public class E1 {\n" // + + " public int foo(int j) {\n" // + + " // return value\n" // + + " int i;\n" // + + " switch (j) {\n" // + + " case 1:\n" // + + " return 6; // we don't support return\n" // + + " case 2:\n" // + + " i = 7; // value 7\n" // + + " break;\n" // + + " default:\n" // + + " i = 8; // value 8\n" // + + " break;\n" // + + " }\n" // + + " return i;\n" // + + " }\n" // + + "}\n"; + ICompilationUnit cu1= pack1.createCompilationUnit("E1.java", sample, false, null); + + enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS); + + assertRefactoringHasNoChange(new ICompilationUnit[] { cu1 }); + } + } diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d15.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d15.java new file mode 100644 index 0000000000..908625deab --- /dev/null +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d15.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2020 Red Hat Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ui.tests.quickfix; + +import org.junit.Rule; +import org.junit.Test; + +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IPackageFragment; + +import org.eclipse.jdt.internal.corext.fix.CleanUpConstants; + +import org.eclipse.jdt.ui.tests.core.rules.Java15ProjectTestSetup; +import org.eclipse.jdt.ui.tests.core.rules.ProjectTestSetup; + +/** + * Tests the cleanup features related to Java 15. + */ +public class CleanUpTest1d15 extends CleanUpTestCase { + + @Rule + public ProjectTestSetup projectSetup = new Java15ProjectTestSetup(true); + + @Override + protected IJavaProject getProject() { + return projectSetup.getProject(); + } + + @Override + protected IClasspathEntry[] getDefaultClasspath() throws CoreException { + return projectSetup.getDefaultClasspath(); + } + + @Test + public void testRegexPatternForRecord() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String sample= "" // + + "package test1;\n" // + + "\n" // + + "public record E(int width, int height) {\n" // + + " public void foo() {\n" // + + " String k = \"bcd\";\n" // + + " String m = \"abcdef\";\n" // + + " String n = \"bcdefg\";\n" // + + " String[] a = m.split(k);\n" // + + " String[] b = n.split(k);\n" // + + " }\n" // + + "}\n"; + ICompilationUnit cu1= pack1.createCompilationUnit("E.java", sample, false, null); + + enable(CleanUpConstants.PRECOMPILE_REGEX); + enable(CleanUpConstants.FORMAT_CORRECT_INDENTATION); + + sample= "" // + + "package test1;\n" // + + "\n" // + + "import java.util.regex.Pattern;\n" // + + "\n" // + + "public record E(int width, int height) {\n" // + + " private static final Pattern k_pattern = Pattern.compile(\"bcd\");\n" // + + "\n" // + + " public void foo() {\n" // + + " Pattern k = k_pattern;\n" // + + " String m = \"abcdef\";\n" // + + " String n = \"bcdefg\";\n" // + + " String[] a = k.split(m);\n" // + + " String[] b = k.split(n);\n" // + + " }\n" // + + "}\n"; + String expected1= sample; + + assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected1 }); + } + +} diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java index 99aab5e5f8..c2b9868dd5 100644 --- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java +++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java @@ -52,6 +52,8 @@ public class CleanUpConstantsOptions extends CleanUpConstants { options.setOption(CONTROL_STATMENTS_CONVERT_FOR_LOOP_TO_ENHANCED, CleanUpOptions.FALSE); options.setOption(CONTROL_STATMENTS_CONVERT_FOR_LOOP_ONLY_IF_LOOP_VAR_USED, CleanUpOptions.FALSE); + options.setOption(CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS, CleanUpOptions.FALSE); + //Expressions options.setOption(EXPRESSIONS_USE_PARENTHESES, CleanUpOptions.FALSE); options.setOption(EXPRESSIONS_USE_PARENTHESES_NEVER, CleanUpOptions.TRUE); @@ -162,6 +164,8 @@ public class CleanUpConstantsOptions extends CleanUpConstants { options.setOption(CONTROL_STATMENTS_CONVERT_FOR_LOOP_TO_ENHANCED, CleanUpOptions.FALSE); options.setOption(CONTROL_STATMENTS_CONVERT_FOR_LOOP_ONLY_IF_LOOP_VAR_USED, CleanUpOptions.FALSE); + options.setOption(CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS, CleanUpOptions.FALSE); + //Expressions options.setOption(EXPRESSIONS_USE_PARENTHESES, CleanUpOptions.FALSE); options.setOption(EXPRESSIONS_USE_PARENTHESES_NEVER, CleanUpOptions.TRUE); diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/SwitchExpressionsFix.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/SwitchExpressionsFix.java new file mode 100644 index 0000000000..ccc3ee9767 --- /dev/null +++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/SwitchExpressionsFix.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2020 Red Hat Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.corext.fix; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.SwitchStatement; + +import org.eclipse.jdt.internal.corext.fix.SwitchExpressionsFixCore.SwitchExpressionsFixOperation; +import org.eclipse.jdt.internal.corext.util.JavaModelUtil; + +import org.eclipse.jdt.ui.cleanup.ICleanUpFix; + +public class SwitchExpressionsFix extends CompilationUnitRewriteOperationsFix { + + public static ICleanUpFix createCleanUp(CompilationUnit compilationUnit) { + if (!JavaModelUtil.is14OrHigher(compilationUnit.getJavaElement().getJavaProject())) + return null; + + List<SwitchExpressionsFixOperation> operations= new ArrayList<>(); + SwitchExpressionsFixCore.SwitchStatementsFinder finder= new SwitchExpressionsFixCore.SwitchStatementsFinder(operations); + compilationUnit.accept(finder); + if (operations.isEmpty()) + return null; + + CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] ops= operations.toArray(new CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[operations.size()]); + return new SwitchExpressionsFix(FixMessages.SwitchExpressionsFix_convert_to_switch_expression, compilationUnit, ops); + } + + public static SwitchExpressionsFix createConvertToSwitchExpressionFix(SwitchStatement switchStatement) { + CompilationUnit root= (CompilationUnit) switchStatement.getRoot(); + if (!JavaModelUtil.is14OrHigher(root.getJavaElement().getJavaProject())) + return null; + + List<SwitchExpressionsFixOperation> operations= new ArrayList<>(); + SwitchExpressionsFixCore.SwitchStatementsFinder finder= new SwitchExpressionsFixCore.SwitchStatementsFinder(operations); + switchStatement.accept(finder); + if (operations.isEmpty()) + return null; + return new SwitchExpressionsFix(FixMessages.SwitchExpressionsFix_convert_to_switch_expression, root, new CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] { operations.get(0) }); + } + + protected SwitchExpressionsFix(String name, CompilationUnit compilationUnit, CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] fixRewriteOperations) { + super(name, compilationUnit, fixRewriteOperations); + } + +} diff --git a/org.eclipse.jdt.ui/plugin.xml b/org.eclipse.jdt.ui/plugin.xml index 194989abab..007160e447 100644 --- a/org.eclipse.jdt.ui/plugin.xml +++ b/org.eclipse.jdt.ui/plugin.xml @@ -7071,9 +7071,14 @@ runAfter="org.eclipse.jdt.ui.cleanup.var"> </cleanUp> <cleanUp + class="org.eclipse.jdt.internal.ui.fix.SwitchExpressionsCleanUp" + id="org.eclipse.jdt.ui.cleanup.switch_expressions" + runAfter="org.eclipse.jdt.ui.cleanup.lambda"> + </cleanUp> + <cleanUp class="org.eclipse.jdt.internal.ui.fix.ExpressionsCleanUp" id="org.eclipse.jdt.ui.cleanup.expressions" - runAfter="org.eclipse.jdt.ui.cleanup.lambda"> + runAfter="org.eclipse.jdt.ui.cleanup.switch_expressions"> </cleanUp> <cleanUp class="org.eclipse.jdt.internal.ui.fix.LambdaExpressionAndMethodRefCleanUp" diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/SwitchExpressionsCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/SwitchExpressionsCleanUp.java new file mode 100644 index 0000000000..cf8538cbd8 --- /dev/null +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/SwitchExpressionsCleanUp.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2020 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Red Hat Inc. - created by modifying LambdaExpressionsCleanUp + *******************************************************************************/ +package org.eclipse.jdt.internal.ui.fix; + +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.jdt.core.manipulation.ICleanUpFixCore; + +import org.eclipse.jdt.ui.cleanup.CleanUpContext; +import org.eclipse.jdt.ui.cleanup.CleanUpOptions; +import org.eclipse.jdt.ui.cleanup.CleanUpRequirements; +import org.eclipse.jdt.ui.cleanup.ICleanUpFix; + +public class SwitchExpressionsCleanUp extends AbstractCleanUp { + + private SwitchExpressionsCleanUpCore coreCleanUp= new SwitchExpressionsCleanUpCore(); + + public SwitchExpressionsCleanUp(Map<String, String> options) { + super(); + setOptions(options); + } + + public SwitchExpressionsCleanUp() { + super(); + } + + @Override + public void setOptions(CleanUpOptions options) { + coreCleanUp.setOptions(options); + } + + @Override + public CleanUpRequirements getRequirements() { + return new CleanUpRequirements(coreCleanUp.getRequirementsCore()); + } + + @Override + public ICleanUpFix createFix(CleanUpContext context) throws CoreException { + ICleanUpFixCore fixCore= coreCleanUp.createFixCore(context); + return fixCore == null ? null : new CleanUpFixWrapper(fixCore); + } + + @Override + public String[] getStepDescriptions() { + return coreCleanUp.getStepDescriptions(); + } + + @Override + public String getPreview() { + return coreCleanUp.getPreview(); + } + +} diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java index dd85271cdb..779b335503 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java @@ -51,6 +51,7 @@ public class CleanUpMessages extends NLS { public static String CodeStyleTabPage_CheckboxName_ConvertForLoopToEnhanced; public static String CodeStyleTabPage_CheckboxName_ConvertLoopOnlyIfLoopVarUsed; + public static String CodeStyleTabPage_CheckboxName_ConvertToSwitchExpressions; public static String CodeStyleTabPage_CheckboxName_UseBlocks; public static String CodeStyleTabPage_CheckboxName_UseFinal; public static String CodeStyleTabPage_CheckboxName_UseFinalForFields; diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties index 1248684a0d..185432eb37 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties @@ -45,6 +45,7 @@ CodeStyleTabPage_CheckboxName_CheckSignOfBitwiseOperation=&Compare with != 0 for CodeStyleTabPage_CheckboxName_UseFinal=U&se modifier 'final' where possible CodeStyleTabPage_CheckboxName_UseFinalForParameters=P&arameter CodeStyleTabPage_CheckboxName_UseVar=&Use local variable type inference (Java 10 or higher) +CodeStyleTabPage_CheckboxName_ConvertToSwitchExpressions=Convert to switch expression (Java 14 or higher) CodeStyleTabPage_RadioName_AlwaysUseParantheses=Alwa&ys CodeStyleTabPage_RadioName_NeverUseParantheses=Only &if necessary CodeStyleTabPage_GroupName_VariableDeclarations=Variable declarations diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CodeStyleTabPage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CodeStyleTabPage.java index 5ec553eed3..ecf63a48f0 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CodeStyleTabPage.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CodeStyleTabPage.java @@ -28,6 +28,7 @@ import org.eclipse.jdt.internal.ui.fix.ExpressionsCleanUp; import org.eclipse.jdt.internal.ui.fix.LambdaExpressionAndMethodRefCleanUp; import org.eclipse.jdt.internal.ui.fix.LambdaExpressionsCleanUp; import org.eclipse.jdt.internal.ui.fix.NumberSuffixCleanUp; +import org.eclipse.jdt.internal.ui.fix.SwitchExpressionsCleanUp; import org.eclipse.jdt.internal.ui.fix.VarCleanUp; import org.eclipse.jdt.internal.ui.fix.VariableDeclarationCleanUp; @@ -44,6 +45,7 @@ public final class CodeStyleTabPage extends AbstractCleanUpTabPage { new BitwiseConditionalExpressionCleanup(values), new VariableDeclarationCleanUp(values), new VarCleanUp(values), + new SwitchExpressionsCleanUp(values), new LambdaExpressionsCleanUp(values), new LambdaExpressionAndMethodRefCleanUp(values) }; @@ -62,6 +64,9 @@ public final class CodeStyleTabPage extends AbstractCleanUpTabPage { final RadioPreference useBlockNeverPref= createRadioPref(controlGroup, numColumns - 1, CleanUpMessages.CodeStyleTabPage_RadioName_NeverUseBlocks, CleanUpConstants.CONTROL_STATMENTS_USE_BLOCKS_NEVER, CleanUpModifyDialog.FALSE_TRUE); registerSlavePreference(useBlockPref, new RadioPreference[] {useBlockAlwaysPref, useBlockJDTStylePref, useBlockNeverPref}); + CheckboxPreference convertToSwitchExpressions= createCheckboxPref(controlGroup, numColumns, CleanUpMessages.CodeStyleTabPage_CheckboxName_ConvertToSwitchExpressions, CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS, CleanUpModifyDialog.FALSE_TRUE); + registerPreference(convertToSwitchExpressions); + CheckboxPreference convertLoop= createCheckboxPref(controlGroup, numColumns, CleanUpMessages.CodeStyleTabPage_CheckboxName_ConvertForLoopToEnhanced, CleanUpConstants.CONTROL_STATMENTS_CONVERT_FOR_LOOP_TO_ENHANCED, CleanUpModifyDialog.FALSE_TRUE); registerPreference(convertLoop); intent(controlGroup); diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/IProposalRelevance.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/IProposalRelevance.java index 46c4350d9b..e8124053e7 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/IProposalRelevance.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/IProposalRelevance.java @@ -236,6 +236,7 @@ public interface IProposalRelevance { int RETURN_ALLOCATED_OBJECT= 2; int REMOVE_BLOCK_FIX= 2; int CONVERT_TO_ANONYMOUS_CLASS_CREATION= 2; + int CONVERT_TO_SWITCH_EXPRESSION= 2; int JOIN_VARIABLE_DECLARATION= 1; int INVERT_EQUALS= 1; diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java index ac651281e7..629833cf45 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java @@ -166,6 +166,7 @@ import org.eclipse.jdt.internal.corext.fix.ConvertLoopFix; import org.eclipse.jdt.internal.corext.fix.IProposableFix; import org.eclipse.jdt.internal.corext.fix.LambdaExpressionsFix; import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel; +import org.eclipse.jdt.internal.corext.fix.SwitchExpressionsFix; import org.eclipse.jdt.internal.corext.fix.TypeParametersFix; import org.eclipse.jdt.internal.corext.fix.UnnecessaryArrayCreationFix; import org.eclipse.jdt.internal.corext.fix.VariableDeclarationFix; @@ -197,6 +198,7 @@ import org.eclipse.jdt.internal.ui.JavaPluginImages; import org.eclipse.jdt.internal.ui.fix.ControlStatementsCleanUp; import org.eclipse.jdt.internal.ui.fix.ConvertLoopCleanUp; import org.eclipse.jdt.internal.ui.fix.LambdaExpressionsCleanUp; +import org.eclipse.jdt.internal.ui.fix.SwitchExpressionsCleanUp; import org.eclipse.jdt.internal.ui.fix.TypeParametersCleanUp; import org.eclipse.jdt.internal.ui.fix.UnnecessaryArrayCreationCleanUp; import org.eclipse.jdt.internal.ui.fix.VariableDeclarationCleanUp; @@ -302,6 +304,7 @@ public class QuickAssistProcessor implements IQuickAssistProcessor { || getRemoveVarOrInferredLambdaParameterTypes(context, coveringNode, null) || getConvertMethodReferenceToLambdaProposal(context, coveringNode, null) || getConvertLambdaToMethodReferenceProposal(context, coveringNode, null) + || getConvertToSwitchExpressionProposals(context, coveringNode, null) || getFixParenthesesInLambdaExpression(context, coveringNode, null) || getRemoveBlockProposals(context, coveringNode, null) || getMakeVariableDeclarationFinalProposals(context, null) @@ -379,6 +382,7 @@ public class QuickAssistProcessor implements IQuickAssistProcessor { getConvertVarTypeToResolvedTypeProposal(context, coveringNode, resultingCollections); getConvertResolvedTypeToVarTypeProposal(context, coveringNode, resultingCollections); getAddStaticImportProposals(context, coveringNode, resultingCollections); + getConvertToSwitchExpressionProposals(context, coveringNode, resultingCollections); } return resultingCollections.toArray(new IJavaCompletionProposal[resultingCollections.size()]); } @@ -677,7 +681,7 @@ public class QuickAssistProcessor implements IQuickAssistProcessor { Map<String, String> options= new Hashtable<>(); options.put(CleanUpConstants.CONVERT_FUNCTIONAL_INTERFACES, CleanUpOptions.TRUE); options.put(CleanUpConstants.USE_ANONYMOUS_CLASS_CREATION, CleanUpOptions.TRUE); - FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new LambdaExpressionsCleanUp(options), IProposalRelevance.CONVERT_TO_ANONYMOUS_CLASS_CREATION, image, context); + FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new LambdaExpressionsCleanUp(options), IProposalRelevance.CONVERT_TO_SWITCH_EXPRESSION, image, context); resultingCollections.add(proposal); return true; } @@ -715,6 +719,35 @@ public class QuickAssistProcessor implements IQuickAssistProcessor { return true; } + private static boolean getConvertToSwitchExpressionProposals(IInvocationContext context, ASTNode covering, Collection<ICommandAccess> resultingCollections) { + while (covering instanceof SwitchCase + || covering instanceof SwitchExpression) { + covering= covering.getParent(); + } + + SwitchStatement switchStatement; + if (covering instanceof SwitchStatement) { + switchStatement= (SwitchStatement) covering; + } else { + return false; + } + + IProposableFix fix= SwitchExpressionsFix.createConvertToSwitchExpressionFix(switchStatement); + if (fix == null) + return false; + + if (resultingCollections == null) + return true; + + // add correction proposal + Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); + Map<String, String> options= new Hashtable<>(); + options.put(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS, CleanUpOptions.TRUE); + FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new SwitchExpressionsCleanUp(options), IProposalRelevance.CONVERT_TO_SWITCH_EXPRESSION, image, context); + resultingCollections.add(proposal); + return true; + } + /** * Returns the functional interface method being implemented by the given method reference. * |