// @skip-test

// To reproduce the problem, run:
//   javac -processor nullness Issue556b.java
//   java Issue556b
// and observe that the javac execution issues no warnings but the java execution suffers a null
// pointer exception.

// Before the constructor is invoked, static initializers and static blocks are executed.  This
// suggests that the Initialization Checker can assume that static fields are initialized in the
// constructor.
//
// However, if any user-defined code -- including callbacks such as executions of equals() and
// hashCode() -- appears in a static initializer or static block, then static fields cannot be
// assumed to be initialized within the constructor.

public class Issue556b {
  static class Parent {
    private final Object o;

    public Parent(final Object o) {
      this.o = o;
    }

    @Override
    public String toString() {
      return o.toString();
    }
  }

  static class Child extends Parent {
    public static final Child CHILD = new Child();
    private static final Object OBJ = new Object();

    private Child() {
      // This call should not be legal, because at the time that the call occurs, the static
      // initializers of Child have not yet finished executing and therefore CHILD and OBJ are
      // not necessarily initialized and are not necessarily non-null.
      // :: error: (method.invocation)
      super(OBJ);
    }
  }

  static class Child2 extends Parent {
    public static final Child2 CHILD;
    private static final Object OBJ;

    static {
      CHILD = new Child2();
      OBJ = new Object();
    }

    private Child2() {
      // This call should not be legal, because at the time that the call occurs, the static
      // initializers of Child have not yet finished executing and therefore CHILD and OBJ are
      // not necessarily initialized and are not necessarily non-null.
      // :: error: (method.invocation)
      super(OBJ);
    }
  }

  // Changing the order of the OBJ and CHILD fields prevents a null pointer exception.
  static class ChildOk1 extends Parent {
    private static final Object OBJ = new Object();
    public static final Child CHILD = new Child();

    private ChildOk1() {
      // This call is legal, because OBJ is non-null at the time of the
      // call.  That's because OBJ is initialized before CHILD and
      // therefore before the call to "new Child()".
      super(OBJ);
    }
  }

  // Changing the order of the OBJ and CHILD field assignments prevents a null pointer exception.
  static class ChildOk2 extends Parent {
    public static final ChildOk2 CHILD;
    private static final Object OBJ;

    static {
      OBJ = new Object();
      CHILD = new ChildOk2();
    }

    private ChildOk2() {
      // This call is legal, because OBJ is non-null at the time of the
      // call.  That's because OBJ is initialized before CHILD and
      // therefore before the call to "new Child()".
      super(OBJ);
    }
  }

  public static void main(final String[] args) {
    System.out.println(Child.CHILD);
  }
}
