[java-intentions] IDEA-331850 Support 'Unroll Loop' intention when there are declarations in a loop

GitOrigin-RevId: 5fa9904997f3eade008dae8278ffc44dd0e9172d
This commit is contained in:
Tagir Valeev
2023-09-18 11:42:55 +00:00
committed by intellij-monorepo-bot
parent ce7ea33a0a
commit bdc4c6c8c1
7 changed files with 90 additions and 9 deletions
@@ -62,7 +62,6 @@ public class UnrollLoopAction extends PsiUpdateModCommandAction<PsiLoopStatement
}
PsiStatement[] statements = ControlFlowUtils.unwrapBlock(body);
if (statements.length == 0) return null;
if (ContainerUtil.exists(statements, PsiDeclarationStatement.class::isInstance)) return null;
if (VariableAccessUtils.variableIsAssigned(iterationParameter, body)) return null;
for (PsiStatement statement : statements) {
if (isLoopBreak(statement)) continue;
@@ -193,7 +192,7 @@ public class UnrollLoopAction extends PsiUpdateModCommandAction<PsiLoopStatement
@Override
protected void invoke(@NotNull ActionContext context, @NotNull PsiLoopStatement loop, @NotNull ModPsiUpdater updater) {
if (!(loop.getParent() instanceof PsiCodeBlock)) return;
if (!(loop.getParent() instanceof PsiCodeBlock parentBlock)) return;
List<PsiExpression> expressions = extractExpressions(loop);
if (expressions.isEmpty()) return;
Project project = context.project();
@@ -215,14 +214,19 @@ public class UnrollLoopAction extends PsiUpdateModCommandAction<PsiLoopStatement
PsiElement[] children;
if (body instanceof PsiBlockStatement) {
PsiCodeBlock block = ((PsiBlockStatement)Objects.requireNonNull(loop.getBody())).getCodeBlock();
PsiElement firstBodyElement = block.getFirstBodyElement();
PsiElement lastBodyElement = block.getLastBodyElement();
if (firstBodyElement != null && lastBodyElement != null) {
ct.markRangeUnchanged(firstBodyElement, lastBodyElement);
if (canUnwrapBlock(block, parentBlock, expressions)) {
PsiElement firstBodyElement = block.getFirstBodyElement();
PsiElement lastBodyElement = block.getLastBodyElement();
if (firstBodyElement != null && lastBodyElement != null) {
ct.markRangeUnchanged(firstBodyElement, lastBodyElement);
}
children = ((PsiBlockStatement)body).getCodeBlock().getChildren();
// Skip {braces}
children = Arrays.copyOfRange(children, 1, children.length-1);
} else {
ct.markUnchanged(loop.getBody());
children = new PsiElement[]{body};
}
children = ((PsiBlockStatement)body).getCodeBlock().getChildren();
// Skip {braces}
children = Arrays.copyOfRange(children, 1, children.length-1);
} else {
ct.markUnchanged(loop.getBody());
children = new PsiElement[]{body};
@@ -247,6 +251,25 @@ public class UnrollLoopAction extends PsiUpdateModCommandAction<PsiLoopStatement
ct.deleteAndRestoreComments(loop);
}
private static boolean canUnwrapBlock(@NotNull PsiCodeBlock block, PsiCodeBlock parentBlock, List<PsiExpression> expressions) {
for (PsiStatement statement : block.getStatements()) {
if (statement instanceof PsiDeclarationStatement declaration) {
if (expressions.size() > 1) return false;
for (PsiElement element : declaration.getDeclaredElements()) {
if (element instanceof PsiVariable variable) {
String name = variable.getName();
if (name != null) {
if (PsiResolveHelper.getInstance(block.getProject()).resolveReferencedVariable(name, parentBlock) != null) {
return false;
}
}
}
}
}
}
return true;
}
private static boolean isLoopBreak(PsiStatement statement) {
if (!(statement instanceof PsiIfStatement ifStatement)) return false;
if (ifStatement.getElseBranch() != null || ifStatement.getCondition() == null) return false;
@@ -0,0 +1,10 @@
// "Unroll loop" "true-preview"
class X {
void test() {
{
int y = 1 + 1;
System.out.println(y);
}
int y = 2;
}
}
@@ -0,0 +1,7 @@
// "Unroll loop" "true-preview"
class X {
void test() {
int y = 1 + 1;
System.out.println(y);
}
}
@@ -0,0 +1,13 @@
// "Unroll loop" "true-preview"
class X {
void test() {
{
int y = 1 + 1;
System.out.println(y);
}
{
int y = 2 + 1;
System.out.println(y);
}
}
}
@@ -0,0 +1,10 @@
// "Unroll loop" "true-preview"
class X {
void test() {
<caret>for (int x : new int[]{1}) {
int y = x + 1;
System.out.println(y);
}
int y = 2;
}
}
@@ -0,0 +1,9 @@
// "Unroll loop" "true-preview"
class X {
void test() {
<caret>for (int x : new int[]{1}) {
int y = x + 1;
System.out.println(y);
}
}
}
@@ -0,0 +1,9 @@
// "Unroll loop" "true-preview"
class X {
void test() {
<caret>for (int x : new int[]{1, 2}) {
int y = x + 1;
System.out.println(y);
}
}
}