diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/BlockUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/BlockUtils.java index a19880de2462..a0a002f9d46a 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/BlockUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/BlockUtils.java @@ -21,31 +21,38 @@ import com.intellij.psi.*; * @author Tagir Valeev */ public class BlockUtils { + /** - * Add new statement before given anchor statement creating code block, if necessary + * Adds new statements before given anchor statement creating a new code block, if necessary * - * @param anchor existing statement - * @param newStatement a new statement which should be added before an existing one - * @return added physical statement + * @param anchor existing statement + * @param newStatements the new statements which should be added before the existing one + * @return last added physical statement */ - public static PsiStatement addBefore(PsiStatement anchor, PsiStatement newStatement) { + public static PsiStatement addBefore(PsiStatement anchor, PsiStatement... newStatements) { + if (newStatements.length == 0) throw new IllegalArgumentException(); PsiElement oldStatement = anchor; PsiElement parent = oldStatement.getParent(); while (parent instanceof PsiLabeledStatement) { oldStatement = parent; parent = oldStatement.getParent(); } - final PsiElement result; + PsiElement result = null; if (parent instanceof PsiCodeBlock) { - result = parent.addBefore(newStatement, oldStatement); + for (PsiStatement statement : newStatements) { + result = parent.addBefore(statement, oldStatement); + } } else { - PsiElementFactory factory = JavaPsiFacade.getElementFactory(anchor.getProject()); + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(anchor.getProject()); final PsiBlockStatement newBlockStatement = (PsiBlockStatement)factory.createStatementFromText("{}", oldStatement); final PsiElement codeBlock = newBlockStatement.getCodeBlock(); - codeBlock.add(newStatement); + for (PsiStatement newStatement : newStatements) { + codeBlock.add(newStatement); + } codeBlock.add(oldStatement); - result = ((PsiBlockStatement)oldStatement.replace(newBlockStatement)).getCodeBlock().getStatements()[0]; + final PsiStatement[] statements = ((PsiBlockStatement)oldStatement.replace(newBlockStatement)).getCodeBlock().getStatements(); + result = statements[statements.length - 2]; } return (PsiStatement)result; } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntention.java index 1d1630596908..986bbbb3ac4a 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntention.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2016 Bas Leijdekkers + * Copyright 2006-2017 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,14 @@ package com.siyeh.ipp.forloop; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.siyeh.ig.psiutils.BlockUtils; import com.siyeh.ipp.base.Intention; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NotNull; +import java.util.Collection; + public class ReplaceForLoopWithWhileLoopIntention extends Intention { @Override @@ -40,7 +43,6 @@ public class ReplaceForLoopWithWhileLoopIntention extends Intention { final PsiWhileStatement whileStatement = (PsiWhileStatement)factory.createStatementFromText("while(true) {}", element); final PsiExpression forCondition = forStatement.getCondition(); final PsiExpression whileCondition = whileStatement.getCondition(); - final PsiStatement body = forStatement.getBody(); if (forCondition != null) { assert whileCondition != null; whileCondition.replace(forCondition); @@ -49,17 +51,18 @@ public class ReplaceForLoopWithWhileLoopIntention extends Intention { if (blockStatement == null) { return; } - final PsiElement newBody; - if (body instanceof PsiBlockStatement) { - final PsiBlockStatement newWhileBody = (PsiBlockStatement)blockStatement.replace(body); - newBody = newWhileBody.getCodeBlock(); + final PsiStatement forStatementBody = forStatement.getBody(); + final PsiElement loopBody; + if (forStatementBody instanceof PsiBlockStatement) { + final PsiBlockStatement newWhileBody = (PsiBlockStatement)blockStatement.replace(forStatementBody); + loopBody = newWhileBody.getCodeBlock(); } else { final PsiCodeBlock codeBlock = blockStatement.getCodeBlock(); - if (body != null && !(body instanceof PsiEmptyStatement)) { - codeBlock.addAfter(body, codeBlock.getFirstChild()); + if (forStatementBody != null && !(forStatementBody instanceof PsiEmptyStatement)) { + codeBlock.add(forStatementBody); } - newBody = codeBlock; + loopBody = codeBlock; } final PsiStatement update = forStatement.getUpdate(); if (update != null) { @@ -69,53 +72,29 @@ public class ReplaceForLoopWithWhileLoopIntention extends Intention { final PsiExpressionList expressionList = expressionListStatement.getExpressionList(); final PsiExpression[] expressions = expressionList.getExpressions(); updateStatements = new PsiStatement[expressions.length]; - for (int i = 0, expressionsLength = expressions.length; i < expressionsLength; i++) { - final PsiExpression expression = expressions[i]; - final PsiStatement updateStatement = factory.createStatementFromText(expression.getText() + ';', element); - updateStatements[i] = updateStatement; + for (int i = 0; i < expressions.length; i++) { + updateStatements[i] = factory.createStatementFromText(expressions[i].getText() + ';', element); } } else { final PsiStatement updateStatement = factory.createStatementFromText(update.getText() + ';', element); updateStatements = new PsiStatement[]{updateStatement}; } - newBody.accept(new UpdateInserter(whileStatement, updateStatements)); + final Collection continueStatements = PsiTreeUtil.findChildrenOfType(loopBody, PsiContinueStatement.class); + for (PsiContinueStatement continueStatement : continueStatements) { + BlockUtils.addBefore(continueStatement, updateStatements); + } for (PsiStatement updateStatement : updateStatements) { - newBody.addBefore(updateStatement, newBody.getLastChild()); + loopBody.addBefore(updateStatement, loopBody.getLastChild()); } } if (initialization == null || initialization instanceof PsiEmptyStatement) { - return; + forStatement.replace(whileStatement); } - initialization = (PsiStatement)initialization.copy(); - PsiElement newElement = forStatement.replace(whileStatement); - BlockUtils.addBefore((PsiStatement)newElement, initialization); - } - - private static class UpdateInserter extends JavaRecursiveElementWalkingVisitor { - - private final PsiWhileStatement whileStatement; - private final PsiStatement[] updateStatements; - - private UpdateInserter(PsiWhileStatement whileStatement, PsiStatement[] updateStatements) { - this.whileStatement = whileStatement; - this.updateStatements = updateStatements; - } - - @Override - public void visitContinueStatement(PsiContinueStatement statement) { - final PsiStatement continuedStatement = statement.findContinuedStatement(); - if (!whileStatement.equals(continuedStatement)) { - return; - } - final PsiElement parent = statement.getParent(); - if (parent == null) { - return; - } - for (PsiStatement updateStatement : updateStatements) { - parent.addBefore(updateStatement, statement); - } - super.visitContinueStatement(statement); + else { + initialization = (PsiStatement)initialization.copy(); + final PsiStatement newStatement = (PsiStatement)forStatement.replace(whileStatement); + BlockUtils.addBefore(newStatement, initialization); } } } \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/Continuing.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/Continuing.java new file mode 100644 index 000000000000..2925e6ef71e6 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/Continuing.java @@ -0,0 +1,8 @@ +class Continuing { + void testFor() { + for (int i=0; i<10; i++) { + if(i == 5) continue; + System.out.println(i); + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/Continuing_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/Continuing_after.java new file mode 100644 index 000000000000..fa6b9cbcc70c --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/Continuing_after.java @@ -0,0 +1,13 @@ +class Continuing { + void testFor() { + int i=0; + while (i<10) { + if(i == 5) { + i++; + continue; + } + System.out.println(i); + i++; + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/NoInit.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/NoInit.java new file mode 100644 index 000000000000..b7a7fcbf3788 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/NoInit.java @@ -0,0 +1,7 @@ +class NoInit{ + void m(int i) { + for (; i < 100; i++) { + + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/NoInit_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/NoInit_after.java new file mode 100644 index 000000000000..8146d187862f --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/NoInit_after.java @@ -0,0 +1,8 @@ +class NoInit{ + void m(int i) { + while (i < 100) { + + i++; + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntentionTest.java index ed9a294443c0..c3f803d7433e 100644 --- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntentionTest.java +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntentionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,8 @@ public class ReplaceForLoopWithWhileLoopIntentionTest extends IPPTestCase { public void testNotInBlock() { doTest(); } public void testDoubleLabelNoBraces() { doTest(); } public void testUpdatingMuch() { doTest(); } + public void testContinuing() { doTest(); } + public void testNoInit() { doTest(); } @Override protected String getIntentionName() {