protected TreeHashResult hashCodeBlock(final List<? extends PsiElement> statements,
                                         final PsiFragment upper,
                                         final NodeSpecificHasher hasher,
                                         boolean forceHash) {
    final int statementsSize = statements.size();
    if (statementsSize == 1) {
      return hash(statements.get(0), upper, hasher);
    }
    if (statementsSize > 0) {
      // Here we compute all the possible code fragments using statements
      if (statementsSize < 20 || forceHash) {   //todo should be configurable
        final PsiFragment[] frags = new PsiFragment[statementsSize];

        final PsiFragment fragment = buildFragment(hasher, statements, 0, statementsSize - 1);
        fragment.setParent(upper);

        // Fill all the statements costs and hashes
        final int[] hashes = new int[statementsSize];
        final int[] costs = new int[statementsSize];
        for (int i = 0; i < statementsSize; i++) {
          final TreeHashResult res = hash(statements.get(i), null, hasher);
          hashes[i] = res.getHash();
          costs[i] = res.getCost();
          frags[i] = res.getFragment();
        }

        if (myCallBack != null) {
          final PsiFragment[] parents = new PsiFragment[statementsSize]; //parent(end) = [beg, end]
          for (int beg = 0; beg < statementsSize; beg++) {
            int hash = 0;
            int cost = 0;
            for (int end = beg; end < statementsSize && end - beg < 20; end++) {
              hash = 31 * hash + hashes[end];
              cost += costs[end];
              final PsiFragment curr =
                beg == end
                ? frags[beg]
                : beg == 0 && end == statementsSize - 1 ? fragment : buildFragment(hasher, statements, beg, end);
              if (beg > 0) {
                curr.setParent(parents[end]); //[beg, end].setParent([beg - 1, end])
              }
              parents[end] = curr;
              if (end > beg) {
                parents[end - 1].setParent(curr);//[beg, end - 1].setParent([beg, end])
              }
              myCallBack.add(hash, cost, curr);
            }
          }
        }
        return new TreeHashResult(vector(hashes, 31), vector(costs), fragment);
      }
    }
    return new TreeHashResult(1, 0, buildFragment(hasher, statements, 0, statementsSize - 1));
  }
protected TreeHashResult hashCodeBlock(final List<? extends PsiElement> statements,
                                         final PsiFragment upper,
                                         final NodeSpecificHasher hasher,
                                         boolean forceHash)