| package com.intellij.dupLocator.treeHash; |
| |
| import com.intellij.dupLocator.DuplocatorSettings; |
| import com.intellij.dupLocator.NodeSpecificHasher; |
| import com.intellij.dupLocator.iterators.FilteringNodeIterator; |
| import com.intellij.dupLocator.iterators.SiblingNodeIterator; |
| import com.intellij.dupLocator.util.DuplocatorUtil; |
| import com.intellij.dupLocator.util.NodeFilter; |
| import com.intellij.lang.Language; |
| import com.intellij.psi.PsiElement; |
| import com.intellij.psi.PsiErrorElement; |
| import com.intellij.psi.PsiWhiteSpace; |
| import com.intellij.psi.impl.source.tree.LeafElement; |
| import com.intellij.psi.tree.IElementType; |
| import org.jetbrains.annotations.NotNull; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * @author Eugene.Kudelevsky |
| */ |
| public class NodeSpecificHasherBase extends NodeSpecificHasher { |
| private final TreeHasherBase myTreeHasher; |
| private final DuplocatorSettings mySettings; |
| private final DuplicatesProfileBase myDuplicatesProfile; |
| |
| private final NodeFilter myNodeFilter = new NodeFilter() { |
| @Override |
| public boolean accepts(PsiElement element) { |
| return DuplocatorUtil.isIgnoredNode(element) || isToSkipAsLiteral(element); |
| } |
| }; |
| protected final boolean myForIndexing; |
| |
| private boolean isToSkipAsLiteral(PsiElement element) { |
| return isLiteral(element) && |
| !myDuplicatesProfile.getDuplocatorState(myDuplicatesProfile.getLanguage(element)).distinguishLiterals(); |
| } |
| |
| public NodeSpecificHasherBase(@NotNull final DuplocatorSettings settings, |
| @NotNull FragmentsCollector callback, |
| @NotNull DuplicatesProfileBase duplicatesProfile) { |
| this(settings, callback, duplicatesProfile, false); |
| } |
| |
| public NodeSpecificHasherBase(@NotNull final DuplocatorSettings settings, |
| @NotNull FragmentsCollector callback, |
| @NotNull DuplicatesProfileBase duplicatesProfile, |
| boolean forIndexing) { |
| myTreeHasher = new TreeHasherBase(callback, duplicatesProfile, forIndexing ? 0:-1, forIndexing); |
| mySettings = settings; |
| myDuplicatesProfile = duplicatesProfile; |
| myForIndexing = forIndexing; |
| } |
| |
| @NotNull |
| public NodeFilter getNodeFilter() { |
| return myNodeFilter; |
| } |
| |
| @Override |
| public int getNodeHash(PsiElement node) { |
| if (node == null) { |
| return 0; |
| } |
| if (node instanceof PsiWhiteSpace || node instanceof PsiErrorElement) { |
| return 0; |
| } |
| else if (node instanceof LeafElement) { |
| if (isToSkipAsLiteral(node)) { |
| return 0; |
| } |
| return node.getText().hashCode(); |
| |
| } |
| return node.getClass().getName().hashCode(); |
| } |
| |
| private boolean isLiteral(PsiElement node) { |
| if (node instanceof LeafElement) { |
| final IElementType elementType = ((LeafElement)node).getElementType(); |
| if (myDuplicatesProfile.getLiterals().contains(elementType)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public int getNodeCost(PsiElement node) { |
| return node != null ? myDuplicatesProfile.getNodeCost(node) : 0; |
| } |
| |
| @Override |
| public List<PsiElement> getNodeChildren(PsiElement node) { |
| final List<PsiElement> result = new ArrayList<PsiElement>(); |
| |
| final FilteringNodeIterator it = new FilteringNodeIterator(new SiblingNodeIterator(node.getFirstChild()), myNodeFilter); |
| while (it.hasNext()) { |
| result.add(it.current()); |
| it.advance(); |
| } |
| |
| return result; |
| } |
| |
| @Override |
| public boolean areNodesEqual(@NotNull PsiElement node1, @NotNull PsiElement node2) { |
| return false; |
| } |
| |
| @Override |
| public boolean areTreesEqual(@NotNull PsiElement root1, @NotNull PsiElement root2, int discardCost) { |
| if (root1 == root2) { |
| return true; |
| } |
| return new DuplicatesMatchingVisitor(this, myNodeFilter, discardCost).match(root1, root2); |
| } |
| |
| @NotNull |
| public DuplicatesProfileBase getDuplicatesProfile() { |
| return myDuplicatesProfile; |
| } |
| |
| @Override |
| public boolean checkDeep(PsiElement node1, PsiElement node2) { |
| // todo: try to optimize this |
| return true; |
| } |
| |
| @Override |
| public void visitNode(@NotNull PsiElement node) { |
| final Language language = node.getLanguage(); |
| if ((myForIndexing || mySettings.SELECTED_PROFILES.contains(language.getDisplayName())) && |
| myDuplicatesProfile.isMyLanguage(language)) { |
| |
| myTreeHasher.hash(node, this); |
| } |
| } |
| |
| @Override |
| public void hashingFinished() { |
| } |
| } |