Bug 572574 - [AutoRefactor #71/151] Do/while rather than while
Replace while by do/while:
- The first evaluation must be always true,
- The first evaluation must be passive.
Given:
boolean isInitedToTrue= true;
while (isInitedToTrue) {
if (i > 100) {
isInitedToTrue= false;
}
i *= 2;
}
When:
Select while loop and perform CTRL+1 to do quick fix...
Then:
boolean isInitedToTrue= true;
do {
if (i > 100) {
isInitedToTrue= false;
}
i *= 2;
} while (isInitedToTrue);
Change-Id: I7c778d6777a5e363e4fc1f2df6c57a57f0d4ff32
Signed-off-by: Fabrice Tiercelin <fabrice.tiercelin@yahoo.fr>
Signed-off-by: Jeff Johnston <jjohnstn@redhat.com>
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.ui/+/178824
Tested-by: JDT Bot <jdt-bot@eclipse.org>
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/DoWhileRatherThanWhileCleanUpCore.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/DoWhileRatherThanWhileCleanUpCore.java
new file mode 100644
index 0000000..6a0b179
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/DoWhileRatherThanWhileCleanUpCore.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Fabrice TIERCELIN 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:
+ * Fabrice TIERCELIN - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.fix;
+
+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.DoWhileRatherThanWhileFixCore;
+
+public class DoWhileRatherThanWhileCleanUpCore extends AbstractCleanUpCore {
+ public DoWhileRatherThanWhileCleanUpCore(final Map<String, String> options) {
+ super(options);
+ }
+
+ public DoWhileRatherThanWhileCleanUpCore() {
+ }
+
+ @Override
+ public CleanUpRequirementsCore getRequirementsCore() {
+ return new CleanUpRequirementsCore(requireAST(), false, false, null);
+ }
+
+ public boolean requireAST() {
+ return isEnabled(CleanUpConstants.DO_WHILE_RATHER_THAN_WHILE);
+ }
+
+ @Override
+ public ICleanUpFixCore createFixCore(final CleanUpContextCore context) throws CoreException {
+ CompilationUnit compilationUnit= context.getAST();
+
+ if (compilationUnit == null || !isEnabled(CleanUpConstants.DO_WHILE_RATHER_THAN_WHILE)) {
+ return null;
+ }
+
+ return DoWhileRatherThanWhileFixCore.createCleanUp(compilationUnit);
+ }
+
+ @Override
+ public String[] getStepDescriptions() {
+ if (isEnabled(CleanUpConstants.DO_WHILE_RATHER_THAN_WHILE)) {
+ return new String[] {MultiFixMessages.DoWhileRatherThanWhileCleanUp_description};
+ }
+
+ return new String[0];
+ }
+
+ @Override
+ public String getPreview() {
+ StringBuilder bld= new StringBuilder();
+
+ if (isEnabled(CleanUpConstants.DO_WHILE_RATHER_THAN_WHILE)) {
+ bld.append("do {\n"); //$NON-NLS-1$
+ } else {
+ bld.append("while (true) {\n"); //$NON-NLS-1$
+ }
+
+ bld.append(" if (i > 100) {\n"); //$NON-NLS-1$
+ bld.append(" return;\n"); //$NON-NLS-1$
+ bld.append(" }\n"); //$NON-NLS-1$
+ bld.append(" i *= 2;\n"); //$NON-NLS-1$
+
+ if (isEnabled(CleanUpConstants.DO_WHILE_RATHER_THAN_WHILE)) {
+ bld.append("} while (true);\n"); //$NON-NLS-1$
+ } else {
+ bld.append("}\n"); //$NON-NLS-1$
+ }
+
+ return bld.toString();
+ }
+}
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 a70a9cc..aa7d64b 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
@@ -130,6 +130,7 @@
public static String SingleUsedFieldCleanUp_description_new_local_var_declaration;
public static String SingleUsedFieldCleanUp_description_uses_of_the_var;
public static String BreakLoopCleanUp_description;
+ public static String DoWhileRatherThanWhileCleanUp_description;
public static String StaticInnerClassCleanUp_description;
public static String StringBuilderCleanUp_description;
public static String PlainReplacementCleanUp_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 ed7409c..a84926c 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
@@ -112,6 +112,7 @@
SingleUsedFieldCleanUp_description_new_local_var_declaration=Convert field assignment into local variable declaration
SingleUsedFieldCleanUp_description_uses_of_the_var=Convert field call into local variable call
BreakLoopCleanUp_description=Exit loop earlier
+DoWhileRatherThanWhileCleanUp_description=Do/while rather than while
StaticInnerClassCleanUp_description=Make inner classes static where possible
StringBuilderCleanUp_description=Replace String concatenation by StringBuilder
PlainReplacementCleanUp_description=Use String.replace() instead of String.replaceAll() when possible
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 42efb3f..f709e8f 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
@@ -2301,6 +2301,17 @@
return null;
}
+ /**
+ * Returns the previous statements in the same block if it exists.
+ *
+ * @param startNode the start node
+ * @return the previous statements in the same block if it exists, empty list
+ * otherwise
+ */
+ public static List<Statement> getPreviousSiblings(final Statement startNode) {
+ return getSiblings(startNode, false);
+ }
+
private static List<Statement> getSiblings(final Statement startNode, final boolean isForward) {
Statement statementAtLevel= statementAtLevel(startNode);
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 9a62773..e2c86e0 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
@@ -1175,6 +1175,18 @@
public static final String BREAK_LOOP= "cleanup.break_loop"; //$NON-NLS-1$
/**
+ * Replace <code>while</code> by <code>do</code>/<code>while</code>.
+ * <p>
+ * Possible values: {TRUE, FALSE}
+ * <p>
+ *
+ * @see CleanUpOptionsCore#TRUE
+ * @see CleanUpOptionsCore#FALSE
+ * @since 4.20
+ */
+ public static final String DO_WHILE_RATHER_THAN_WHILE= "cleanup.do_while_rather_than_while"; //$NON-NLS-1$
+
+ /**
* Make inner <code>class</code> static.
* <p>
* Possible values: {TRUE, FALSE}
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/DoWhileRatherThanWhileFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/DoWhileRatherThanWhileFixCore.java
new file mode 100644
index 0000000..35021d8
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/DoWhileRatherThanWhileFixCore.java
@@ -0,0 +1,387 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Fabrice TIERCELIN 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:
+ * Fabrice TIERCELIN - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.corext.fix;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.text.edits.TextEditGroup;
+
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
+import org.eclipse.jdt.core.dom.Assignment;
+import org.eclipse.jdt.core.dom.Block;
+import org.eclipse.jdt.core.dom.CatchClause;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.ConditionalExpression;
+import org.eclipse.jdt.core.dom.CreationReference;
+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.ForStatement;
+import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.IVariableBinding;
+import org.eclipse.jdt.core.dom.IfStatement;
+import org.eclipse.jdt.core.dom.InfixExpression;
+import org.eclipse.jdt.core.dom.LambdaExpression;
+import org.eclipse.jdt.core.dom.MethodReference;
+import org.eclipse.jdt.core.dom.ParenthesizedExpression;
+import org.eclipse.jdt.core.dom.PostfixExpression;
+import org.eclipse.jdt.core.dom.PrefixExpression;
+import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
+import org.eclipse.jdt.core.dom.Statement;
+import org.eclipse.jdt.core.dom.SuperMethodReference;
+import org.eclipse.jdt.core.dom.SwitchStatement;
+import org.eclipse.jdt.core.dom.TryStatement;
+import org.eclipse.jdt.core.dom.TypeMethodReference;
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
+import org.eclipse.jdt.core.dom.WhileStatement;
+import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
+import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer;
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
+
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.dom.VarDefinitionsUsesVisitor;
+import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
+
+import org.eclipse.jdt.internal.ui.fix.MultiFixMessages;
+
+public class DoWhileRatherThanWhileFixCore extends CompilationUnitRewriteOperationsFixCore {
+ public static final class DoWhileRatherThanWhileFinder extends ASTVisitor {
+ private List<CompilationUnitRewriteOperation> fResult;
+
+ public DoWhileRatherThanWhileFinder(List<CompilationUnitRewriteOperation> ops) {
+ fResult= ops;
+ }
+
+ @Override
+ public boolean visit(final WhileStatement visited) {
+ if (ASTNodes.isPassiveWithoutFallingThrough(visited.getExpression()) && Boolean.TRUE.equals(peremptoryValue(visited, visited.getExpression()))) {
+ fResult.add(new DoWhileRatherThanWhileOperation(visited));
+ return false;
+ }
+
+ return true;
+ }
+
+ private Object peremptoryValue(final ASTNode visited, final Expression condition) {
+ Object constantCondition= condition.resolveConstantExpressionValue();
+
+ if (constantCondition != null) {
+ return constantCondition;
+ }
+
+ Long integerLiteral= ASTNodes.getIntegerLiteral(condition);
+
+ if (integerLiteral != null) {
+ return integerLiteral;
+ }
+
+ SimpleName variable= ASTNodes.as(condition, SimpleName.class);
+
+ if (variable != null
+ && variable.resolveBinding() != null
+ && variable.resolveBinding().getKind() == IBinding.VARIABLE) {
+ List<ASTNode> precedingStatements= getPrecedingCode(visited);
+
+ Collections.reverse(precedingStatements);
+
+ for (ASTNode precedingStatement : precedingStatements) {
+ if (isConditionalCode(precedingStatement)) {
+ return null;
+ }
+
+ VarDefinitionsUsesVisitor visitor= new VarDefinitionsUsesVisitor((IVariableBinding) variable.resolveBinding(), precedingStatement, true);
+
+ if (visitor.getWrites().size() > 1) {
+ return null;
+ }
+
+ for (SimpleName astNode : visitor.getReads()) {
+ ASTNode parent= astNode.getParent();
+
+ while (parent instanceof ParenthesizedExpression) {
+ parent= astNode.getParent();
+ }
+
+ if (parent instanceof PrefixExpression && ASTNodes.hasOperator((PrefixExpression) parent, PrefixExpression.Operator.INCREMENT, PrefixExpression.Operator.DECREMENT)
+ || parent instanceof PostfixExpression && ASTNodes.hasOperator((PostfixExpression) parent, PostfixExpression.Operator.INCREMENT, PostfixExpression.Operator.DECREMENT)) {
+ return null;
+ }
+ }
+
+ if (!visitor.getWrites().isEmpty()) {
+ SimpleName write= visitor.getWrites().get(0);
+ ASTNode parent= write;
+
+ while (parent != precedingStatement) {
+ if (isConditionalCode(parent)) {
+ return null;
+ }
+
+ parent= parent.getParent();
+ }
+
+ switch (write.getParent().getNodeType()) {
+ case ASTNode.ASSIGNMENT:
+ Assignment assignment= (Assignment) write.getParent();
+
+ if (ASTNodes.hasOperator(assignment, Assignment.Operator.ASSIGN)) {
+ return peremptoryValue(precedingStatement, assignment.getRightHandSide());
+ }
+
+ break;
+
+ case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
+ VariableDeclarationFragment fragment= (VariableDeclarationFragment) write.getParent();
+
+ if (fragment.getInitializer() != null) {
+ return peremptoryValue(precedingStatement, fragment.getInitializer());
+ }
+
+ break;
+
+ case ASTNode.SINGLE_VARIABLE_DECLARATION:
+ SingleVariableDeclaration singleVariableDeclaration= (SingleVariableDeclaration) write.getParent();
+
+ if (singleVariableDeclaration.getInitializer() != null) {
+ return peremptoryValue(precedingStatement, singleVariableDeclaration.getInitializer());
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return null;
+ }
+ }
+
+ return null;
+ }
+
+ InfixExpression infixExpression= ASTNodes.as(condition, InfixExpression.class);
+
+ if (infixExpression != null) {
+ if (!infixExpression.hasExtendedOperands()
+ && ASTNodes.hasOperator(infixExpression, InfixExpression.Operator.EQUALS,
+ InfixExpression.Operator.NOT_EQUALS,
+ InfixExpression.Operator.GREATER,
+ InfixExpression.Operator.GREATER_EQUALS,
+ InfixExpression.Operator.LESS,
+ InfixExpression.Operator.LESS_EQUALS)) {
+ Object leftOperand= peremptoryValue(visited, infixExpression.getLeftOperand());
+ Object rightOperand= peremptoryValue(visited, infixExpression.getRightOperand());
+
+ if (leftOperand instanceof Number && rightOperand instanceof Number) {
+ Number leftNumber= (Number) leftOperand;
+ Number rightNumber= (Number) rightOperand;
+
+ if (ASTNodes.hasOperator(infixExpression, InfixExpression.Operator.EQUALS)) {
+ return leftNumber.longValue() == rightNumber.longValue();
+ }
+
+ if (ASTNodes.hasOperator(infixExpression, InfixExpression.Operator.NOT_EQUALS)) {
+ return leftNumber.longValue() != rightNumber.longValue();
+ }
+
+ if (ASTNodes.hasOperator(infixExpression, InfixExpression.Operator.GREATER)) {
+ return leftNumber.longValue() > rightNumber.longValue();
+ }
+
+ if (ASTNodes.hasOperator(infixExpression, InfixExpression.Operator.GREATER_EQUALS)) {
+ return leftNumber.longValue() >= rightNumber.longValue();
+ }
+
+ if (ASTNodes.hasOperator(infixExpression, InfixExpression.Operator.LESS)) {
+ return leftNumber.longValue() < rightNumber.longValue();
+ }
+
+ if (ASTNodes.hasOperator(infixExpression, InfixExpression.Operator.LESS_EQUALS)) {
+ return leftNumber.longValue() <= rightNumber.longValue();
+ }
+ }
+
+ return null;
+ }
+
+ if (ASTNodes.hasOperator(infixExpression, InfixExpression.Operator.CONDITIONAL_AND,
+ InfixExpression.Operator.AND)) {
+ for (Expression operand : ASTNodes.allOperands(infixExpression)) {
+ final Object hasAlwaysValue= peremptoryValue(visited, operand);
+
+ if (!Boolean.TRUE.equals(hasAlwaysValue)) {
+ return hasAlwaysValue;
+ }
+ }
+
+ return Boolean.TRUE;
+ }
+
+ if (ASTNodes.hasOperator(infixExpression, InfixExpression.Operator.CONDITIONAL_OR,
+ InfixExpression.Operator.OR)) {
+ for (Expression operand : ASTNodes.allOperands(infixExpression)) {
+ final Object hasAlwaysValue= peremptoryValue(visited, operand);
+
+ if (!Boolean.FALSE.equals(hasAlwaysValue)) {
+ return hasAlwaysValue;
+ }
+ }
+
+ return Boolean.FALSE;
+ }
+ }
+
+ return Boolean.FALSE;
+ }
+
+ private boolean isConditionalCode(final ASTNode expression) {
+ return expression == null
+ || expression instanceof IfStatement
+ || expression instanceof ConditionalExpression
+ || expression instanceof EnhancedForStatement
+ || expression instanceof SwitchStatement
+ || expression instanceof WhileStatement
+ || expression instanceof ForStatement
+ || expression instanceof DoStatement
+ || expression instanceof AbstractTypeDeclaration
+ || expression instanceof LambdaExpression
+ || expression instanceof MethodReference
+ || expression instanceof SuperMethodReference
+ || expression instanceof CreationReference
+ || expression instanceof TypeMethodReference
+ || expression instanceof SuperMethodReference;
+ }
+
+ @SuppressWarnings({ "deprecation" })
+ private List<ASTNode> getPrecedingCode(final ASTNode node) {
+ Statement statement= null;
+
+ if (node instanceof Statement) {
+ statement= (Statement) node;
+ } else {
+ statement= ASTNodes.getTypedAncestor(node, Statement.class);
+ }
+
+ if (statement == null) {
+ return new ArrayList<>();
+ }
+
+ List<ASTNode> precedingStatements= new ArrayList<>(ASTNodes.getPreviousSiblings(statement));
+ ASTNode parent= statement.getParent();
+
+ if (parent instanceof Block) {
+ precedingStatements.addAll(0, getPrecedingCode(parent));
+ return precedingStatements;
+ }
+
+ if (parent instanceof IfStatement) {
+ precedingStatements.add(0, ((IfStatement) parent).getExpression());
+ precedingStatements.addAll(0, getPrecedingCode(parent));
+ }
+
+ if (parent instanceof CatchClause) {
+ TryStatement tryStatement= (TryStatement) parent.getParent();
+ precedingStatements.addAll(0, ASTNodes.asList(tryStatement.getBody()));
+
+ if (statement.getParent().getLocationInParent() != TryStatement.RESOURCES_PROPERTY) {
+ precedingStatements.addAll(0, tryStatement.resources());
+ }
+
+ precedingStatements.addAll(0, getPrecedingCode(tryStatement));
+ }
+
+ if (parent instanceof TryStatement) {
+ if (statement.getLocationInParent() == TryStatement.FINALLY_PROPERTY) {
+ return precedingStatements;
+ }
+
+ if (statement.getLocationInParent() != TryStatement.RESOURCES2_PROPERTY) {
+ precedingStatements.addAll(0, ((TryStatement) parent).resources());
+ }
+
+ precedingStatements.addAll(0, getPrecedingCode(parent));
+ }
+
+ return precedingStatements;
+ }
+ }
+
+ public static class DoWhileRatherThanWhileOperation extends CompilationUnitRewriteOperation {
+ private final WhileStatement visited;
+
+ public DoWhileRatherThanWhileOperation(final WhileStatement visited) {
+ this.visited= visited;
+ }
+
+ @Override
+ public void rewriteAST(final CompilationUnitRewrite cuRewrite, final LinkedProposalModelCore linkedModel) throws CoreException {
+ ASTRewrite rewrite= cuRewrite.getASTRewrite();
+ AST ast= cuRewrite.getRoot().getAST();
+ TextEditGroup group= createTextEditGroup(MultiFixMessages.DoWhileRatherThanWhileCleanUp_description, cuRewrite);
+ rewrite.setTargetSourceRangeComputer(new TargetSourceRangeComputer() {
+ @Override
+ public SourceRange computeSourceRange(final ASTNode nodeWithComment) {
+ if (Boolean.TRUE.equals(nodeWithComment.getProperty(ASTNodes.UNTOUCH_COMMENT))) {
+ return new SourceRange(nodeWithComment.getStartPosition(), nodeWithComment.getLength());
+ }
+
+ return super.computeSourceRange(nodeWithComment);
+ }
+ });
+
+ DoStatement newDoStatement= ast.newDoStatement();
+ newDoStatement.setExpression(ASTNodes.createMoveTarget(rewrite, ASTNodes.getUnparenthesedExpression(visited.getExpression())));
+ newDoStatement.setBody(ASTNodes.createMoveTarget(rewrite, visited.getBody()));
+ ASTNodes.replaceButKeepComment(rewrite, visited, newDoStatement, group);
+ }
+ }
+
+ public static ICleanUpFixCore createCleanUp(final CompilationUnit compilationUnit) {
+ List<CompilationUnitRewriteOperation> operations= new ArrayList<>();
+ DoWhileRatherThanWhileFinder finder= new DoWhileRatherThanWhileFinder(operations);
+ compilationUnit.accept(finder);
+
+ if (operations.isEmpty()) {
+ return null;
+ }
+
+ CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] ops= operations.toArray(new CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[0]);
+ return new DoWhileRatherThanWhileFixCore(FixMessages.DoWhileRatherThanWhileFix_description, compilationUnit, ops);
+ }
+
+ public static ICleanUpFixCore createCleanUp(final CompilationUnit compilationUnit, final WhileStatement whileStatement) {
+ List<CompilationUnitRewriteOperation> operations= new ArrayList<>();
+ DoWhileRatherThanWhileFinder finder= new DoWhileRatherThanWhileFinder(operations);
+ whileStatement.accept(finder);
+
+ if (operations.isEmpty()) {
+ return null;
+ }
+
+ CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] ops= operations.toArray(new CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[0]);
+ return new DoWhileRatherThanWhileFixCore(FixMessages.DoWhileRatherThanWhileFix_description, compilationUnit, ops);
+ }
+
+ protected DoWhileRatherThanWhileFixCore(final String name, final CompilationUnit compilationUnit, final CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] fixRewriteOperations) {
+ super(name, compilationUnit, fixRewriteOperations);
+ }
+}
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 a7ac432..f38e2be 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
@@ -136,6 +136,7 @@
public static String VariableDeclarationFix_changeModifierOfUnknownToFinal_description;
public static String VariableDeclarationFix_ChangeMidifiersToFinalWherPossible_description;
+ public static String DoWhileRatherThanWhileFix_description;
public static String NullAnnotationsFix_add_annotation_change_name;
public static String NullAnnotationsRewriteOperations_change_method_parameter_nullness;
public static String NullAnnotationsRewriteOperations_change_target_method_parameter_nullness;
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 fc2ce75..46c0308 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
@@ -165,3 +165,4 @@
TypeAnnotationFix_move=Move type annotation
TypeAnnotationFix_remove=Remove type annotation
ConstantsCleanUpFix_refactor=Replace system property with Java method
+DoWhileRatherThanWhileFix_description=Convert while to do/while
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest.java
index 572fd10..27ced63 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2020 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -2516,7 +2516,7 @@
AssistContext context= getCorrectionContext(cu, buf.toString().indexOf(str) + str.length(), 0);
List<IJavaCompletionProposal> proposals= collectAssists(context, false);
- assertNumberOfProposals(proposals, 1);
+ assertNumberOfProposals(proposals, 2);
assertCorrectLabels(proposals);
CUCorrectionProposal proposal= (CUCorrectionProposal) proposals.get(0);
@@ -6191,7 +6191,7 @@
AssistContext context= getCorrectionContext(cu, buf.toString().indexOf(str), 0);
List<IJavaCompletionProposal> proposals= collectAssists(context, false);
- assertNumberOfProposals(proposals, 1);
+ assertNumberOfProposals(proposals, 2);
assertCorrectLabels(proposals);
buf= new StringBuilder();
@@ -6232,7 +6232,7 @@
AssistContext context= getCorrectionContext(cu, buf.toString().indexOf(str), 0);
List<IJavaCompletionProposal> proposals= collectAssists(context, false);
- assertNumberOfProposals(proposals, 2);
+ assertNumberOfProposals(proposals, 3);
assertCorrectLabels(proposals);
buf= new StringBuilder();
@@ -10515,4 +10515,272 @@
assertNumberOfProposals(proposals, 2);
assertProposalExists(proposals, Messages.format(CorrectionMessages.QuickAssistProcessor_create_new_impl, "E.java"));
}
+
+ @Test
+ public void testDoWhileRatherThanWhile1() throws Exception {
+
+ IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+ StringBuilder buf= new StringBuilder();
+ buf.append("package test1;\n");
+ buf.append("public class E {\n");
+ buf.append(" public void replaceWhileByDoWhile(int i) {\n");
+ buf.append(" // Keep this comment\n");
+ buf.append(" while (true) {\n");
+ buf.append(" // Keep this comment too\n");
+ buf.append(" if (i > 100) {\n");
+ buf.append(" return;\n");
+ buf.append(" }\n");
+ buf.append(" i *= 2;\n");
+ buf.append(" }\n");
+ buf.append(" }\n");
+ buf.append("}\n");
+ ICompilationUnit cu= pack1.createCompilationUnit("E.java", buf.toString(), false, null);
+
+ String str= "while (";
+ AssistContext context= getCorrectionContext(cu, buf.toString().indexOf(str), 0);
+ List<IJavaCompletionProposal> proposals= collectAssists(context, false);
+
+ assertCorrectLabels(proposals);
+
+ buf= new StringBuilder();
+ buf.append("package test1;\n");
+ buf.append("public class E {\n");
+ buf.append(" public void replaceWhileByDoWhile(int i) {\n");
+ buf.append(" // Keep this comment\n");
+ buf.append(" do {\n");
+ buf.append(" // Keep this comment too\n");
+ buf.append(" if (i > 100) {\n");
+ buf.append(" return;\n");
+ buf.append(" }\n");
+ buf.append(" i *= 2;\n");
+ buf.append(" } while (true);\n");
+ buf.append(" }\n");
+ buf.append("}\n");
+ String expected1= buf.toString();
+
+ assertExpectedExistInProposals(proposals, new String[] {expected1});
+ }
+
+ @Test
+ public void testDoWhileRatherThanWhile2() throws Exception {
+
+ IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+ StringBuilder buf= new StringBuilder();
+ buf.append("package test1;\n");
+ buf.append("public class E {\n");
+ buf.append(" public void replaceWithInitedBoolean(int i) {\n");
+ buf.append(" boolean isInitedToTrue= true;\n");
+ buf.append("\n");
+ buf.append(" // Keep this comment\n");
+ buf.append(" while (isInitedToTrue) {\n");
+ buf.append(" ); Keep this comment too\n");
+ buf.append(" if (i > 100) {\n");
+ buf.append(" isInitedToTrue= false;\n");
+ buf.append(" }\n");
+ buf.append(" i *= 2;\n");
+ buf.append(" }\n");
+ buf.append(" }\n");
+ buf.append("}\n");
+ ICompilationUnit cu= pack1.createCompilationUnit("E.java", buf.toString(), false, null);
+
+ String str= "while (";
+ AssistContext context= getCorrectionContext(cu, buf.toString().indexOf(str), 0);
+ List<IJavaCompletionProposal> proposals= collectAssists(context, false);
+
+ assertCorrectLabels(proposals);
+
+ buf= new StringBuilder();
+ buf.append("package test1;\n");
+ buf.append("public class E {\n");
+ buf.append(" public void replaceWithInitedBoolean(int i) {\n");
+ buf.append(" boolean isInitedToTrue= true;\n");
+ buf.append("\n");
+ buf.append(" // Keep this comment\n");
+ buf.append(" do {\n");
+ buf.append(" ); Keep this comment too\n");
+ buf.append(" if (i > 100) {\n");
+ buf.append(" isInitedToTrue= false;\n");
+ buf.append(" }\n");
+ buf.append(" i *= 2;\n");
+ buf.append(" } while (isInitedToTrue);\n");
+ buf.append(" }\n");
+ buf.append("}\n");
+ String expected1= buf.toString();
+
+ assertExpectedExistInProposals(proposals, new String[] {expected1});
+ }
+
+ @Test
+ public void testDoWhileRatherThanWhile3() throws Exception {
+
+ IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+ StringBuilder buf= new StringBuilder();
+ buf.append("package test1;\n");
+ buf.append("public class E {\n");
+ buf.append(" public void replaceWithInitedBooleanAndInteger(int i) {\n");
+ buf.append(" int j= 1000;\n");
+ buf.append(" boolean isInitedToTrue= true;\n");
+ buf.append("\n");
+ buf.append(" // Keep this comment\n");
+ buf.append(" while (isInitedToTrue && j > 0) {\n");
+ buf.append(" // Keep this comment too\n");
+ buf.append(" if (i > 100) {\n");
+ buf.append(" isInitedToTrue= false;\n");
+ buf.append(" }\n");
+ buf.append(" i *= 2;\n");
+ buf.append(" j--;\n");
+ buf.append(" }\n");
+ buf.append(" }\n");
+ buf.append("}\n");
+ ICompilationUnit cu= pack1.createCompilationUnit("E.java", buf.toString(), false, null);
+
+ String str= "while (";
+ AssistContext context= getCorrectionContext(cu, buf.toString().indexOf(str), 0);
+ List<IJavaCompletionProposal> proposals= collectAssists(context, false);
+
+ assertCorrectLabels(proposals);
+
+ buf= new StringBuilder();
+ buf.append("package test1;\n");
+ buf.append("public class E {\n");
+ buf.append(" public void replaceWithInitedBooleanAndInteger(int i) {\n");
+ buf.append(" int j= 1000;\n");
+ buf.append(" boolean isInitedToTrue= true;\n");
+ buf.append("\n");
+ buf.append(" // Keep this comment\n");
+ buf.append(" do {\n");
+ buf.append(" // Keep this comment too\n");
+ buf.append(" if (i > 100) {\n");
+ buf.append(" isInitedToTrue= false;\n");
+ buf.append(" }\n");
+ buf.append(" i *= 2;\n");
+ buf.append(" j--;\n");
+ buf.append(" } while (isInitedToTrue && j > 0);\n");
+ buf.append(" }\n");
+ buf.append("}\n");
+ String expected1= buf.toString();
+
+ assertExpectedExistInProposals(proposals, new String[] {expected1});
+ }
+
+ @Test
+ public void testDoWhileRatherThanWhile4() throws Exception {
+
+ IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+ StringBuilder buf= new StringBuilder();
+ buf.append("package test1;\n");
+ buf.append("public class E {\n");
+ buf.append(" public void replaceWithReassignment(int i) {\n");
+ buf.append(" int j= 1000;\n");
+ buf.append(" int k= -1000;\n");
+ buf.append(" boolean isInitedToTrue= false;\n");
+ buf.append(" isInitedToTrue= k < 0;\n");
+ buf.append("\n");
+ buf.append(" // Keep this comment\n");
+ buf.append(" while (isInitedToTrue && j > 0) {\n");
+ buf.append(" // Keep this comment too\n");
+ buf.append(" if (i > 100) {\n");
+ buf.append(" isInitedToTrue= false;\n");
+ buf.append(" }\n");
+ buf.append(" i *= 2;\n");
+ buf.append(" j--;\n");
+ buf.append(" }\n");
+ buf.append(" }\n");
+ buf.append("}\n");
+ ICompilationUnit cu= pack1.createCompilationUnit("E.java", buf.toString(), false, null);
+
+ String str= "while (";
+ AssistContext context= getCorrectionContext(cu, buf.toString().indexOf(str), 0);
+ List<IJavaCompletionProposal> proposals= collectAssists(context, false);
+
+ assertCorrectLabels(proposals);
+
+ buf= new StringBuilder();
+ buf.append("package test1;\n");
+ buf.append("public class E {\n");
+ buf.append(" public void replaceWithReassignment(int i) {\n");
+ buf.append(" int j= 1000;\n");
+ buf.append(" int k= -1000;\n");
+ buf.append(" boolean isInitedToTrue= false;\n");
+ buf.append(" isInitedToTrue= k < 0;\n");
+ buf.append("\n");
+ buf.append(" // Keep this comment\n");
+ buf.append(" do {\n");
+ buf.append(" // Keep this comment too\n");
+ buf.append(" if (i > 100) {\n");
+ buf.append(" isInitedToTrue= false;\n");
+ buf.append(" }\n");
+ buf.append(" i *= 2;\n");
+ buf.append(" j--;\n");
+ buf.append(" } while (isInitedToTrue && j > 0);\n");
+ buf.append(" }\n");
+ buf.append("}\n");
+ String expected1= buf.toString();
+
+ assertExpectedExistInProposals(proposals, new String[] {expected1});
+ }
+
+ @Test
+ public void testDoWhileRatherThanWhile5() throws Exception {
+
+ IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+ StringBuilder buf= new StringBuilder();
+ buf.append("package test1;\n");
+ buf.append("public class E {\n");
+ buf.append(" public void replaceWithInnerWhile(int i) {\n");
+ buf.append(" int j= 1000;\n");
+ buf.append(" int k= -1000;\n");
+ buf.append(" boolean isInitedToTrue= false;\n");
+ buf.append(" isInitedToTrue= k < 0;\n");
+ buf.append("\n");
+ buf.append(" // Keep this comment\n");
+ buf.append(" while (isInitedToTrue && j > 0) {\n");
+ buf.append(" // Keep this comment too\n");
+ buf.append(" while (i < 50 || isInitedToTrue) {\n");
+ buf.append(" ++i;\n");
+ buf.append(" }\n");
+ buf.append(" if (i > 100) {\n");
+ buf.append(" isInitedToTrue= false;\n");
+ buf.append(" }\n");
+ buf.append(" i *= 2;\n");
+ buf.append(" j--;\n");
+ buf.append(" }\n");
+ buf.append(" }\n");
+ buf.append("}\n");
+ ICompilationUnit cu= pack1.createCompilationUnit("E.java", buf.toString(), false, null);
+
+ String str= "while (is";
+ AssistContext context= getCorrectionContext(cu, buf.toString().indexOf(str), 0);
+ List<IJavaCompletionProposal> proposals= collectAssists(context, false);
+
+ assertCorrectLabels(proposals);
+
+ buf= new StringBuilder();
+ buf.append("package test1;\n");
+ buf.append("public class E {\n");
+ buf.append(" public void replaceWithInnerWhile(int i) {\n");
+ buf.append(" int j= 1000;\n");
+ buf.append(" int k= -1000;\n");
+ buf.append(" boolean isInitedToTrue= false;\n");
+ buf.append(" isInitedToTrue= k < 0;\n");
+ buf.append("\n");
+ buf.append(" // Keep this comment\n");
+ buf.append(" do {\n");
+ buf.append(" // Keep this comment too\n");
+ buf.append(" while (i < 50 || isInitedToTrue) {\n");
+ buf.append(" ++i;\n");
+ buf.append(" }\n");
+ buf.append(" if (i > 100) {\n");
+ buf.append(" isInitedToTrue= false;\n");
+ buf.append(" }\n");
+ buf.append(" i *= 2;\n");
+ buf.append(" j--;\n");
+ buf.append(" } while (isInitedToTrue && j > 0);\n");
+ buf.append(" }\n");
+ buf.append("}\n");
+ String expected1= buf.toString();
+
+ assertExpectedExistInProposals(proposals, 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 218b58a..ae8e08f 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
@@ -77,6 +77,7 @@
options.setOption(PREFER_BOOLEAN_LITERAL, CleanUpOptions.FALSE);
options.setOption(SINGLE_USED_FIELD, CleanUpOptions.FALSE);
options.setOption(BREAK_LOOP, CleanUpOptions.FALSE);
+ options.setOption(DO_WHILE_RATHER_THAN_WHILE, CleanUpOptions.TRUE);
options.setOption(STATIC_INNER_CLASS, CleanUpOptions.FALSE);
options.setOption(STRINGBUILDER, CleanUpOptions.FALSE);
options.setOption(STRINGBUFFER_TO_STRINGBUILDER, CleanUpOptions.FALSE);
@@ -253,6 +254,7 @@
options.setOption(PREFER_BOOLEAN_LITERAL, CleanUpOptions.FALSE);
options.setOption(SINGLE_USED_FIELD, CleanUpOptions.FALSE);
options.setOption(BREAK_LOOP, CleanUpOptions.FALSE);
+ options.setOption(DO_WHILE_RATHER_THAN_WHILE, CleanUpOptions.FALSE);
options.setOption(STATIC_INNER_CLASS, CleanUpOptions.FALSE);
options.setOption(STRINGBUILDER, CleanUpOptions.FALSE);
options.setOption(STRINGBUFFER_TO_STRINGBUILDER, CleanUpOptions.FALSE);
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/DoWhileRatherThanWhileFix.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/DoWhileRatherThanWhileFix.java
new file mode 100644
index 0000000..48c18d5
--- /dev/null
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/DoWhileRatherThanWhileFix.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2021 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.WhileStatement;
+
+import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
+
+public class DoWhileRatherThanWhileFix extends CompilationUnitRewriteOperationsFix {
+
+ public static ICleanUpFix createCleanUp(CompilationUnit compilationUnit) {
+ List<CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation> operations= new ArrayList<>();
+ DoWhileRatherThanWhileFixCore.DoWhileRatherThanWhileFinder finder= new DoWhileRatherThanWhileFixCore.DoWhileRatherThanWhileFinder(operations);
+ compilationUnit.accept(finder);
+ if (operations.isEmpty())
+ return null;
+
+ CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] ops= operations.toArray(new CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[operations.size()]);
+ return new DoWhileRatherThanWhileFix(FixMessages.DoWhileRatherThanWhileFix_description, compilationUnit, ops);
+ }
+
+ public static DoWhileRatherThanWhileFix createDoWhileFix(WhileStatement switchStatement) {
+ CompilationUnit root= (CompilationUnit) switchStatement.getRoot();
+ List<CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation> operations= new ArrayList<>();
+ DoWhileRatherThanWhileFixCore.DoWhileRatherThanWhileFinder finder= new DoWhileRatherThanWhileFixCore.DoWhileRatherThanWhileFinder(operations);
+ switchStatement.accept(finder);
+ if (operations.isEmpty())
+ return null;
+ return new DoWhileRatherThanWhileFix(FixMessages.DoWhileRatherThanWhileFix_description, root, new CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] { operations.get(0) });
+ }
+
+ protected DoWhileRatherThanWhileFix(String name, CompilationUnit compilationUnit, CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] fixRewriteOperations) {
+ super(name, compilationUnit, fixRewriteOperations);
+ }
+
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/DoWhileRatherThanWhileCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/DoWhileRatherThanWhileCleanUp.java
new file mode 100644
index 0000000..d5c7fcb
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/DoWhileRatherThanWhileCleanUp.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Fabrice TIERCELIN 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:
+ * Fabrice TIERCELIN - initial API and implementation
+ *******************************************************************************/
+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;
+
+/**
+ * A fix that replaces <code>while</code> by <code>do</code>/<code>while</code>:
+ * <ul>
+ * <li>The first evaluation must be always true.</li>
+ * <li>The first evaluation must be passive.</li>
+ * </ul>
+ */
+public class DoWhileRatherThanWhileCleanUp extends AbstractCleanUp {
+ private DoWhileRatherThanWhileCleanUpCore coreCleanUp= new DoWhileRatherThanWhileCleanUpCore();
+
+ public DoWhileRatherThanWhileCleanUp(final Map<String, String> options) {
+ setOptions(options);
+ }
+
+ public DoWhileRatherThanWhileCleanUp() {
+ }
+
+ @Override
+ public void setOptions(final CleanUpOptions options) {
+ coreCleanUp.setOptions(options);
+ }
+
+ @Override
+ public CleanUpRequirements getRequirements() {
+ return new CleanUpRequirements(coreCleanUp.getRequirementsCore());
+ }
+
+ @Override
+ public ICleanUpFix createFix(final CleanUpContext context) throws CoreException {
+ ICleanUpFixCore fixCore= coreCleanUp.createFixCore(context);
+ return fixCore != null ? new CleanUpFixWrapper(fixCore) : null;
+ }
+
+ @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 456b47b..ec6a29e 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
@@ -84,6 +84,7 @@
public static String OptimizationTabPage_CheckboxName_SingleUsedField;
public static String OptimizationTabPage_CheckboxName_BreakLoop;
+ public static String OptimizationTabPage_CheckboxName_DoWhileRatherThanWhile;
public static String OptimizationTabPage_CheckboxName_StaticInnerClass;
public static String OptimizationTabPage_CheckboxName_StringBuilder;
public static String OptimizationTabPage_CheckboxName_PlainReplacement;
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 666abf6..03f3406 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
@@ -63,6 +63,7 @@
OptimizationTabPage_GroupName_Optimization=Optimization
OptimizationTabPage_CheckboxName_SingleUsedField=Convert fields into local variables if the use is only local
OptimizationTabPage_CheckboxName_BreakLoop=Exit &loop earlier
+OptimizationTabPage_CheckboxName_DoWhileRatherThanWhile=Do/while rather than while
OptimizationTabPage_CheckboxName_StaticInnerClass=Make inner classes static where possible
OptimizationTabPage_CheckboxName_StringBuilder=Replace &String concatenation by StringBuilder
OptimizationTabPage_CheckboxName_PlainReplacement=Use String.replace() instead of String.replaceAll() when possible
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 795039a..35e9048 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
@@ -291,6 +291,7 @@
int INSERT_INFERRED_TYPE_ARGUMENTS_ERROR= 1;
int RETURN_ALLOCATED_OBJECT_VOID= 1;
int CONVERT_TO_IF_RETURN= 1;
+ int DO_WHILE_RATHER_THAN_WHILE= 1;
int CONVERT_TO_MESSAGE_FORMAT= 0;
int COPY_ANNOTATION_JAR= 0;
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 0347d55..b2da09c 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
@@ -165,6 +165,7 @@
import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
import org.eclipse.jdt.internal.corext.fix.ControlStatementsFix;
import org.eclipse.jdt.internal.corext.fix.ConvertLoopFix;
+import org.eclipse.jdt.internal.corext.fix.DoWhileRatherThanWhileFix;
import org.eclipse.jdt.internal.corext.fix.IProposableFix;
import org.eclipse.jdt.internal.corext.fix.LambdaExpressionsFix;
import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel;
@@ -201,6 +202,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.DoWhileRatherThanWhileCleanUp;
import org.eclipse.jdt.internal.ui.fix.LambdaExpressionsCleanUp;
import org.eclipse.jdt.internal.ui.fix.SwitchExpressionsCleanUp;
import org.eclipse.jdt.internal.ui.fix.TypeParametersCleanUp;
@@ -320,6 +322,7 @@
|| getJUnitTestCaseProposal(context, coveringNode, null)
|| getNewImplementationProposal(context, coveringNode, null)
|| getAddStaticImportProposals(context, coveringNode, null)
+ || getDoWhileRatherThanWhileProposal(context, coveringNode, null)
|| getSplitSwitchLabelProposal(context, coveringNode, null);
}
return false;
@@ -389,6 +392,7 @@
getConvertResolvedTypeToVarTypeProposal(context, coveringNode, resultingCollections);
getAddStaticImportProposals(context, coveringNode, resultingCollections);
getConvertToSwitchExpressionProposals(context, coveringNode, resultingCollections);
+ getDoWhileRatherThanWhileProposal(context, coveringNode, resultingCollections);
}
return resultingCollections.toArray(new IJavaCompletionProposal[resultingCollections.size()]);
}
@@ -4359,6 +4363,32 @@
return true;
}
+ private static boolean getDoWhileRatherThanWhileProposal(IInvocationContext context, ASTNode node, Collection<ICommandAccess> resultingCollections) {
+ WhileStatement whileStatement= null;
+ if (node instanceof WhileStatement) {
+ whileStatement= (WhileStatement) node;
+ } else if (node.getParent() instanceof WhileStatement) {
+ whileStatement= (WhileStatement) node.getParent();
+ }
+ if (whileStatement == null)
+ return false;
+
+ if (resultingCollections == null)
+ return true;
+
+ IProposableFix fix= DoWhileRatherThanWhileFix.createDoWhileFix(whileStatement);
+ if (fix == null)
+ return false;
+
+ Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
+ Map<String, String> options= new HashMap<>();
+ options.put(CleanUpConstants.DO_WHILE_RATHER_THAN_WHILE, CleanUpOptions.TRUE);
+ ICleanUp cleanUp= new DoWhileRatherThanWhileCleanUp(options);
+ FixCorrectionProposal proposal= new FixCorrectionProposal(fix, cleanUp, IProposalRelevance.DO_WHILE_RATHER_THAN_WHILE, image, context);
+ resultingCollections.add(proposal);
+ return true;
+ }
+
private static boolean getConvertForLoopProposal(IInvocationContext context, ASTNode node, Collection<ICommandAccess> resultingCollections) {
ForStatement forStatement= getEnclosingForStatementHeader(node);
if (forStatement == null)