TreeHashResult (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)); }