summaryrefslogtreecommitdiff
path: root/platform/duplicates-analysis/src/com/intellij/dupLocator/treeHash/TreeHashingUtils.java
blob: 115a3cf5b5667c6da6a53dae9e689a2f0129b65b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.intellij.dupLocator.treeHash;

import com.intellij.dupLocator.NodeSpecificHasher;
import com.intellij.dupLocator.util.PsiFragment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.source.tree.LeafElement;

import java.util.List;

/**
 * Created by Maxim.Mossienko on 2/17/14.
 */
public class TreeHashingUtils {
  protected static TreeHashResult hashCodeBlockForIndexing(AbstractTreeHasher treeHasher, FragmentsCollector callBack,
                                                           List<? extends PsiElement> statements,
                                                           PsiFragment upper,
                                                           NodeSpecificHasher hasher) {
    final int statementsSize = statements.size();

    if (statementsSize > 0) {
      final PsiFragment fragment = treeHasher.buildFragment(hasher, statements, 0, statementsSize - 1);
      fragment.setParent(upper);
      int cost = 0;
      int hash = 0;
      for (PsiElement statement : statements) {
        final TreeHashResult res = treeHasher.hash(statement, null, hasher);
        hash = hash* 31 + res.getHash();
        cost += res.getCost();
      }

      TreeHashResult result = new TreeHashResult(hash, cost, treeHasher.buildFragment(hasher, statements, 0, statementsSize - 1));
      if (callBack != null && statementsSize > 1) callBack.add(hash, cost, fragment);
      return result;
    }
    return new TreeHashResult(1, 0, treeHasher.buildFragment(hasher, statements, 0, statementsSize - 1));
  }
  static TreeHashResult computeElementHashForIndexing(AbstractTreeHasher base,
                                                      FragmentsCollector callBack,
                                                      PsiElement root,
                                                      PsiFragment upper,
                                                      NodeSpecificHasher hasher
  ) {
    final List<PsiElement> children = hasher.getNodeChildren(root);
    final PsiFragment fragment = base.buildFragment(hasher, root, base.getCost(root));

    if (upper != null) {
      fragment.setParent(upper);
    }

    final int size = children.size();
    if (size == 0 && !(root instanceof LeafElement)) {
      // contains only whitespaces and other unmeaning children
      return new TreeHashResult(0, hasher.getNodeCost(root), fragment);
    }

    final int discardCost = base.getDiscardCost(root);
    int c = hasher.getNodeCost(root);
    int h = hasher.getNodeHash(root);

    for (int i = 0; i < size; i++) {
      PsiElement child = children.get(i);
      final TreeHashResult res = base.hash(child, fragment, hasher);
      int childCost = res.getCost();
      c += childCost;
      if (childCost > discardCost || !base.ignoreChildHash(child)) {
        h += res.getHash();
      }
    }

    if (base.shouldAnonymize(root, hasher)) {
      h = 0;
    }

    if (callBack != null) {
      callBack.add(h, c, fragment);
    }

    return new TreeHashResult(h, c, fragment);
  }
}