IDEA-243019 Unroll loop: get loop size from dataflow

GitOrigin-RevId: 0ba4a16c098414fcb539502446b6cd138922f398
This commit is contained in:
Tagir Valeev
2020-06-10 10:23:45 +07:00
committed by intellij-monorepo-bot
parent 7bef713cfd
commit c180e2cec5
7 changed files with 132 additions and 3 deletions

View File

@@ -2,12 +2,18 @@
package com.intellij.codeInsight.intention.impl;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.codeInspection.dataFlow.CommonDataflow;
import com.intellij.codeInspection.dataFlow.SpecialField;
import com.intellij.codeInspection.dataFlow.types.DfConstantType;
import com.intellij.codeInspection.dataFlow.types.DfType;
import com.intellij.java.JavaBundle;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiPrecedenceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.util.InlineUtil;
@@ -104,16 +110,59 @@ public class UnrollLoopAction extends PsiElementBaseIntentionAction {
}
}
}
if (ExpressionUtils.isSafelyRecomputableExpression(expression)) {
PsiType type = expression.getType();
if (type instanceof PsiArrayType) {
DfType dfType = CommonDataflow.getDfType(expression);
Integer arraySize = DfConstantType.getConstantOfType(SpecialField.ARRAY_LENGTH.getFromQualifier(dfType), Integer.class);
if (arraySize != null) {
PsiElementFactory factory = JavaPsiFacade.getElementFactory(loop.getProject());
PsiExpression array = expression;
return new AbstractList<PsiExpression>() {
@Override
public PsiExpression get(int index) {
return factory.createExpressionFromText(ParenthesesUtils.getText(array, PsiPrecedenceUtil.POSTFIX_PRECEDENCE)
+"["+index+"]", loop);
}
@Override
public int size() {
return arraySize;
}
};
}
}
if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_LIST)) {
DfType dfType = CommonDataflow.getDfType(expression);
Integer listSize = DfConstantType.getConstantOfType(SpecialField.COLLECTION_SIZE.getFromQualifier(dfType), Integer.class);
if (listSize != null) {
PsiElementFactory factory = JavaPsiFacade.getElementFactory(loop.getProject());
PsiExpression array = expression;
return new AbstractList<PsiExpression>() {
@Override
public PsiExpression get(int index) {
return factory.createExpressionFromText(ParenthesesUtils.getText(array, PsiPrecedenceUtil.METHOD_CALL_PRECEDENCE)
+".get("+index+")", loop);
}
@Override
public int size() {
return listSize;
}
};
}
}
}
}
if (loop instanceof PsiForStatement) {
CountingLoop countingLoop = CountingLoop.from((PsiForStatement)loop);
if (countingLoop != null) {
boolean descending = countingLoop.isDescending();
long multiplier = descending ? -1 : 1;
Object from = ExpressionUtils.computeConstantExpression(countingLoop.getInitializer());
Object from = CommonDataflow.computeValue(countingLoop.getInitializer());
if (!(from instanceof Integer) && !(from instanceof Long)) return Collections.emptyList();
long fromValue = ((Number)from).longValue();
Object to = ExpressionUtils.computeConstantExpression(countingLoop.getBound());
Object to = CommonDataflow.computeValue(countingLoop.getBound());
if (!(to instanceof Integer) && !(to instanceof Long)) return Collections.emptyList();
long toValue = ((Number)to).longValue();
long diff = multiplier * (toValue - fromValue);
@@ -200,7 +249,7 @@ public class UnrollLoopAction extends PsiElementBaseIntentionAction {
if (loop instanceof PsiForeachStatement) {
PsiExpression iteratedValue = ((PsiForeachStatement)loop).getIteratedValue();
PsiLocalVariable variable = ExpressionUtils.resolveLocalVariable(iteratedValue);
if (variable != null) ct.delete(variable);
if (variable != null && PsiTreeUtil.isAncestor(variable, expressions.get(0), true)) ct.delete(variable);
}
ct.deleteAndRestoreComments(loop);
}

View File

@@ -0,0 +1,19 @@
// "Unroll loop" "true"
import java.util.Arrays;
class X {
void test() {
int[] array = new int[10];
Arrays.setAll(array, i -> i);
System.out.println(array[0]);
System.out.println(array[1]);
System.out.println(array[2]);
System.out.println(array[3]);
System.out.println(array[4]);
System.out.println(array[5]);
System.out.println(array[6]);
System.out.println(array[7]);
System.out.println(array[8]);
System.out.println(array[9]);
}
}

View File

@@ -0,0 +1,14 @@
// "Unroll loop" "true"
import java.util.Arrays;
class X {
void testLoop(int size) {
if (size == 5) {
System.out.println(0);
System.out.println(1);
System.out.println(2);
System.out.println(3);
System.out.println(4);
}
}
}

View File

@@ -0,0 +1,11 @@
// "Unroll loop" "true"
import java.util.List;
class X {
void testList(List<String> list) {
if (list.size() == 2) {
System.out.println(list.get(0));
System.out.println(list.get(1));
}
}
}

View File

@@ -0,0 +1,12 @@
// "Unroll loop" "true"
import java.util.Arrays;
class X {
void test() {
int[] array = new int[10];
Arrays.setAll(array, i -> i);
<caret>for (int i : array) {
System.out.println(i);
}
}
}

View File

@@ -0,0 +1,12 @@
// "Unroll loop" "true"
import java.util.Arrays;
class X {
void testLoop(int size) {
if (size == 5) {
<caret>for (int i = 0; i < size; i++) {
System.out.println(i);
}
}
}
}

View File

@@ -0,0 +1,12 @@
// "Unroll loop" "true"
import java.util.List;
class X {
void testList(List<String> list) {
if (list.size() == 2) {
<caret>for (String s : list) {
System.out.println(s);
}
}
}
}