| import org.checkerframework.checker.nullness.qual.*; |
| |
| @org.checkerframework.framework.qual.DefaultQualifier(Nullable.class) |
| public class FlowField { |
| |
| public @Nullable String s = null; |
| |
| void test() { |
| if (s != null) { |
| s.startsWith("foo"); |
| } |
| } |
| |
| static String field = "asdf"; |
| |
| static { |
| field = "asdf"; |
| } |
| |
| void testFields() { |
| // :: error: (dereference.of.nullable) |
| System.out.println(field.length()); |
| } |
| |
| // Fowrard reference to static finals |
| void test1() { |
| nonnull.toString(); |
| } |
| |
| static final String nonnull = new String(); |
| |
| class A { |
| protected String field = null; |
| } |
| |
| class B extends A { |
| void test() { |
| assert field != null : "@AssumeAssertion(nullness)"; |
| field.length(); |
| } |
| } |
| |
| static class BooleanWrapper { |
| @Nullable Object b; |
| } |
| |
| @Nullable BooleanWrapper bw; |
| |
| void testBitwise(@NonNull FlowField a, @NonNull FlowField b) { |
| Object r; |
| if (a.bw != null) { |
| if (b.bw != null) { |
| r = a.bw.b; |
| r = b.bw.b; |
| } |
| } |
| if (a.bw != null && b.bw != null) { |
| r = a.bw.b; |
| r = b.bw.b; |
| } |
| } |
| |
| void testInstanceOf(@NonNull FlowField a) { |
| if (!(a.s instanceof String)) { |
| return; |
| } |
| @NonNull String s = a.s; |
| } |
| |
| void testTwoLevels(@NonNull FlowField a, BooleanWrapper bwArg) { |
| // :: error: (dereference.of.nullable) |
| if (!(a.bw.hashCode() == 0)) // warning here |
| return; |
| Object o = a.bw.b; // but not here |
| } |
| } |