public boolean equals(Object o) {
      if (o instanceof SLeak) {
        final SLeak l = (SLeak) o;
        return source.equals(l.source) && sink.equals(l.sink);
      }

      return false;
    }
    @Override
    public int compareTo(final SLeak o) {
      if (o == this || this.equals(o)) {
        return 0;
      }

      if (!source.equals(o.source)) {
        return source.compareTo(o.source);
      }

      if (!sink.equals(o.sink)) {
        return sink.compareTo(o.sink);
      }

      return 0;
    }
    public String toString() {
      String info = "";
      switch (reason) {
        case BOTH_FLOW:
          info = "direct and indirect flow ";
          break;
        case DIRECT_FLOW:
          info = "direct flow ";
          break;
        case INDIRECT_FLOW:
          info = "indirect flow ";
          break;
        case EXCEPTION:
          info = "flow caused by exceptions ";
          break;
        case THREAD:
          info = "critical thread interference ";
          break;
        case THREAD_DATA:
          info = "critical thread interference (data) ";
          break;
        case THREAD_ORDER:
          info = "critical thread interference (order) ";
          break;
        case THREAD_EXCEPTION:
          info = "critical thread interference caused by exceptions ";
          break;
      }

      switch (reason) {
        case THREAD:
        case THREAD_DATA:
        case THREAD_ORDER:
        case THREAD_EXCEPTION:
          info += "between '" + source.toString() + "' and '" + sink.toString() + "'";
          break;
        default:
          info += "from '" + source.toString() + "' to '" + sink.toString() + "'";
      }

      return info;
    }
    public String toString(final File srcFile) {
      StringBuffer sbuf = new StringBuffer();
      switch (reason) {
        case DIRECT_FLOW:
          sbuf.append("direct flow:\n");
          break;
        case INDIRECT_FLOW:
          sbuf.append("indirect flow:\n");
          break;
        case BOTH_FLOW:
          sbuf.append("direct and indirect flow:\n");
          break;
        case EXCEPTION:
          sbuf.append("flow due to exceptions:\n");
          break;
        case THREAD:
          sbuf.append("possibilistic or probabilistic flow:\n");
          break;
        case THREAD_DATA:
          sbuf.append("possibilistic flow:\n");
          break;
        case THREAD_ORDER:
          sbuf.append("probabilistic flow:\n");
          break;
        case THREAD_EXCEPTION:
          sbuf.append("possibilistic or probabilistic flow caused by exceptions:\n");
          break;
        default:
          sbuf.append("reason: " + reason + "\n");
      }

      sbuf.append("from '" + source.toString() + "' to '" + sink.toString() + "'\n");

      for (final SPos pos : chop) {
        sbuf.append(pos.toString() + "\t");
        final String code = pos.getSourceCode(srcFile);
        sbuf.append(code + "\n");
      }

      return sbuf.toString();
    }
 public int hashCode() {
   return source.hashCode() + 23 * sink.hashCode();
 }