IPP: add codeblock when necessary (IDEA-170028)

This commit is contained in:
Bas Leijdekkers
2017-03-24 11:09:38 +01:00
parent bc66eac89f
commit 93e46868cd
7 changed files with 80 additions and 56 deletions
@@ -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;
}
@@ -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<PsiContinueStatement> 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);
}
}
}
@@ -0,0 +1,8 @@
class Continuing {
void testFor() {
<caret>for (int i=0; i<10; i++) {
if(i == 5) continue;
System.out.println(i);
}
}
}
@@ -0,0 +1,13 @@
class Continuing {
void testFor() {
int i=0;
while (i<10) {
if(i == 5) {
i++;
continue;
}
System.out.println(i);
i++;
}
}
}
@@ -0,0 +1,7 @@
class NoInit{
void m(int i) {
<caret>for (; i < 100; i++) {
}
}
}
@@ -0,0 +1,8 @@
class NoInit{
void m(int i) {
while (i < 100) {
i++;
}
}
}
@@ -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() {