mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-inspections] IDEA-311273 'Explicit array filling' could process a case when array length is a variable
GitOrigin-RevId: cdf0c90b6844a750935198fa1efeb3c8e8af103b
This commit is contained in:
committed by
intellij-monorepo-bot
parent
ab16ae81bc
commit
8edd7f0dd1
+28
-16
@@ -53,10 +53,10 @@ public class ExplicitArrayFillingInspection extends AbstractBaseJavaLocalInspect
|
||||
CountingLoop loop = CountingLoop.from(statement);
|
||||
if (loop == null || loop.isIncluding() || loop.isDescending()) return;
|
||||
if (!ExpressionUtils.isZero(loop.getInitializer())) return;
|
||||
IndexedContainer container = IndexedContainer.fromLengthExpression(loop.getBound());
|
||||
if (container == null || !(container.getQualifier().getType() instanceof PsiArrayType)) return;
|
||||
PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(ControlFlowUtils.stripBraces(statement.getBody()));
|
||||
if (assignment == null) return;
|
||||
IndexedContainer container = getContainer(loop, assignment);
|
||||
if (container == null || !(container.getQualifier().getType() instanceof PsiArrayType)) return;
|
||||
PsiExpression index = container.extractIndexFromGetExpression(assignment.getLExpression());
|
||||
if (!ExpressionUtils.isReferenceTo(index, loop.getCounter())) return;
|
||||
PsiExpression rValue = assignment.getRExpression();
|
||||
@@ -80,7 +80,7 @@ public class ExplicitArrayFillingInspection extends AbstractBaseJavaLocalInspect
|
||||
registerProblem(statement, true);
|
||||
}
|
||||
|
||||
private boolean isChangedInLoop(@NotNull CountingLoop loop, @NotNull PsiExpression rValue) {
|
||||
private static boolean isChangedInLoop(@NotNull CountingLoop loop, @NotNull PsiExpression rValue) {
|
||||
if (VariableAccessUtils.collectUsedVariables(rValue).contains(loop.getCounter()) ||
|
||||
SideEffectChecker.mayHaveSideEffects(rValue)) {
|
||||
return true;
|
||||
@@ -90,7 +90,7 @@ public class ExplicitArrayFillingInspection extends AbstractBaseJavaLocalInspect
|
||||
.anyMatch(call -> !ClassUtils.isImmutable(call.getType()) && !ConstructionUtils.isEmptyArrayInitializer(call));
|
||||
}
|
||||
|
||||
private boolean isDefaultValue(@NotNull PsiExpression expression, @Nullable Object defaultValue, @Nullable PsiType lType) {
|
||||
private static boolean isDefaultValue(@NotNull PsiExpression expression, @Nullable Object defaultValue, @Nullable PsiType lType) {
|
||||
if (ExpressionUtils.isNullLiteral(expression) && defaultValue == null) return true;
|
||||
Object constantValue = ExpressionUtils.computeConstantExpression(expression);
|
||||
PsiType rType = expression.getType();
|
||||
@@ -102,9 +102,9 @@ public class ExplicitArrayFillingInspection extends AbstractBaseJavaLocalInspect
|
||||
return constantValue != null && constantValue.equals(defaultValue);
|
||||
}
|
||||
|
||||
private boolean isFilledWithDefaultValues(@NotNull PsiExpression expression,
|
||||
@NotNull PsiForStatement statement,
|
||||
@Nullable Object defaultValue) {
|
||||
private static boolean isFilledWithDefaultValues(@NotNull PsiExpression expression,
|
||||
@NotNull PsiForStatement statement,
|
||||
@Nullable Object defaultValue) {
|
||||
PsiReferenceExpression arrayRef = tryCast(PsiUtil.skipParenthesizedExprDown(expression), PsiReferenceExpression.class);
|
||||
if (arrayRef == null) return false;
|
||||
PsiVariable arrayVar = tryCast(arrayRef.resolve(), PsiVariable.class);
|
||||
@@ -129,7 +129,7 @@ public class ExplicitArrayFillingInspection extends AbstractBaseJavaLocalInspect
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ControlFlow createControlFlow(@NotNull PsiCodeBlock block) {
|
||||
private static ControlFlow createControlFlow(@NotNull PsiCodeBlock block) {
|
||||
try {
|
||||
return ControlFlowFactory.getInstance(block.getProject())
|
||||
.getControlFlow(block, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance());
|
||||
@@ -139,10 +139,10 @@ public class ExplicitArrayFillingInspection extends AbstractBaseJavaLocalInspect
|
||||
}
|
||||
}
|
||||
|
||||
private PsiElement @Nullable [] getDefs(@NotNull PsiCodeBlock block,
|
||||
@NotNull PsiVariable arrayVar,
|
||||
@NotNull PsiReferenceExpression arrayRef,
|
||||
@Nullable Object defaultValue) {
|
||||
private static PsiElement @Nullable [] getDefs(@NotNull PsiCodeBlock block,
|
||||
@NotNull PsiVariable arrayVar,
|
||||
@NotNull PsiReferenceExpression arrayRef,
|
||||
@Nullable Object defaultValue) {
|
||||
PsiElement[] defs = DefUseUtil.getDefs(block, arrayVar, arrayRef);
|
||||
PsiExpression[] expressions = new PsiExpression[defs.length];
|
||||
for (int i = 0; i < defs.length; i++) {
|
||||
@@ -165,7 +165,7 @@ public class ExplicitArrayFillingInspection extends AbstractBaseJavaLocalInspect
|
||||
return expressions;
|
||||
}
|
||||
|
||||
private boolean isNewArrayCreation(@Nullable PsiExpression expression, @Nullable Object defaultValue) {
|
||||
private static boolean isNewArrayCreation(@Nullable PsiExpression expression, @Nullable Object defaultValue) {
|
||||
PsiExpression arrInitExpr = PsiUtil.skipParenthesizedExprDown(expression);
|
||||
PsiNewExpression newExpression = tryCast(arrInitExpr, PsiNewExpression.class);
|
||||
PsiArrayInitializerExpression initializer;
|
||||
@@ -181,7 +181,7 @@ public class ExplicitArrayFillingInspection extends AbstractBaseJavaLocalInspect
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Set<Integer> getDefsOffsets(@NotNull ControlFlow flow, PsiElement @NotNull [] defs) {
|
||||
private static Set<Integer> getDefsOffsets(@NotNull ControlFlow flow, PsiElement @NotNull [] defs) {
|
||||
Set<Integer> set = new HashSet<>();
|
||||
for (PsiElement def : defs) {
|
||||
int start = flow.getStartOffset(def);
|
||||
@@ -256,10 +256,10 @@ public class ExplicitArrayFillingInspection extends AbstractBaseJavaLocalInspect
|
||||
if (statement == null) return;
|
||||
CountingLoop loop = CountingLoop.from(statement);
|
||||
if (loop == null) return;
|
||||
IndexedContainer container = IndexedContainer.fromLengthExpression(loop.getBound());
|
||||
if (container == null) return;
|
||||
PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(ControlFlowUtils.stripBraces(statement.getBody()));
|
||||
if (assignment == null) return;
|
||||
IndexedContainer container = getContainer(loop, assignment);
|
||||
if (container == null) return;
|
||||
PsiExpression rValue = assignment.getRExpression();
|
||||
if (rValue == null) return;
|
||||
CommentTracker ct = new CommentTracker();
|
||||
@@ -288,4 +288,16 @@ public class ExplicitArrayFillingInspection extends AbstractBaseJavaLocalInspect
|
||||
return TypeConversionUtil.isAssignable(assignTo, rType) ? "" : "(" + elementType.getCanonicalText() + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static IndexedContainer getContainer(CountingLoop loop, PsiAssignmentExpression assignment) {
|
||||
IndexedContainer container = IndexedContainer.fromLengthExpression(loop.getBound());
|
||||
if (container == null) {
|
||||
if (!(assignment.getLExpression() instanceof PsiArrayAccessExpression arrayAccessExpression)) {
|
||||
return null;
|
||||
}
|
||||
container = IndexedContainer.arrayContainerWithBound(arrayAccessExpression, loop.getBound());
|
||||
}
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Remove 'for' statement" "true"
|
||||
|
||||
class Test {
|
||||
|
||||
public static int[] init(int n, boolean b) {
|
||||
int[] data = new int[n];
|
||||
data[n - 1] = 6;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace loop with 'Arrays.setAll()' method call" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
class Test {
|
||||
|
||||
public static Object[] init(int n, boolean b) {
|
||||
Object[] data = new Object[n];
|
||||
Arrays.setAll(data, j -> (j / 2 + n == 0) ? "1" : new Object());
|
||||
return data;
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Remove 'for' statement" "false"
|
||||
|
||||
class Test {
|
||||
|
||||
public static int[] init(int n, boolean b) {
|
||||
int[] data = new int[n];
|
||||
data = new int[n + 1];
|
||||
for (<caret>int j = 0; j < n; j++) {
|
||||
data[j] = 0;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Remove 'for' statement" "true"
|
||||
|
||||
class Test {
|
||||
|
||||
public static int[] init(int n, boolean b) {
|
||||
int[] data = new int[n];
|
||||
for (<caret>int j = 0; j < n; j++) {
|
||||
data[j] = 0;
|
||||
}
|
||||
data[n - 1] = 6;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Replace loop with 'Arrays.setAll()' method call" "true"
|
||||
|
||||
class Test {
|
||||
|
||||
public static Object[] init(int n, boolean b) {
|
||||
Object[] data = new Object[n];
|
||||
for (<caret>int j = 0; j < n; j++) {
|
||||
data[j] = (j / 2 + n == 0) ? "1" : new Object();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Remove 'for' statement" "false"
|
||||
|
||||
class Test {
|
||||
|
||||
public static int[] init(int n, boolean b) {
|
||||
int[] data = new int[n];
|
||||
n = 10;
|
||||
for (<caret>int j = 0; j < n; j++) {
|
||||
data[j] = 0;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
+9
@@ -1032,6 +1032,15 @@ public final class ExpressionUtils {
|
||||
return tryCast(referenceExpression.resolve(), PsiLocalVariable.class);
|
||||
}
|
||||
|
||||
@Contract("null -> null")
|
||||
@Nullable
|
||||
public static PsiVariable resolveVariable(@Nullable PsiExpression expression) {
|
||||
expression = PsiUtil.skipParenthesizedExprDown(expression);
|
||||
PsiReferenceExpression referenceExpression = tryCast(expression, PsiReferenceExpression.class);
|
||||
if(referenceExpression == null) return null;
|
||||
return tryCast(referenceExpression.resolve(), PsiVariable.class);
|
||||
}
|
||||
|
||||
public static boolean isOctalLiteral(PsiLiteralExpression literal) {
|
||||
final PsiType type = literal.getType();
|
||||
if (!PsiType.INT.equals(type) && !PsiType.LONG.equals(type)) {
|
||||
|
||||
+42
@@ -104,6 +104,48 @@ public abstract class IndexedContainer {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to create IndexedContainer for the next case:
|
||||
* <pre>{@code
|
||||
* int[] newArray = new int[arrayLength];
|
||||
* for (int i=0; i < arrayLength; i++) {
|
||||
* newArray[i] = 0;
|
||||
* }
|
||||
* }</pre>
|
||||
* Additionally, the method that newArray and arrayLength are not reassigned
|
||||
*
|
||||
* @param arrayAccessExpression expression to create an IndexedContainer from
|
||||
* @param bound reference to arrayLength
|
||||
* @return newly created IndexedContainer or null if it is impossible to resolve it
|
||||
*/
|
||||
@Nullable
|
||||
public static IndexedContainer arrayContainerWithBound(@NotNull PsiArrayAccessExpression arrayAccessExpression,
|
||||
@NotNull PsiExpression bound) {
|
||||
PsiExpression arrayExpression = arrayAccessExpression.getArrayExpression();
|
||||
if (arrayExpression instanceof PsiReferenceExpression reference &&
|
||||
reference.resolve() instanceof PsiVariable arrayVariable) {
|
||||
PsiExpression initializer = arrayVariable.getInitializer();
|
||||
if (!(initializer instanceof PsiNewExpression newExpression)) {
|
||||
return null;
|
||||
}
|
||||
PsiExpression[] dimensions = newExpression.getArrayDimensions();
|
||||
if (dimensions.length != 1) {
|
||||
return null;
|
||||
}
|
||||
PsiExpression dimension = dimensions[0];
|
||||
PsiVariable dimensionVariable = ExpressionUtils.resolveVariable(dimension);
|
||||
PsiVariable boundVariable = ExpressionUtils.resolveVariable(bound);
|
||||
if (dimensionVariable == null || boundVariable == null || !dimensionVariable.isEquivalentTo(boundVariable)) {
|
||||
return null;
|
||||
}
|
||||
if ((VariableAccessUtils.variableIsAssigned(dimensionVariable)) ||
|
||||
(VariableAccessUtils.variableIsAssigned(arrayVariable))) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return new ArrayIndexedContainer(arrayExpression);
|
||||
}
|
||||
|
||||
static class ArrayIndexedContainer extends IndexedContainer {
|
||||
ArrayIndexedContainer(@NotNull PsiExpression qualifier) {
|
||||
super(qualifier);
|
||||
|
||||
Reference in New Issue
Block a user