public class B {
  private boolean maybe;
  public final boolean flag;
  public B(boolean b, boolean f) {
    this.maybe = b;
    this.flag = f;
  }

  public void caller() {
    callee1(new Object());
    callee1(null);
    callee2(new Object());
  }

  public void callee1(Object param) {
    param.toString(); // NPE
  }

  public void callee2(Object param) {
    if (param != null) {
      param.toString(); // OK
    }
    param.toString(); // NPE
  }

  private static boolean customIsNull(Object x) {
    if (x instanceof String) return false;
    if (x == null) return true;
    return x == null;
  }

  public void nullGuards() {
    Object o1 = maybe ? null : new Object();
    if (o1 != null) o1.hashCode(); // OK

    Object o2 = maybe ? null : "";
    if (o2 instanceof String) o2.hashCode(); // OK

    Object o3 = null;
    if ((o3 = maybe ? null : "") != null) o3.hashCode(); // OK

    Object o4 = maybe ? null : "";
    if ((2 > 1 && o4 != null) != false) o4.hashCode(); // OK

    Object o5 = (o4 != null) ? "" : null;
    if (o5 != null) o4.hashCode(); // OK
    if (o4 != null) o5.hashCode(); // OK

    Object o6 = maybe ? null : "";
    if (!customIsNull(o6)) o6.hashCode(); // OK

    Object o7 = maybe ? null : "";
    boolean ok = o7 != null && 2 > 1;
    if (ok)
      o7.hashCode(); // OK
    else
      o7.hashCode(); // NPE

    Object o8 = maybe ? null : "";
    int track = o8 == null ? 42 : 1+1;
    if (track == 2) o8.hashCode(); // OK
    if (track != 42) o8.hashCode(); // OK
    if (track < 42) o8.hashCode(); // OK
    if (track <= 41) o8.hashCode(); // OK
  }

  public void deref() {
    int[] xs = maybe ? null : new int[2];
    if (2 > 1) xs[0] = 5; // NPE
    if (2 > 1) maybe = xs[1] > 5; // NPE
    if (2 > 1) {
      int l = xs.length; // NPE
    }
    if (2 > 1) {
      for (int i : xs) { } // NPE
    }
    if (2 > 1) {
      synchronized(xs) { // NPE
        xs.hashCode(); // Not reported - same basic block
      }
    }
    if (4 > 3) {
      assert xs != null;
      xs[0] = xs[1]; // OK
    }
  }

  public void f(boolean b) {
    String x = b ? null : "abc";
    x = x == null ? "" : x;
    if (x == null)
      x.hashCode(); // OK - dead
    else
      x.hashCode(); // OK
  }

  public void lengthGuard(int[] a, int[] b) {
    int alen = a == null ? 0 : a.length; // OK
    int blen = b == null ? 0 : b.length; // OK
    int sum = 0;
    if (alen == blen) {
      for(int i = 0; i < alen; i++) {
        sum += a[i]; // OK
        sum += b[i]; // OK
      }
    }
    int alen2;
    if (a != null)
      alen2 = a.length; // OK
    else
      alen2 = 0;
    for(int i = 1; i <= alen2; ++i) {
      sum += a[i-1]; // OK
    }
  }

  public void missedGuard(Object obj) {
    obj.hashCode(); // NPE
    int x = obj != null ? 1 : 0;
  }

  private Object mkMaybe() {
    if (maybe) throw new RuntimeException();
    return new Object();
  }

  public void exceptions() {
    Object obj = null;
    try {
      obj = mkMaybe();
    } catch(Exception e) {
    }
    obj.hashCode(); // NPE

    Object obj2 = null;
    try {
      obj2 = mkMaybe();
    } catch(Exception e) {
      assert false;
    }
    obj2.hashCode(); // OK

    Object obj3 = null;
    try {
      obj3 = mkMaybe();
    } finally {
      //cleanup
    }
    obj3.hashCode(); // OK
  }

  public void clearNotNull() {
    Object o = new Object();
    if (o == null) o.hashCode(); // OK
    o.hashCode(); // OK

    try {
      mkMaybe();
    } catch(Exception e) {
      if (e == null) e.hashCode(); // OK
      e.hashCode(); // OK
    }

    Object n = null;
    Object o2 = n == null ? new Object() : n;
    o2.hashCode(); // OK

    Object o3 = "abc";
    if (o3 == null) o3.hashCode(); // OK
    o3.hashCode(); // OK

    Object o4 = "" + null;
    if (o4 == null) o4.hashCode(); // OK
    o4.hashCode(); // OK
  }

  public void correlatedConditions(boolean cond, int num) {
    Object o = null;
    if (cond) o = new Object();
    if (cond) o.hashCode(); // OK

    o = null;
    if (flag) o = "";
    if (flag) o.hashCode(); // OK

    o = null;
    Object other = maybe ? null : "";
    if (other == null) o = "";
    if (other != null)
      o.hashCode(); // NPE
    else
      o.hashCode(); // OK

    Object o2 = (num < 0) ? null : "";
    if (num < 0)
      o2 = "";
    else
      o2.hashCode(); // OK
  }

  public void trackingVariable(int[] a) {
    Object o = null;
    Object other = null;
    if (maybe) {
      o = "abc";
      other = "def";
    }
    if (other instanceof String) o.hashCode(); // OK

    o = null;
    int count = 0;
    boolean found = false;
    for (int i = 0; i < a.length; i++) {
      if (a[i] == 42) {
        o = ((Integer)a[i]).toString();
        count++;
        if (2 > 1) { }
        found = true;
      }
      if (a[i] > 10000) {
        o = null;
        count = 0;
        if (2 > 1) { }
        found = false;
      }
    }
    if (count > 3) o.hashCode(); // OK
    if (found) o.hashCode(); // OK

    Object prev = null;
    for (int i = 0; i < a.length; ++i) {
      if (i != 0) prev.hashCode(); // OK
      prev = a[i];
    }

    String s = null;
    if (2 > 1) {
      boolean s_null = true;
      for (int i : a) {
        s_null = false;
        s = "" + a;
      }
      if (!s_null) s.hashCode(); // OK
    }

    Object r = null;
    MyStatus stat = MyStatus.INIT;
    while (stat == MyStatus.INIT && stat != MyStatus.READY) {
      r = mkMaybe();
      if (2 > 1)
        stat = MyStatus.READY;
    }
    r.hashCode(); // OK
  }

  public enum MyStatus {
    READY,
    INIT
  }

  public void g(Object obj) {
    String msg = null;
    if(obj == null)
      msg = "foo";
    else if(obj.hashCode() > 7) { // OK
      msg = "bar";
    }
    if(msg != null) {
      msg += "foobar";
      throw new RuntimeException(msg);
    }
    obj.hashCode(); // OK
  }

  public void loopCorr(int iters) {
    int[] a = null;
    if (iters > 0) a = new int[iters];
    for (int i = 0; i < iters; ++i)
      a[i] = 0; // NPE - false positive

    if (iters > 0) {
      String last = null;
      for (int i = 0; i < iters; i++) last = "abc";
      last.hashCode(); // OK
    }

    int[] b = maybe ? null : new int[iters];
    if (iters > 0 && (b == null || b.length < iters)) {
      throw new RuntimeException();
    }
    for (int i = 0; i < iters; ++i) {
      b[i] = 0; // NPE - false positive
    }
  }

  void test(Exception e, boolean b) {
    Exception ioe = null;
    if (b) {
      ioe = new Exception("");
    }
    if (ioe != null) {
      ioe = e;
    } else {
      ioe.getMessage(); // NPE; always
    }
  }

  public void lengthGuard2(int[] a, int[] b) {
    int alen = a == null ? 0 : a.length; // OK
    int sum = 0;
    int i;
    for(i = 0; i < alen; i++) {
      sum += a[i]; // OK
    }
    int blen = b == null ? 0 : b.length; // OK
    for(i = 0; i < blen; i++) {
      sum += b[i]; // OK
    }
    i = -3;
  }

  public void corrConds2(Object x, Object y) {
    if ((x != null && y == null) || (x == null && y != null)) return;
    if (x != null) y.hashCode(); // OK
    if (y != null) x.hashCode(); // OK
  }
}
