IDEA-184733 Better array access tracking in DFA

This commit is contained in:
Tagir Valeev
2018-01-10 12:26:47 +07:00
parent c5421d1260
commit af97567674
16 changed files with 345 additions and 95 deletions
@@ -9,7 +9,7 @@ public abstract class Super {
}
class Sub extends Zzza {
interface Sub extends Zzza {
void subMethod() {}
}
@@ -9,7 +9,7 @@ public abstract class Super {
}
class Sub extends Zzza {
interface Sub extends Zzza {
void subMethod() {}
}
@@ -0,0 +1,108 @@
import java.util.*;
class AdvancedArrayAccess {
private static final int[] LENGTH = {0, 10, 20, 30};
private static final int[] LENGTH2 = {0, 10, 20, 30};
void testInstanceOf() {
Object[] arr = {new String("foo"), new Integer(0)};
if(<warning descr="Condition 'arr[0] instanceof Number' is always 'false'">arr[0] instanceof Number</warning>) {
System.out.println(((Number)arr[0]).intValue());
}
}
void testStaticFinal() {
if(<warning descr="Condition 'LENGTH[2] == 20' is always 'true'">LENGTH[2] == 20</warning>) {
System.out.println("ok");
}
}
int[] getLengths() {
// array is still read-only
return LENGTH.clone();
}
int getLengthsCount() {
// array is still read-only
return LENGTH.length;
}
int[] getLength2() {
// Reference leaks: do not consider an array as read-only
return LENGTH2;
}
void testStaticFinal(int idx) {
if(idx == 2 && <warning descr="Condition 'LENGTH[idx] == 20' is always 'true' when reached">LENGTH[idx] == 20</warning>) {
System.out.println("ok");
}
}
void testStaticFinalRW(int idx) {
if(idx == 2 && LENGTH2[idx] == 20) {
System.out.println("ok");
}
}
void testWrite(int[] arr, int idx) {
if(idx != 0) return;
arr[idx] = 10;
if(<warning descr="Condition 'arr[0] == 11' is always 'false'">arr[0] == 11</warning>) {
System.out.println("impossible");
}
}
void testSplitState(boolean b, String[] data) {
data[1] = "A";
data[2] = "B";
int idx = b ? 0 : 1;
data[idx] = "C";
if(<warning descr="Condition 'data[2].equals(\"D\")' is always 'false'">data[2].equals("D")</warning>) {
System.out.println("never");
}
if(<warning descr="Condition 'data[1].equals(\"E\")' is always 'false'">data[1].equals("E")</warning>) {
System.out.println("never");
}
if(data[1].equals("A") && <warning descr="Condition 'b' is always 'true' when reached">b</warning>) {
System.out.println("Only if b is true");
}
}
// Should not be too complex
static int max(float[] array) {
int max = 0;
float val = array[0];
for (int i = 1; i < array.length; i++) {
if (val < array[i]) {
max = i;
val = array[i];
}
}
return max;
}
void processArray(String[] arr) {
for(int i=0; i<arr.length; i++) {
if(arr[i].isEmpty()) arr[i] = null; // No NPE warning here even if we update arr[i] to null we'll never visit same element twice
}
}
void testMethodQualifier() {
if(getData()[0] == null) {
System.out.println(getData()[0].<warning descr="Method invocation 'trim' may produce 'java.lang.NullPointerException'">trim</warning>());
}
}
final String[] getData() {
return new String[] {"a", "b", "c"};
}
void testConditional(String[] arr, int idx) {
if(idx == 0) {
arr[idx] = "foo";
}
if(<warning descr="Condition 'arr[0].equals(\"bar\") && idx == 0' is always 'false'">arr[0].equals("bar") && <warning descr="Condition 'idx == 0' is always 'false' when reached">idx == 0</warning></warning>) {
System.out.println("never");
}
}
}
@@ -68,4 +68,14 @@ public final class ArrayLength {
Arrays.fill(x, -1);
Arrays.<warning descr="The call to 'fill' always fails as index is out of bounds">fill</warning>(x, -1, -1, -1);
}
static final String[] ARR1 = {};
static final String[] ARR2 = new String[10];
static final String[] ARR3 = new String[] {"foo", "bar", "baz"};
void testFieldInitializers() {
if(<warning descr="Condition 'ARR1.length == 0' is always 'true'">ARR1.length == 0</warning>) System.out.println("yes");
if(<warning descr="Condition 'ARR2.length == 10' is always 'true'">ARR2.length == 10</warning>) System.out.println("yes");
if(<warning descr="Condition 'ARR3.length == 3' is always 'true'">ARR3.length == 3</warning>) System.out.println("yes");
}
}
@@ -99,6 +99,11 @@ public class LongRangeBasics {
}
}
static final String FOO = "bar";
void testStaticLength() {
if(<warning descr="Condition 'FOO.isEmpty()' is always 'false'">FOO.isEmpty()</warning>) System.out.println("nope");
}
void testWrongMerge(boolean a, boolean b, int c) {
int currentLevel = 0;