From 0a9d2963aeafc9ebe62eae57129677bbdbf02beb Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 24 Mar 2016 11:20:16 +0100 Subject: [PATCH] don't lose precision during constant comparison in dfa (IDEA-153532) --- .../dataFlow/StandardInstructionVisitor.java | 39 +++++++++++-------- .../fixture/InherentNumberRanges.java | 6 +++ 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index 7c0b1f02db92..f3fb5e4c410b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -476,7 +476,7 @@ public class StandardInstructionVisitor extends InstructionVisitor { Object value = ((DfaConstValue)dfaRight).getValue(); if (value instanceof Number) { DfaInstructionState[] result = checkComparingWithConstant(instruction, runner, memState, (DfaVariableValue)dfaLeft, opSign, - ((Number)value).doubleValue()); + (Number)value); if (result != null) { return result; } @@ -508,12 +508,11 @@ public class StandardInstructionVisitor extends InstructionVisitor { DataFlowRunner runner, DfaMemoryState memState, DfaVariableValue var, - IElementType opSign, double comparedWith) { + IElementType opSign, Number comparedWith) { DfaConstValue knownConstantValue = memState.getConstantValue(var); Object knownValue = knownConstantValue == null ? null : knownConstantValue.getValue(); if (knownValue instanceof Number) { - double knownDouble = ((Number)knownValue).doubleValue(); - return checkComparisonWithKnownRange(instruction, runner, memState, opSign, comparedWith, knownDouble, knownDouble); + return checkComparisonWithKnownRange(instruction, runner, memState, opSign, comparedWith, (Number)knownValue, (Number)knownValue); } PsiType varType = var.getVariableType(); @@ -533,28 +532,36 @@ public class StandardInstructionVisitor extends InstructionVisitor { return checkComparisonWithKnownRange(instruction, runner, memState, opSign, comparedWith, minValue, maxValue); } + private static int compare(Number a, Number b) { + long aLong = a.longValue(); + long bLong = b.longValue(); + if (aLong != bLong) return aLong > bLong ? 1 : -1; + + return Double.compare(a.doubleValue(), b.doubleValue()); + } + @Nullable private static DfaInstructionState[] checkComparisonWithKnownRange(BinopInstruction instruction, DataFlowRunner runner, DfaMemoryState memState, IElementType opSign, - double comparedWith, - double rangeMin, - double rangeMax) { - if (comparedWith < rangeMin || comparedWith > rangeMax) { + Number comparedWith, + Number rangeMin, + Number rangeMax) { + if (compare(comparedWith, rangeMin) < 0 || compare(comparedWith, rangeMax) > 0) { if (opSign == EQEQ) return alwaysFalse(instruction, runner, memState); if (opSign == NE) return alwaysTrue(instruction, runner, memState); } - if (opSign == LT && comparedWith <= rangeMin) return alwaysFalse(instruction, runner, memState); - if (opSign == LT && comparedWith > rangeMax) return alwaysTrue(instruction, runner, memState); - if (opSign == LE && comparedWith >= rangeMax) return alwaysTrue(instruction, runner, memState); - if (opSign == LE && comparedWith < rangeMin) return alwaysFalse(instruction, runner, memState); + if (opSign == LT && compare(comparedWith, rangeMin) <= 0) return alwaysFalse(instruction, runner, memState); + if (opSign == LT && compare(comparedWith, rangeMax) > 0) return alwaysTrue(instruction, runner, memState); + if (opSign == LE && compare(comparedWith, rangeMax) >= 0) return alwaysTrue(instruction, runner, memState); + if (opSign == LE && compare(comparedWith, rangeMin) < 0) return alwaysFalse(instruction, runner, memState); - if (opSign == GT && comparedWith >= rangeMax) return alwaysFalse(instruction, runner, memState); - if (opSign == GT && comparedWith < rangeMin) return alwaysTrue(instruction, runner, memState); - if (opSign == GE && comparedWith <= rangeMin) return alwaysTrue(instruction, runner, memState); - if (opSign == GE && comparedWith > rangeMax) return alwaysFalse(instruction, runner, memState); + if (opSign == GT && compare(comparedWith, rangeMax) >= 0) return alwaysFalse(instruction, runner, memState); + if (opSign == GT && compare(comparedWith, rangeMin) < 0) return alwaysTrue(instruction, runner, memState); + if (opSign == GE && compare(comparedWith, rangeMin) <= 0) return alwaysTrue(instruction, runner, memState); + if (opSign == GE && compare(comparedWith, rangeMax) > 0) return alwaysFalse(instruction, runner, memState); return null; } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/InherentNumberRanges.java b/java/java-tests/testData/inspection/dataFlow/fixture/InherentNumberRanges.java index df784c72ca68..064399b9e560 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/InherentNumberRanges.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/InherentNumberRanges.java @@ -22,4 +22,10 @@ class Foo { if (k > Integer.MAX_VALUE); if (k >= Integer.MIN_VALUE); } + + void doo() { + for (long l = Long.MIN_VALUE; l < Long.MIN_VALUE + 10; l++) { + System.out.println(l); + } + } } \ No newline at end of file