com.intellij.codeInsight.PsiEquivalenceUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core-api Show documentation
Show all versions of core-api Show documentation
A packaging of the IntelliJ Community Edition core-api library.
This is release number 1 of trunk branch 142.
The newest version!
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Couple;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.PairConsumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
* @author ven
*/
public class PsiEquivalenceUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.PsiEquivalenceUtil");
public static boolean areElementsEquivalent(@NotNull PsiElement element1,
@NotNull PsiElement element2,
@Nullable Comparator resolvedElementsComparator,
boolean areCommentsSignificant) {
return areElementsEquivalent(element1, element2, new ReferenceComparator(resolvedElementsComparator), null, null, areCommentsSignificant);
}
public static boolean areElementsEquivalent(@NotNull PsiElement element1,
@NotNull PsiElement element2,
@Nullable Comparator resolvedElementsComparator,
@Nullable Comparator leafElementsComparator) {
return areElementsEquivalent(element1, element2, new ReferenceComparator(resolvedElementsComparator), leafElementsComparator, null, false);
}
private static class ReferenceComparator implements Comparator {
private @Nullable final Comparator myResolvedElementsComparator;
ReferenceComparator(@Nullable Comparator resolvedElementsComparator) {
myResolvedElementsComparator = resolvedElementsComparator;
}
@Override
public int compare(PsiReference ref1, PsiReference ref2) {
PsiElement resolved1 = ref1.resolve();
PsiElement resolved2 = ref2.resolve();
return Comparing.equal(resolved1, resolved2) ||
myResolvedElementsComparator != null && myResolvedElementsComparator.compare(resolved1, resolved2) == 0 ? 0 : 1;
}
}
public static boolean areElementsEquivalent(@NotNull PsiElement element1,
@NotNull PsiElement element2,
@NotNull Comparator referenceComparator,
@Nullable Comparator leafElementsComparator,
@Nullable Condition isElementSignificantCondition,
boolean areCommentsSignificant) {
if(element1 == element2) return true;
ASTNode node1 = element1.getNode();
ASTNode node2 = element2.getNode();
if (node1 == null || node2 == null) return false;
if (node1.getElementType() != node2.getElementType()) return false;
PsiElement[] children1 = getFilteredChildren(element1, isElementSignificantCondition, areCommentsSignificant);
PsiElement[] children2 = getFilteredChildren(element2, isElementSignificantCondition, areCommentsSignificant);
if (children1.length != children2.length) return false;
for (int i = 0; i < children1.length; i++) {
PsiElement child1 = children1[i];
PsiElement child2 = children2[i];
if (!areElementsEquivalent(child1, child2, referenceComparator,
leafElementsComparator, isElementSignificantCondition, areCommentsSignificant)) return false;
}
if (children1.length == 0) {
if (leafElementsComparator != null) {
if (leafElementsComparator.compare(element1, element2) != 0) return false;
}
else {
if (!element1.textMatches(element2)) return false;
}
}
PsiReference ref1 = element1.getReference();
if (ref1 != null) {
PsiReference ref2 = element2.getReference();
if (ref2 == null) return false;
if (referenceComparator.compare(ref1, ref2) != 0) return false;
}
return true;
}
public static boolean areElementsEquivalent(@NotNull PsiElement element1, @NotNull PsiElement element2) {
return areElementsEquivalent(element1, element2, null, false);
}
public static PsiElement[] getFilteredChildren(@NotNull final PsiElement element,
@Nullable Condition isElementSignificantCondition,
boolean areCommentsSignificant) {
ASTNode[] children1 = element.getNode().getChildren(null);
ArrayList array = new ArrayList();
for (ASTNode node : children1) {
final PsiElement child = node.getPsi();
if (!(child instanceof PsiWhiteSpace) && (areCommentsSignificant || !(child instanceof PsiComment)) &&
(isElementSignificantCondition == null || isElementSignificantCondition.value(child))) {
array.add(child);
}
}
return PsiUtilCore.toPsiElementArray(array);
}
public static void findChildRangeDuplicates(PsiElement first, PsiElement last,
final List> result,
PsiElement scope) {
findChildRangeDuplicates(first, last, scope, new PairConsumer() {
@Override
public void consume(final PsiElement start, final PsiElement end) {
result.add(Couple.of(start, end));
}
});
}
public static void findChildRangeDuplicates(PsiElement first, PsiElement last, PsiElement scope,
PairConsumer consumer) {
LOG.assertTrue(first.getParent() == last.getParent());
LOG.assertTrue(!(first instanceof PsiWhiteSpace) && !(last instanceof PsiWhiteSpace));
addRangeDuplicates(scope, first, last, consumer);
}
private static void addRangeDuplicates(final PsiElement scope,
final PsiElement first,
final PsiElement last,
final PairConsumer result) {
final PsiElement[] children = getFilteredChildren(scope, null, true);
NextChild:
for (int i = 0; i < children.length;) {
PsiElement child = children[i];
if (child != first) {
int j = i;
PsiElement next = first;
do {
if (!areElementsEquivalent(children[j], next)) break;
j++;
if (next == last) {
result.consume(child, children[j - 1]);
i = j + 1;
continue NextChild;
}
next = PsiTreeUtil.skipSiblingsForward(next, PsiWhiteSpace.class);
}
while (true);
if (i == j) {
addRangeDuplicates(child, first, last, result);
}
}
i++;
}
}
}