IDEA-205011 DFA: limited support for shift-left

This commit is contained in:
Tagir Valeev
2019-01-06 16:18:42 +07:00
parent 725cf20422
commit a48ee49974
3 changed files with 39 additions and 1 deletions
@@ -32,7 +32,7 @@ import static com.intellij.psi.JavaTokenType.*;
public class BinopInstruction extends BranchingInstruction implements ExpressionPushingInstruction {
private static final TokenSet ourSignificantOperations =
TokenSet.create(EQEQ, NE, LT, GT, LE, GE, INSTANCEOF_KEYWORD, PLUS, MINUS, AND, PERC, DIV, ASTERISK, GTGT, GTGTGT);
TokenSet.create(EQEQ, NE, LT, GT, LE, GE, INSTANCEOF_KEYWORD, PLUS, MINUS, AND, PERC, DIV, ASTERISK, GTGT, GTGTGT, LTLT);
private final IElementType myOperationSign;
private final @Nullable PsiType myResultType;
private final int myLastOperand;
@@ -184,6 +184,9 @@ public abstract class LongRangeSet {
if (token.equals(JavaTokenType.DIV)) {
return div(right, isLong);
}
if (token.equals(JavaTokenType.LTLT)) {
return shiftLeft(right, isLong);
}
if (token.equals(JavaTokenType.GTGT)) {
return shiftRight(right, isLong);
}
@@ -371,6 +374,25 @@ public abstract class LongRangeSet {
.unite(point(-1).minus(point(-1).minus(negative, isLong).shrPositive(min, max, isLong), isLong));
}
/**
* Returns a range which represents all the possible values after applying {@code x << y} operation for
* all {@code x} from this set and for all {@code y} from the shiftSize set. The resulting set may contain
* some more values.
*
* @param shiftSize set of possible shift sizes (number of bits to shift to the left)
* @param isLong whether the operation is performed on long type (if false, the int type is assumed).
* @return a new range
*/
@NotNull
public LongRangeSet shiftLeft(LongRangeSet shiftSize, boolean isLong) {
if (isEmpty() || shiftSize.isEmpty()) return empty();
if (shiftSize instanceof Point) {
long shift = ((Point)shiftSize).myValue & ((isLong ? Long.SIZE : Integer.SIZE)-1);
return point(1 << shift).mul(this, isLong);
}
return isLong ? Range.LONG_RANGE : Range.INT_RANGE;
}
/**
* Returns a range which represents all the possible values after applying {@code x >>> y} operation for
* all {@code x} from this set and for all {@code y} from the shiftSize set. The resulting set may contain
@@ -432,6 +432,17 @@ public class LongRangeSetTest {
checkShr(range(1000000, 1000020), range(3, 5), true, "{31250..125002}");
}
@Test
public void testShl() {
assertEquals(empty(), empty().shiftLeft(all(), true));
assertEquals(empty(), all().shiftLeft(empty(), true));
assertEquals(all(), all().shiftLeft(all(), true));
checkShl(point(1), point(3), false, "{8}");
checkShl(range(0, 10), point(3), false, "{0..80}");
checkShl(range(0, 15), point(28), false, "{Integer.MIN_VALUE..Integer.MAX_VALUE}");
checkShl(range(0, 15), point(28), true, "{0..4026531840}");
}
@Test
public void testUShr() {
assertEquals(empty(), empty().unsignedShiftRight(all(), true));
@@ -549,6 +560,11 @@ public class LongRangeSetTest {
checkBinOp(arg, shiftSize, result, x -> true, (a, b) -> isLong ? a >> b : ((int)a >> (int)b), expected, ">>");
}
void checkShl(LongRangeSet arg, LongRangeSet shiftSize, boolean isLong, String expected) {
LongRangeSet result = arg.shiftLeft(shiftSize, isLong);
checkBinOp(arg, shiftSize, result, x -> true, (a, b) -> isLong ? a << b : ((int)a << (int)b), expected, "<<");
}
void checkUShr(LongRangeSet arg, LongRangeSet shiftSize, boolean isLong, String expected) {
LongRangeSet result = arg.unsignedShiftRight(shiftSize, isLong);
checkBinOp(arg, shiftSize, result, x -> true, (a, b) -> isLong ? a >>> b : ((int)a >>> (int)b), expected, ">>>");