private TreeHashResult computeHash(PsiElement root, PsiFragment upper, NodeSpecificHasher hasher) {
    final EquivalenceDescriptorProvider descriptorProvider = EquivalenceDescriptorProvider.getInstance(root);

    if (descriptorProvider != null) {
      final EquivalenceDescriptor descriptor = descriptorProvider.buildDescriptor(root);

      if (descriptor != null) {
        return computeHash(root, upper, descriptor, hasher);
      }
    }

    if (root instanceof PsiFile) {
      final List<PsiElement> children = hasher.getNodeChildren(root);
      if (children.size() <= 20) {
        return hashCodeBlock(children, upper, hasher, true);
      }
    }

    final NodeSpecificHasherBase ssrNodeSpecificHasher = (NodeSpecificHasherBase)hasher;

    if (shouldBeAnonymized(root, ssrNodeSpecificHasher)) {
      return computeElementHash(root, upper, hasher);
    }

    if (myForIndexing) {
      return computeElementHash(root, upper, hasher);
    }

    final PsiElement element = DuplocatorUtil.getOnlyChild(root, ssrNodeSpecificHasher.getNodeFilter());
    if (element != root) {
      final TreeHashResult result = hash(element, upper, hasher);
      final int cost = hasher.getNodeCost(root);
      return new TreeHashResult(result.getHash(), result.getCost() + cost, result.getFragment());
    }

    return computeElementHash(element, upper, hasher);
  }
private TreeHashResult computeHash(PsiElement root, PsiFragment upper, NodeSpecificHasher hasher)