| import org.checkerframework.checker.nullness.qual.*; |
| import org.checkerframework.framework.qual.DefaultQualifier; |
| |
| /** |
| * The component type of newly created arrays is always @Nullable, also for boxed types. This is an |
| * expanded version of the test case for Issue 151: |
| * https://github.com/typetools/checker-framework/issues/151 |
| */ |
| public class ArrayCreationNullable { |
| |
| void testObjectArray(@NonNull Object @NonNull [] p) { |
| @NonNull Object @NonNull [] objs; |
| // :: error: (new.array) |
| objs = new Object[10]; |
| objs[0].toString(); |
| // :: error: (assignment) |
| objs = new @Nullable Object[10]; |
| objs[0].toString(); |
| // :: error: (new.array) |
| objs = new @NonNull Object[10]; |
| objs[0].toString(); |
| // Allowed. |
| objs = p; |
| objs[0].toString(); |
| } |
| |
| @DefaultQualifier(NonNull.class) |
| void testObjectArray2() { |
| Object[] objs; |
| // Even if the default qualifier is NonNull, array component |
| // types must be Nullable. |
| // :: error: (new.array) |
| objs = new Object[10]; |
| objs[0].toString(); |
| } |
| |
| void testInitializers() { |
| Object[] objs = {1, 2, 3}; |
| objs = new Integer[] {1, 2, 3}; |
| objs = new Object[] {new Object(), "ha"}; |
| |
| @NonNull Object[] objs2 = {}; |
| // :: error: (assignment) |
| objs2 = new Integer[] {1, null, 3}; |
| // :: error: (assignment) |
| objs2 = new Object[] {new Object(), "ha", null}; |
| |
| @NonNull Object[] objs3 = new Integer[] {1, 2, 3}; |
| objs3 = new Integer[] {1, 2, 3}; |
| // :: error: (assignment) |
| objs3 = new Integer[] {1, 2, 3, null}; |
| |
| (new Integer[] {1, 2, 3})[0].toString(); |
| // :: error: (dereference.of.nullable) |
| (new Integer[] {1, 2, 3, null})[0].toString(); |
| |
| // The assignment context is used to infer a @Nullable component type. |
| @Nullable Object[] objs4 = new Integer[] {1, 2, 3}; |
| // :: error: (dereference.of.nullable) |
| objs4[0].toString(); |
| objs4 = new Integer[] {1, 2, 3}; |
| } |
| |
| void testStringArray(@NonNull String @NonNull [] p) { |
| @NonNull String @NonNull [] strs; |
| // :: error: (new.array) |
| strs = new String[10]; |
| strs[0].toString(); |
| // :: error: (assignment) |
| strs = new @Nullable String[10]; |
| strs[0].toString(); |
| // :: error: (new.array) |
| strs = new @NonNull String[10]; |
| strs[0].toString(); |
| // Allowed. |
| strs = p; |
| strs[0].toString(); |
| } |
| |
| void testIntegerArray(@NonNull Integer @NonNull [] p) { |
| @NonNull Integer @NonNull [] ints; |
| // :: error: (new.array) |
| ints = new Integer[10]; |
| ints[0].toString(); |
| // :: error: (assignment) |
| ints = new @Nullable Integer[10]; |
| ints[0].toString(); |
| // :: error: (new.array) |
| ints = new @NonNull Integer[10]; |
| ints[0].toString(); |
| // Allowed. |
| ints = p; |
| ints[0].toString(); |
| } |
| |
| // The component type of zero-length arrays can be non-null - they will always generate |
| // IndexOutOfBoundsExceptions, but are usually just used for the type, e.g. in List.toArray. |
| void testLengthZero() { |
| @NonNull Object @NonNull [] objs; |
| objs = new Object[0]; |
| } |
| |
| /* Test case for Issue 153. |
| // toArray re-uses the passed array, if it is of appropriate size. |
| // It is only guaranteed to be non-null, if it is at most the same size. |
| void testToArray(java.util.Set<Object> nns) { |
| @NonNull Object [] nna = nns.toArray(new Object[nns.size()]); |
| // Given array is too small -> new one is created. |
| nna = nns.toArray(new Object[nns.size()-2]); |
| // Padding elements will be null. |
| // TODO:: error: (assignment) |
| nna = nns.toArray(new Object[nns.size() + 2]); |
| @Nullable Object [] nbla = nns.toArray(new Object[nns.size() + 2]); |
| } |
| */ |
| |
| void testMultiDim() { |
| // new double[10][10] has type double @NonNull[] @Nullable[] |
| // :: error: (new.array) |
| double @NonNull [] @NonNull [] daa = new double[10][10]; |
| double @NonNull [] @Nullable [] daa2 = new double[10][10]; |
| |
| // new Object[10][10] has type @Nullable Object @NonNull[] @Nullable[] |
| // :: error: (new.array) |
| @Nullable Object @NonNull [] @NonNull [] oaa = new Object[10][10]; |
| @Nullable Object @NonNull [] @Nullable [] oaa2 = new Object[10][10]; |
| |
| // new Object[10][10] has type @Nullable Object @NonNull[] @Nullable[] |
| // :: error: (new.array) |
| oaa2 = new Object @NonNull [10] @NonNull [10]; |
| |
| @MonotonicNonNull Object @NonNull [] @MonotonicNonNull [] oaa3 = |
| new @MonotonicNonNull Object @NonNull [10] @MonotonicNonNull [10]; |
| oaa3[0] = new @MonotonicNonNull Object[4]; |
| // :: error: (assignment) |
| oaa3[0] = null; |
| // :: error: (assignment) :: error: (accessing.nullable) |
| oaa3[0][0] = null; |
| } |
| |
| @PolyNull Object[] testPolyNull(@PolyNull Object[] in) { |
| @PolyNull Object[] out = new @PolyNull Object[in.length]; |
| for (int i = 0; i < in.length; ++i) { |
| if (in[i] == null) { |
| out[i] = null; |
| } else { |
| out[i] = in[i].getClass().toString(); |
| // :: error: (assignment) |
| out[i] = null; |
| } |
| } |
| return out; |
| } |
| |
| void testMonotonicNonNull() { |
| @MonotonicNonNull Object @NonNull [] loa = new @MonotonicNonNull Object @NonNull [10]; |
| loa = new Object @NonNull [10]; |
| loa[0] = new Object(); |
| @MonotonicNonNull Object @NonNull [] loa2 = new Object @NonNull [10]; |
| // :: error: (dereference.of.nullable) |
| loa2[0].toString(); |
| } |
| |
| @MonotonicNonNull Object @NonNull [] testReturnContext() { |
| return new Object[10]; |
| } |
| |
| // :: error: (new.array) |
| @NonNull Object @NonNull [] oa0 = new Object[10]; |
| |
| // OK |
| @MonotonicNonNull Object @NonNull [] loa0 = new @MonotonicNonNull Object @NonNull [10]; |
| |
| Object[] oa1 = new Object[] {new Object()}; |
| |
| // :: error: (assignment) |
| Object[] oa2 = new Object[] {new Object(), null}; |
| |
| public static void main(String[] args) { |
| ArrayCreationNullable e = new ArrayCreationNullable(); |
| Integer[] ints = new Integer[] {5, 6}; |
| // This would result in a NPE, if there were no error. |
| e.testIntegerArray(ints); |
| } |
| } |