mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-209947 CollectionSizeEquality test, better merge, better presentation of two-element ranges
GitOrigin-RevId: 3e12f5cc9f8eaf828b6ec84a393351b9cad8187e
This commit is contained in:
committed by
intellij-monorepo-bot
parent
76b6484215
commit
fb79b6d617
+57
-8
@@ -156,6 +156,11 @@ public class TrackingRunner extends StandardDataFlowRunner {
|
||||
CauseItem[] findCauses(TrackingRunner runner, PsiExpression expression, MemoryStateChange history) {
|
||||
return new CauseItem[0];
|
||||
}
|
||||
|
||||
@Nullable
|
||||
DfaProblemType tryMerge(DfaProblemType other) {
|
||||
return this.toString().equals(other.toString()) ? this : null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CauseItem {
|
||||
@@ -163,6 +168,12 @@ public class TrackingRunner extends StandardDataFlowRunner {
|
||||
final @NotNull DfaProblemType myProblem;
|
||||
final @Nullable SmartPsiFileRange myTarget;
|
||||
|
||||
private CauseItem(@NotNull List<CauseItem> children, @NotNull DfaProblemType problem, @Nullable SmartPsiFileRange target) {
|
||||
myChildren = children;
|
||||
myProblem = problem;
|
||||
myTarget = target;
|
||||
}
|
||||
|
||||
CauseItem(@NotNull String problem, @Nullable PsiElement target) {
|
||||
this(new CustomDfaProblemType(problem), target);
|
||||
}
|
||||
@@ -270,9 +281,17 @@ public class TrackingRunner extends StandardDataFlowRunner {
|
||||
|
||||
public CauseItem merge(CauseItem other) {
|
||||
if (this.equals(other)) return this;
|
||||
if (Objects.equals(this.myTarget, other.myTarget) && getProblemName().equals(other.getProblemName())) {
|
||||
if(tryMergeChildren(other.myChildren)) return this;
|
||||
if(other.tryMergeChildren(this.myChildren)) return other;
|
||||
if (Objects.equals(this.myTarget, other.myTarget)) {
|
||||
if (myChildren.equals(other.myChildren)) {
|
||||
DfaProblemType mergedProblem = myProblem.tryMerge(other.myProblem);
|
||||
if (mergedProblem != null) {
|
||||
return new CauseItem(myChildren, mergedProblem, myTarget);
|
||||
}
|
||||
}
|
||||
if (getProblemName().equals(other.getProblemName())) {
|
||||
if (tryMergeChildren(other.myChildren)) return this;
|
||||
if (other.tryMergeChildren(this.myChildren)) return other;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -350,6 +369,35 @@ public class TrackingRunner extends StandardDataFlowRunner {
|
||||
return myComplete ? "one of the following happens:" : "an execution might exist where:";
|
||||
}
|
||||
}
|
||||
|
||||
static class RangeDfaProblemType extends DfaProblemType {
|
||||
final @NotNull String myTemplate;
|
||||
final @NotNull LongRangeSet myRangeSet;
|
||||
final @Nullable PsiPrimitiveType myType;
|
||||
|
||||
RangeDfaProblemType(@NotNull String template, @NotNull LongRangeSet set, @Nullable PsiPrimitiveType type) {
|
||||
myTemplate = template;
|
||||
myRangeSet = set;
|
||||
myType = type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
DfaProblemType tryMerge(DfaProblemType other) {
|
||||
if (other instanceof RangeDfaProblemType) {
|
||||
RangeDfaProblemType rangeProblem = (RangeDfaProblemType)other;
|
||||
if (myTemplate.equals(rangeProblem.myTemplate) && Objects.equals(myType, rangeProblem.myType)) {
|
||||
return new RangeDfaProblemType(myTemplate, myRangeSet.unite(((RangeDfaProblemType)other).myRangeSet), myType);
|
||||
}
|
||||
}
|
||||
return super.tryMerge(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(myTemplate, myRangeSet.getPresentationText(myType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ValueDfaProblemType extends DfaProblemType {
|
||||
@@ -933,7 +981,7 @@ public class TrackingRunner extends StandardDataFlowRunner {
|
||||
LongRangeSet result = operandRange.castTo((PsiPrimitiveType)type);
|
||||
if (range.equals(result)) {
|
||||
CauseItem cause =
|
||||
new CauseItem("result of '(" + type.getCanonicalText() + ")' cast is " + range.getPresentationText(null), expression);
|
||||
new CauseItem(new RangeDfaProblemType("result of '(" + type.getCanonicalText() + ")' cast is %s", range, null), expression);
|
||||
if (!operandRange.equals(LongRangeSet.fromType(operand.getType()))) {
|
||||
cause.addChildren(findRangeCause(operandPush, castedValue, operandRange, "cast operand is %s"));
|
||||
}
|
||||
@@ -963,8 +1011,9 @@ public class TrackingRunner extends StandardDataFlowRunner {
|
||||
LongRangeSet rightRange = rightSet.getFact(fromType);
|
||||
LongRangeSet result = leftRange.binOpFromToken(binOp.getOperationTokenType(), rightRange, isLong);
|
||||
if (range.equals(result)) {
|
||||
CauseItem cause = new CauseItem("result of '" + binOp.getOperationSign().getText() +
|
||||
"' is " + range.getPresentationText(type), factUse);
|
||||
String sign = binOp.getOperationSign().getText();
|
||||
CauseItem cause = new CauseItem(new RangeDfaProblemType("result of '" + (sign.equals("%")?"%%":sign) + "' is %s",
|
||||
range, ObjectUtils.tryCast(type, PsiPrimitiveType.class)), factUse);
|
||||
CauseItem leftCause = null, rightCause = null;
|
||||
if (!leftRange.equals(fromType)) {
|
||||
leftCause = findRangeCause(leftPush, leftVal, leftRange, "left operand is %s");
|
||||
@@ -979,8 +1028,8 @@ public class TrackingRunner extends StandardDataFlowRunner {
|
||||
}
|
||||
}
|
||||
}
|
||||
String rangeText = range.getPresentationText(expression != null ? expression.getType() : null);
|
||||
CauseItem item = new CauseItem(String.format(template, rangeText), factUse);
|
||||
PsiPrimitiveType type = expression != null ? ObjectUtils.tryCast(expression.getType(), PsiPrimitiveType.class) : null;
|
||||
CauseItem item = new CauseItem(new RangeDfaProblemType(template, range, type), factUse);
|
||||
FactDefinition<LongRangeSet> info = factUse.findFact(value, DfaFactType.RANGE);
|
||||
MemoryStateChange factDef = range.equals(info.myFact) ? info.myChange : null;
|
||||
if (factDef != null) {
|
||||
|
||||
+6
@@ -1258,6 +1258,9 @@ public abstract class LongRangeSet {
|
||||
return ">= " + LongRangeSet.formatNumber(myFrom);
|
||||
}
|
||||
}
|
||||
if (myTo - myFrom == 1) {
|
||||
return myFrom + " or " + myTo;
|
||||
}
|
||||
return "in " + toString();
|
||||
}
|
||||
|
||||
@@ -2006,6 +2009,9 @@ public abstract class LongRangeSet {
|
||||
return "!= " + diff.min();
|
||||
}
|
||||
}
|
||||
if (myRanges.length == 4 && myRanges[0] == myRanges[1] && myRanges[2] == myRanges[3]) {
|
||||
return myRanges[0] + " or " + myRanges[2];
|
||||
}
|
||||
return "in " + toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
/*
|
||||
Value is always false (foo > 3; line#16)
|
||||
One of the following happens:
|
||||
Left operand is 1 (foo; line#16)
|
||||
'foo' was assigned (=; line#15)
|
||||
or left operand is 2 (foo; line#16)
|
||||
'foo' was assigned (=; line#15)
|
||||
Value is always false (foo > 3; line#13)
|
||||
Left operand is 1 or 2 (foo; line#13)
|
||||
'foo' was assigned (=; line#12)
|
||||
*/
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Value is always false (l1 == l2; line#16)
|
||||
Values cannot be equal because l1.size != l2.size
|
||||
Left operand is 0 (l1; line#16)
|
||||
Range is known from line #14 (!l1.isEmpty(); line#14)
|
||||
and right operand is in {3..Integer.MAX_VALUE} (l2; line#16)
|
||||
Range is known from line #15 (l2.size() < 3; line#15)
|
||||
*/
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class Test {
|
||||
void test(List<String> l1, List<String> l2) {
|
||||
if (!l1.isEmpty()) return;
|
||||
if (l2.size() < 3) return;
|
||||
if (<selection>l1 == l2</selection>) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -164,4 +164,5 @@ public class DataFlowInspectionTrackerTest extends LightCodeInsightFixtureTestCa
|
||||
public void testSimpleContract() { doTest(); }
|
||||
public void testSimpleContract2() { doTest(); }
|
||||
public void testEqualsContract() { doTest(); }
|
||||
public void testCollectionSizeEquality() { doTest(); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user