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 be70ba0e4328..784db54634a5 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
@@ -310,7 +310,7 @@ public class StandardInstructionVisitor extends InstructionVisitor {
final IElementType opSign = instruction.getOperationSign();
if (opSign != null) {
- DfaInstructionState[] states = handleConstantComparison(instruction, runner, memState, dfaRight, dfaLeft);
+ DfaInstructionState[] states = handleConstantComparison(instruction, runner, memState, dfaRight, dfaLeft, opSign);
if (states == null) {
states = handleRelationBinop(instruction, runner, memState, dfaRight, dfaLeft);
}
@@ -422,8 +422,21 @@ public class StandardInstructionVisitor extends InstructionVisitor {
DataFlowRunner runner,
DfaMemoryState memState,
DfaValue dfaRight,
- DfaValue dfaLeft) {
- final IElementType opSign = instruction.getOperationSign();
+ DfaValue dfaLeft, IElementType opSign) {
+ if (dfaRight instanceof DfaConstValue && dfaLeft instanceof DfaVariableValue) {
+ PsiType varType = ((DfaVariableValue)dfaLeft).getVariableType();
+ Object value = ((DfaConstValue)dfaRight).getValue();
+ if (varType instanceof PsiPrimitiveType && value instanceof Number) {
+ DfaInstructionState[] result = checkTypeRanges(instruction, runner, memState, opSign, varType, ((Number)value).longValue());
+ if (result != null) {
+ return result;
+ }
+ }
+ }
+ if (dfaRight instanceof DfaVariableValue && dfaLeft instanceof DfaConstValue) {
+ return handleConstantComparison(instruction, runner, memState, dfaLeft, dfaRight, DfaRelationValue.getSymmetricOperation(opSign));
+ }
+
if (EQEQ != opSign && NE != opSign ||
!(dfaLeft instanceof DfaConstValue) || !(dfaRight instanceof DfaConstValue)) {
return null;
@@ -431,13 +444,49 @@ public class StandardInstructionVisitor extends InstructionVisitor {
boolean negated = (NE == opSign) ^ (DfaMemoryStateImpl.isNaN(dfaLeft) || DfaMemoryStateImpl.isNaN(dfaRight));
if (dfaLeft == dfaRight ^ negated) {
- memState.push(runner.getFactory().getConstFactory().getTrue());
- instruction.setTrueReachable();
+ return alwaysTrue(instruction, runner, memState);
}
- else {
- memState.push(runner.getFactory().getConstFactory().getFalse());
- instruction.setFalseReachable();
+ return alwaysFalse(instruction, runner, memState);
+ }
+
+ private static DfaInstructionState[] checkTypeRanges(BinopInstruction instruction,
+ DataFlowRunner runner,
+ DfaMemoryState memState,
+ IElementType opSign, PsiType varType, long constantValue) {
+ long minValue = varType == PsiType.BYTE ? Byte.MIN_VALUE :
+ varType == PsiType.SHORT ? Short.MIN_VALUE :
+ varType == PsiType.INT ? Integer.MIN_VALUE :
+ varType == PsiType.CHAR ? Character.MIN_VALUE :
+ Long.MIN_VALUE;
+ long maxValue = varType == PsiType.BYTE ? Byte.MAX_VALUE :
+ varType == PsiType.SHORT ? Short.MAX_VALUE :
+ varType == PsiType.INT ? Integer.MAX_VALUE :
+ varType == PsiType.CHAR ? Character.MAX_VALUE :
+ Long.MAX_VALUE;
+
+ if (constantValue < minValue || constantValue > maxValue) {
+ if (opSign == EQEQ) return alwaysFalse(instruction, runner, memState);
+ if (opSign == NE) return alwaysTrue(instruction, runner, memState);
}
+
+ if (opSign == LT && constantValue <= minValue) return alwaysFalse(instruction, runner, memState);
+ if ((opSign == LT || opSign == LE) && constantValue > maxValue) return alwaysTrue(instruction, runner, memState);
+
+ if (opSign == GT && constantValue >= maxValue) return alwaysFalse(instruction, runner, memState);
+ if ((opSign == GT || opSign == GE) && constantValue < minValue) return alwaysTrue(instruction, runner, memState);
+
+ return null;
+ }
+
+ private static DfaInstructionState[] alwaysFalse(BinopInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
+ memState.push(runner.getFactory().getConstFactory().getFalse());
+ instruction.setFalseReachable();
+ return nextInstruction(instruction, runner, memState);
+ }
+
+ private static DfaInstructionState[] alwaysTrue(BinopInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
+ memState.push(runner.getFactory().getConstFactory().getTrue());
+ instruction.setTrueReachable();
return nextInstruction(instruction, runner, memState);
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java
index c3593f6eca21..8343fc9e6a2c 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java
@@ -114,13 +114,14 @@ public class DfaRelationValue extends DfaValue {
return result;
}
- private static IElementType getSymmetricOperation(IElementType sign) {
- if (LT == sign) return GT;
- if (GE == sign) return LE;
- if (GT == sign) return LT;
- if (LE == sign) return GE;
- return sign;
- }
+ }
+
+ public static IElementType getSymmetricOperation(IElementType sign) {
+ if (LT == sign) return GT;
+ if (GE == sign) return LE;
+ if (GT == sign) return LT;
+ if (LE == sign) return GE;
+ return sign;
}
private DfaRelationValue(DfaValueFactory factory) {
diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/InherentNumberRanges.java b/java/java-tests/testData/inspection/dataFlow/fixture/InherentNumberRanges.java
new file mode 100644
index 000000000000..09ec04884108
--- /dev/null
+++ b/java/java-tests/testData/inspection/dataFlow/fixture/InherentNumberRanges.java
@@ -0,0 +1,19 @@
+class Foo {
+
+ private void foo(byte myByte) {
+ if (myByte == 0xFF) {
+ System.out.println("wrong");
+ }
+ if (myByte != 0xFFF) {
+ System.out.println("wrong");
+ }
+ if (myByte == (byte) 0xFF) {
+ System.out.println("right");
+ }
+ }
+
+ void foo2(int i) {
+ boolean a = i < 0x80000000L;
+ boolean f = i > 0x7fffffff;
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java
index 58dcf3ecc0f1..8de5e670edc2 100644
--- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java
@@ -179,6 +179,7 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase {
}
public void testConstantDoubleComparisons() { doTest(); }
+ public void testInherentNumberRanges() { doTest(); }
public void testMutableNullableFieldsTreatment() { doTest(); }
public void testMutableVolatileNullableFieldsTreatment() { doTest(); }
diff --git a/platform/util/src/com/intellij/util/containers/VariableWidthIntArray.java b/platform/util/src/com/intellij/util/containers/VariableWidthIntArray.java
deleted file mode 100644
index d73a732ba447..000000000000
--- a/platform/util/src/com/intellij/util/containers/VariableWidthIntArray.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.intellij.util.containers;
-
-import com.intellij.openapi.diagnostic.Logger;
-
-/**
- * @author Dmitry.Shtukenberg
- */
-public final class VariableWidthIntArray implements Cloneable {
- private static final Logger LOG = Logger.getInstance("#com.intellij.util.containers.VariableWidthIntArray");
-
- private int[] intArray = null;
- private short[] shortArray = null;
- private byte[] byteArray = null;
-
- private final int minValue;
- private final int maxValue;
-
- static final int INT = 1;
- static final int SHORT = 2;
- static final int BYTE = 3;
- private final int arrayType;
-
- public VariableWidthIntArray( int minValue, int maxValue, int initialCapacity ) {
- this.minValue = minValue;
- this.maxValue = maxValue;
-
- if( minValue < Short.MIN_VALUE || maxValue > Short.MAX_VALUE ) {
- intArray = new int[ bestSize(initialCapacity) ];
- arrayType = INT;
- }
- else if( minValue < Byte.MIN_VALUE || maxValue > Byte.MAX_VALUE ) {
- shortArray = new short[ bestSize(initialCapacity) ];
- arrayType = SHORT;
- }
- else {
- byteArray = new byte[ bestSize(initialCapacity) ];
- arrayType = BYTE;
- }
- }
-
- static int bestSize( int maxSize ) {
- int newSize = (int)(((double)maxSize) * 5 / 4);
- return newSize <= maxSize ? maxSize + 1 : newSize;
- }
-
- public void ensureArraySize( int index ) {
- if( intArray != null && intArray.length <= index ) {
- int[] tmp = new int[ bestSize(index) ];
- System.arraycopy( intArray, 0, tmp, 0, intArray.length );
- intArray = tmp;
- }
- else if( shortArray != null && shortArray.length <= index ) {
- short[] tmp = new short[ bestSize(index) ];
- System.arraycopy( shortArray, 0, tmp, 0, shortArray.length );
- shortArray = tmp;
- }
- else if( byteArray.length <= index ) {
- byte[] tmp = new byte[ bestSize(index) ];
- System.arraycopy( byteArray, 0, tmp, 0, byteArray.length );
- byteArray = tmp;
- }
- }
-
- public int get( int index ) {
- switch( arrayType ) {
- case INT: return intArray[index];
- case SHORT: return shortArray[index];
- case BYTE: return byteArray[index];
- }
- LOG.error("No array allocated");
- return 0;
- }
-
- public void put( int index, int value ) {
- if( value < minValue || value > maxValue ) {
- LOG.error("Value out of domain");
- }
-
- switch( arrayType ) {
- case INT: intArray[index] = value; return;
- case SHORT: shortArray[index] = (short)value; return;
- case BYTE: byteArray[index] = (byte)value; return;
- }
-
- LOG.error("No array allocated");
- }
-
- @Override
- public Object clone() throws CloneNotSupportedException {
- VariableWidthIntArray arr = (VariableWidthIntArray)super.clone();
- if( intArray != null ) { arr.intArray = intArray.clone(); }
- if( shortArray != null ) { arr.shortArray = shortArray.clone(); }
- if( byteArray != null ) { arr.byteArray = byteArray.clone(); }
- return arr;
- }
-
- public void arraycopy(int[] src, int from, int to, int count) {
- for( int i = 0; i < count; i++ )
- put( i + to, src[i + from] );
- }
-
- public void move(int from, int to, int count) {
- switch( arrayType ) {
- case INT: System.arraycopy( intArray, from, intArray, to, count ); break;
- case SHORT: System.arraycopy( shortArray, from, shortArray, to, count ); break;
- case BYTE: System.arraycopy( byteArray, from, byteArray, to, count ); break;
- default:
- LOG.error("Invalid array type");
- }
- }
-
- public boolean arrayequal( VariableWidthIntArray src, int srcfrom, int from, int count ) {
- if( src.arrayType != arrayType ) return false;
- for( int i = 0; i < count; i++ )
- if( get(from+i) != src.get(srcfrom+i)) return false;
- return true;
- }
-}