From fc97cbbd2c971fc415ab78736e6d96a1f10eb0fe Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Tue, 24 Sep 2019 12:18:44 +0700 Subject: [PATCH] LongRangeSet#wideBinOpFromToken: limited multiplication support GitOrigin-RevId: 0d7671705a883d921d7935fc955a8b114f984c46 --- .../dataFlow/rangeSet/LongRangeSet.java | 31 ++++++++++++++----- .../dataFlow/fixture/WidenMulInLoop.java | 21 +++++++++++++ .../DataFlowRangeAnalysisTest.java | 1 + 3 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/WidenMulInLoop.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSet.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSet.java index d924681dc0e8..0e9128817d04 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSet.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSet.java @@ -214,6 +214,20 @@ public abstract class LongRangeSet { if (token.equals(JavaTokenType.PLUS) || token.equals(JavaTokenType.MINUS)) { return plusWiden(token.equals(JavaTokenType.MINUS) ? other.negate(isLong) : other, isLong); } + if (token.equals(JavaTokenType.ASTERISK)) { + return mulWiden(other, isLong); + } + return null; + } + + private LongRangeSet mulWiden(LongRangeSet other, boolean isLong) { + if (Point.ZERO.equals(this)) return this; + if (Point.ZERO.equals(other)) return other; + if (Point.ONE.equals(this)) return other; + if (Point.ONE.equals(other)) return this; + if (Point.ZERO.equals(this.mod(point(2))) || Point.ZERO.equals(other.mod(point(2)))) { + return modRange(minValue(isLong), maxValue(isLong), 2, 1); + } return null; } @@ -378,7 +392,7 @@ public abstract class LongRangeSet { */ @NotNull public LongRangeSet div(LongRangeSet divisor, boolean isLong) { - if (divisor.isEmpty() || divisor.equals(new Point(0))) return empty(); + if (divisor.isEmpty() || divisor.equals(Point.ZERO)) return empty(); long[] left = splitAtZero(asRanges()); long[] right = splitAtZero(new long[]{divisor.min(), divisor.max()}); LongRangeSet result = empty(); @@ -520,7 +534,7 @@ public abstract class LongRangeSet { if (isEmpty()) return empty(); int maxShift = (isLong ? Long.SIZE : Integer.SIZE) - 1; if (max == maxShift) { - return min == max ? point(0) : point(0).unite(div(range(1L << min, 1L << (max - 1)), isLong)); + return min == max ? Point.ZERO : Point.ZERO.unite(div(range(1L << min, 1L << (max - 1)), isLong)); } return div(range(1L << min, 1L << max), isLong); } @@ -666,7 +680,7 @@ public abstract class LongRangeSet { * @return a new set */ public static LongRangeSet point(long value) { - return new Point(value); + return value == 0 ? Point.ZERO : value == 1 ? Point.ONE : new Point(value); } /** @@ -708,7 +722,7 @@ public abstract class LongRangeSet { * @return a new LongRangeSet */ public static LongRangeSet range(long from, long to) { - return from == to ? new Point(from) : new Range(from, to); + return from == to ? point(from) : new Range(from, to); } /** @@ -1015,6 +1029,9 @@ public abstract class LongRangeSet { } static final class Point extends LongRangeSet { + static final Point ZERO = new Point(0); + static final Point ONE = new Point(1); + final long myValue; Point(long value) { @@ -1225,7 +1242,7 @@ public abstract class LongRangeSet { @NotNull @Override public LongRangeSet mod(LongRangeSet divisor) { - if (divisor.isEmpty() || divisor.equals(point(0))) return empty(); + if (divisor.isEmpty() || divisor.equals(ZERO)) return empty(); if (myValue == 0) return this; if (divisor instanceof Point) { return LongRangeSet.point(myValue % ((Point)divisor).myValue); @@ -1589,9 +1606,9 @@ public abstract class LongRangeSet { @NotNull @Override public LongRangeSet mod(LongRangeSet divisor) { - if (divisor.isEmpty() || divisor.equals(point(0))) return empty(); + if (divisor.isEmpty() || divisor.equals(Point.ZERO)) return empty(); if (divisor instanceof Point && ((Point)divisor).myValue == Long.MIN_VALUE) { - return this.contains(Long.MIN_VALUE) ? this.subtract(divisor).unite(point(0)) : this; + return this.contains(Long.MIN_VALUE) ? this.subtract(divisor).unite(Point.ZERO) : this; } if (divisor.contains(Long.MIN_VALUE)) { return possibleMod(); diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/WidenMulInLoop.java b/java/java-tests/testData/inspection/dataFlow/fixture/WidenMulInLoop.java new file mode 100644 index 000000000000..efd021957eb6 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/WidenMulInLoop.java @@ -0,0 +1,21 @@ +import java.util.*; + +public class WidenMulInLoop { + void test1() { + for (int i = 0; i < Integer.MAX_VALUE; i *= 3) { + System.out.println(i); + } + } + + void test2() { + for (int i = 1; i < Integer.MAX_VALUE; i *= 2) { + System.out.println(i); + } + } + + void test3() { + for (int i = 1; i < Integer.MAX_VALUE; i *= 3) { + System.out.println(i); + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowRangeAnalysisTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowRangeAnalysisTest.java index aeff3b150479..11dba5d76e42 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowRangeAnalysisTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowRangeAnalysisTest.java @@ -64,4 +64,5 @@ public class DataFlowRangeAnalysisTest extends DataFlowInspectionTestCase { public void testStringConcat() { doTest(); } public void testUnaryPlusMinus() { doTest(); } public void testWidenPlusInLoop() { doTest(); } + public void testWidenMulInLoop() { doTest(); } }