package edu.umd.cs.findbugs;
import java.util.Iterator;
import java.util.NoSuchElementException;
import edu.umd.cs.findbugs.model.ClassNameRewriter;
import edu.umd.cs.findbugs.model.ClassNameRewriterUtil;
import edu.umd.cs.findbugs.model.IdentityClassNameRewriter;
public class VersionInsensitiveBugComparator implements WarningComparator {
private ClassNameRewriter classNameRewriter = IdentityClassNameRewriter.instance();
private boolean exactBugPatternMatch = true;
private boolean comparePriorities;
public VersionInsensitiveBugComparator() {
}
@Override
public void setClassNameRewriter(ClassNameRewriter classNameRewriter) {
this.classNameRewriter = classNameRewriter;
}
public void setComparePriorities(boolean b) {
comparePriorities = b;
}
private class FilteringAnnotationIterator implements Iterator<BugAnnotation> {
private final Iterator<BugAnnotation> iter;
private BugAnnotation next;
public FilteringAnnotationIterator(Iterator<BugAnnotation> iter) {
this.iter = iter;
this.next = null;
}
@Override
public boolean hasNext() {
findNext();
return next != null;
}
@Override
public BugAnnotation next() {
findNext();
if (next == null) {
throw new NoSuchElementException();
}
BugAnnotation result = next;
next = null;
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
private void findNext() {
while (next == null) {
if (!iter.hasNext()) {
break;
}
BugAnnotation candidate = iter.next();
if (!isBoring(candidate)) {
next = candidate;
break;
}
}
}
}
private boolean isBoring(BugAnnotation annotation) {
return !(annotation instanceof LocalVariableAnnotation || annotation.isSignificant());
}
@Override
public int compare(BugInstance lhs, BugInstance rhs) {
int cmp;
BugPattern lhsPattern = lhs.getBugPattern();
BugPattern rhsPattern = rhs.getBugPattern();
if ((cmp = lhsPattern.getAbbrev().compareTo(rhsPattern.getAbbrev())) != 0) {
return cmp;
}
if (isExactBugPatternMatch() && (cmp = lhsPattern.getType().compareTo(rhsPattern.getType())) != 0) {
return cmp;
}
if (comparePriorities) {
cmp = lhs.getPriority() - rhs.getPriority();
if (cmp != 0) {
return cmp;
}
}
Iterator<BugAnnotation> lhsIter = new FilteringAnnotationIterator(lhs.annotationIterator());
Iterator<BugAnnotation> rhsIter = new FilteringAnnotationIterator(rhs.annotationIterator());
while (lhsIter.hasNext() && rhsIter.hasNext()) {
BugAnnotation lhsAnnotation = lhsIter.next();
BugAnnotation rhsAnnotation = rhsIter.next();
Class<? extends BugAnnotation> lhsClass;
while (true) {
lhsClass = lhsAnnotation.getClass();
Class<? extends BugAnnotation> rhsClass = rhsAnnotation.getClass();
if (lhsClass == rhsClass) {
break;
}
if (lhsClass == LocalVariableAnnotation.class && !((LocalVariableAnnotation) lhsAnnotation).isSignificant()
&& lhsIter.hasNext()) {
lhsAnnotation = lhsIter.next();
} else if (rhsClass == LocalVariableAnnotation.class && !((LocalVariableAnnotation) rhsAnnotation).isSignificant()
&& rhsIter.hasNext()) {
rhsAnnotation = rhsIter.next();
} else {
return lhsClass.getName().compareTo(rhsClass.getName());
}
}
if (lhsClass == ClassAnnotation.class) {
String lhsClassName = classNameRewriter.rewriteClassName(((ClassAnnotation) lhsAnnotation).getClassName());
String rhsClassName = classNameRewriter.rewriteClassName(((ClassAnnotation) rhsAnnotation).getClassName());
cmp = lhsClassName.compareTo(rhsClassName);
} else if (lhsClass == MethodAnnotation.class) {
MethodAnnotation lhsMethod = ClassNameRewriterUtil.convertMethodAnnotation(classNameRewriter,
(MethodAnnotation) lhsAnnotation);
MethodAnnotation rhsMethod = ClassNameRewriterUtil.convertMethodAnnotation(classNameRewriter,
(MethodAnnotation) rhsAnnotation);
cmp = lhsMethod.compareTo(rhsMethod);
} else if (lhsClass == FieldAnnotation.class) {
FieldAnnotation lhsField = ClassNameRewriterUtil.convertFieldAnnotation(classNameRewriter,
(FieldAnnotation) lhsAnnotation);
FieldAnnotation rhsField = ClassNameRewriterUtil.convertFieldAnnotation(classNameRewriter,
(FieldAnnotation) rhsAnnotation);
cmp = lhsField.compareTo(rhsField);
} else if (lhsClass == StringAnnotation.class) {
String lhsString = ((StringAnnotation) lhsAnnotation).getValue();
String rhsString = ((StringAnnotation) rhsAnnotation).getValue();
cmp = lhsString.compareTo(rhsString);
} else if (lhsClass == LocalVariableAnnotation.class) {
String lhsName = ((LocalVariableAnnotation) lhsAnnotation).getName();
String rhsName = ((LocalVariableAnnotation) rhsAnnotation).getName();
if ("?".equals(lhsName) || "?".equals(rhsName)) {
continue;
}
cmp = lhsName.compareTo(rhsName);
} else if (lhsClass == TypeAnnotation.class) {
String lhsType = ((TypeAnnotation) lhsAnnotation).getTypeDescriptor();
String rhsType = ((TypeAnnotation) rhsAnnotation).getTypeDescriptor();
lhsType = ClassNameRewriterUtil.rewriteSignature(classNameRewriter, lhsType);
rhsType = ClassNameRewriterUtil.rewriteSignature(classNameRewriter, rhsType);
cmp = lhsType.compareTo(rhsType);
} else if (lhsClass == IntAnnotation.class) {
int lhsValue = ((IntAnnotation) lhsAnnotation).getValue();
int rhsValue = ((IntAnnotation) rhsAnnotation).getValue();
cmp = lhsValue - rhsValue;
} else if (isBoring(lhsAnnotation)) {
throw new IllegalStateException("Impossible");
} else {
throw new IllegalStateException("Unknown annotation type: " + lhsClass.getName());
}
if (cmp != 0) {
return cmp;
}
}
if (interestingNext(rhsIter)) {
return -1;
} else if (interestingNext(lhsIter)) {
return 1;
} else {
return 0;
}
}
private boolean interestingNext(Iterator<BugAnnotation> i) {
while (i.hasNext()) {
BugAnnotation a = i.next();
if (isBoring(a)) {
continue;
}
if (!(a instanceof LocalVariableAnnotation)) {
return true;
}
if (((LocalVariableAnnotation) a).isSignificant()) {
return true;
}
}
return false;
}
public void setExactBugPatternMatch(boolean exactBugPatternMatch) {
this.exactBugPatternMatch = exactBugPatternMatch;
}
public boolean isExactBugPatternMatch() {
return exactBugPatternMatch;
}
}