mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-inspections] IDEA-282262 Add 'Find the cause' action to 'Redundant operation on empty container' inspection
GitOrigin-RevId: 79f33120532750b5e93ffa3d7ce40c2345d17e39
This commit is contained in:
committed by
intellij-monorepo-bot
parent
97569c0311
commit
ed69cc6401
@@ -491,6 +491,7 @@ dfa.find.cause.call.always.fails=call always fails
|
||||
dfa.find.cause.one.of.the.following.happens=one of the following happens:
|
||||
dfa.find.cause.an.execution.might.exist.where=an execution might exist where:
|
||||
dfa.find.cause.value.is.always.the.same=value is always {0}
|
||||
dfa.find.cause.size.is.always.zero=size is always zero
|
||||
dfa.find.cause.value.x.is.always.the.same=value ''{0}'' is always ''{1}''
|
||||
dfa.find.cause.compile.time.constant=it''s compile-time constant which evaluates to ''{0}''
|
||||
dfa.find.cause.equality.established.from.condition=''{0}'' was established from condition
|
||||
|
||||
+25
-4
@@ -533,6 +533,27 @@ public final class TrackingRunner extends StandardDataFlowRunner {
|
||||
}
|
||||
}
|
||||
|
||||
public static class ZeroSizeDfaProblemType extends DfaProblemType {
|
||||
final SpecialField myField;
|
||||
|
||||
public ZeroSizeDfaProblemType(@NotNull SpecialField field) {
|
||||
myField = field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CauseItem[] findCauses(TrackingRunner runner, PsiExpression expression, MemoryStateChange history) {
|
||||
DfaValue topOfStack = history.myTopOfStack;
|
||||
DfaValue value = myField.createValue(runner.getFactory(), topOfStack);
|
||||
MemoryStateChange change = MemoryStateChange.create(history, new JvmPushInstruction(value, null), Map.of(), value);
|
||||
return runner.findConstantValueCause(expression, change, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JavaAnalysisBundle.message("dfa.find.cause.size.is.always.zero");
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomDfaProblemType extends DfaProblemType {
|
||||
private final @Nls String myMessage;
|
||||
|
||||
@@ -546,7 +567,7 @@ public final class TrackingRunner extends StandardDataFlowRunner {
|
||||
}
|
||||
}
|
||||
|
||||
private CauseItem @NotNull [] findConstantValueCause(PsiExpression expression, MemoryStateChange history, Object expectedValue) {
|
||||
private CauseItem @NotNull [] findConstantValueCause(@Nullable PsiExpression expression, MemoryStateChange history, Object expectedValue) {
|
||||
if (expression instanceof PsiLiteralExpression) return new CauseItem[0];
|
||||
Object constantExpressionValue = ExpressionUtils.computeConstantExpression(expression);
|
||||
DfaValue value = history.myTopOfStack;
|
||||
@@ -554,7 +575,7 @@ public final class TrackingRunner extends StandardDataFlowRunner {
|
||||
return new CauseItem[]{new CauseItem(JavaAnalysisBundle.message("dfa.find.cause.compile.time.constant", value), expression)};
|
||||
}
|
||||
Boolean boolConst = value.getDfType().getConstantOfType(Boolean.class);
|
||||
if (boolConst != null && boolConst.equals(expectedValue)) {
|
||||
if (boolConst != null && expression != null && boolConst.equals(expectedValue)) {
|
||||
return findBooleanResultCauses(expression, history, boolConst);
|
||||
}
|
||||
if (value instanceof DfaVariableValue) {
|
||||
@@ -618,8 +639,8 @@ public final class TrackingRunner extends StandardDataFlowRunner {
|
||||
return new CauseItem(message, anchor);
|
||||
}
|
||||
|
||||
private CauseItem[] findBooleanResultCauses(PsiExpression expression,
|
||||
MemoryStateChange history,
|
||||
private CauseItem[] findBooleanResultCauses(@NotNull PsiExpression expression,
|
||||
@NotNull MemoryStateChange history,
|
||||
boolean value) {
|
||||
if (BoolUtils.isNegation(expression)) {
|
||||
PsiExpression negated = BoolUtils.getNegated(expression);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
Size is always zero (map.entrySet(); line#10)
|
||||
'map.size == 0' was established from condition (map.isEmpty(); line#9)
|
||||
*/
|
||||
import java.util.*;
|
||||
|
||||
public class EmptyCollectionSimple {
|
||||
void test(Map<String, Integer> map) {
|
||||
if (map.isEmpty()) {
|
||||
for(var e : <selection>map.entrySet()</selection>) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -4,6 +4,7 @@ package com.intellij.java.codeInspection;
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.codeInspection.dataFlow.CommonDataflow;
|
||||
import com.intellij.codeInspection.dataFlow.TrackingRunner;
|
||||
import com.intellij.codeInspection.dataFlow.jvm.SpecialField;
|
||||
import com.intellij.openapi.editor.SelectionModel;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -93,6 +94,10 @@ public class DataFlowInspectionTrackerTest extends LightJavaCodeInsightFixtureTe
|
||||
return new TrackingRunner.CastDfaProblemType();
|
||||
}
|
||||
PsiElement parent = expression.getParent();
|
||||
if (parent instanceof PsiForeachStatement) {
|
||||
return new TrackingRunner.ZeroSizeDfaProblemType(
|
||||
expression.getType() instanceof PsiArrayType ? SpecialField.ARRAY_LENGTH : SpecialField.COLLECTION_SIZE);
|
||||
}
|
||||
if (parent instanceof PsiReferenceExpression) {
|
||||
// Test possible NPE in qualifiers only
|
||||
return new TrackingRunner.NullableDfaProblemType();
|
||||
@@ -191,4 +196,5 @@ public class DataFlowInspectionTrackerTest extends LightJavaCodeInsightFixtureTe
|
||||
public void testSubStringEqualsIgnoreCase() { doTest(); }
|
||||
public void testSubStringEqualsIgnoreCase2() { doTest(); }
|
||||
public void testArrayBlockingQueueContract() { doTest(); }
|
||||
public void testEmptyCollectionSimple() { doTest(); }
|
||||
}
|
||||
|
||||
+17
-2
@@ -6,6 +6,8 @@ import com.intellij.codeInspection.AbstractBaseJavaLocalInspectionTool;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.codeInspection.dataFlow.CommonDataflow;
|
||||
import com.intellij.codeInspection.dataFlow.TrackingRunner;
|
||||
import com.intellij.codeInspection.dataFlow.fix.FindDfaProblemCauseFix;
|
||||
import com.intellij.codeInspection.dataFlow.jvm.SpecialField;
|
||||
import com.intellij.codeInspection.dataFlow.types.DfType;
|
||||
import com.intellij.codeInspection.util.InspectionMessage;
|
||||
@@ -70,7 +72,7 @@ public class RedundantOperationOnEmptyContainerInspection extends AbstractBaseJa
|
||||
if (ExpressionUtils.isVoidContext(call)) {
|
||||
fix = new DeleteElementFix(call, InspectionGadgetsBundle.message("remove.call.fix.family.name"));
|
||||
}
|
||||
holder.registerProblem(container, msg, fix);
|
||||
holder.registerProblem(container, msg, fix, getFindCauseFix(container));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +82,20 @@ public class RedundantOperationOnEmptyContainerInspection extends AbstractBaseJa
|
||||
if (value == null) return;
|
||||
String msg = getProblemMessage(value);
|
||||
if (msg == null) return;
|
||||
holder.registerProblem(value, msg, new DeleteElementFix(statement, InspectionGadgetsBundle.message("remove.loop.fix.family.name")));
|
||||
holder.registerProblem(value, msg,
|
||||
new DeleteElementFix(statement, InspectionGadgetsBundle.message("remove.loop.fix.family.name")),
|
||||
getFindCauseFix(value));
|
||||
}
|
||||
|
||||
private @NotNull LocalQuickFix getFindCauseFix(@NotNull PsiExpression value) {
|
||||
PsiType type = value.getType();
|
||||
SpecialField field;
|
||||
if (type instanceof PsiArrayType) {
|
||||
field = SpecialField.ARRAY_LENGTH;
|
||||
} else {
|
||||
field = SpecialField.COLLECTION_SIZE;
|
||||
}
|
||||
return new FindDfaProblemCauseFix(false, value, new TrackingRunner.ZeroSizeDfaProblemType(field));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
Reference in New Issue
Block a user