import java.util.ArrayList; import java.util.List; import org.checkerframework.checker.initialization.qual.UnknownInitialization; import org.checkerframework.checker.nullness.qual.*; import org.checkerframework.checker.nullness.qual.EnsuresNonNull; class RawAssertNonNull { class Test1 { private Object f; private Object g; Test1() { m(); } @EnsuresNonNull({"f", "g"}) private void m(@Raw @UnknownInitialization Test1 this) { this.f = new Object(); this.g = new Object(); } } class Test1b { private Object f; private Object g; Test1b() { m(); } @EnsuresNonNull({"f", "g"}) //:: error: (contracts.postcondition.not.satisfied) private void m(@Raw @UnknownInitialization Test1b this) { this.f = new Object(); } } class Test1c { private Object f; private Object g; //:: error: (initialization.fields.uninitialized) Test1c() { m(); } @EnsuresNonNull({"f"}) private void m(@Raw @UnknownInitialization Test1c this) { this.f = new Object(); this.g = new Object(); } } class Test1d { private Object f; private Object g; Test1d() { m(); // If one has some additional information that the type system hasn't // one can suppress the error from Test1c using an assertion, // which is nicer than suppressing the warning. assert this.g != null : "@AssumeAssertion(nullness)"; } @EnsuresNonNull({"f"}) private void m(@Raw @UnknownInitialization Test1d this) { this.f = new Object(); this.g = new Object(); } } class Test2 { private List<String> f; private List<String> g; Test2(Global g) { m(g); } @EnsuresNonNull({"f", "this.g"}) private void m(@Raw @UnknownInitialization Test2 this, Global g) { this.f = new ArrayList<String>(); this.g = new ArrayList<String>(); g.nonpure(); // The global method sees the fields as non-null and // cannot set them to null. } } class Test2b { private List<String> f; private List<String> g; Test2b(Global g) { m(); g.nonpure(); // The global method sees the fields as non-null and // cannot set them to null. } @EnsuresNonNull({"f", "g"}) private void m(@Raw @UnknownInitialization Test2b this) { this.f = new ArrayList<String>(); this.g = new ArrayList<String>(); } } class Test2c { private List<String> f; private List<String> g; Test2c(Global g) { m(); nonpure(); // The raw, non-pure method "nonpure" cannot set fields back to null. // -> All fields initialized. } @EnsuresNonNull({"f", "g"}) private void m(@Raw @UnknownInitialization Test2c this) { this.f = new ArrayList<String>(); this.g = new ArrayList<String>(); } private void nonpure(@Raw @UnknownInitialization Test2c this) { //:: error: (assignment.type.incompatible) this.f = null; } } class Global { void nonpure() {} } }