1 19 20 package edu.umd.cs.findbugs; 21 22 import java.io.Serializable ; 23 import java.util.HashSet ; 24 import java.util.IdentityHashMap ; 25 import java.util.Iterator ; 26 import java.util.Map ; 27 import java.util.NoSuchElementException ; 28 import java.util.TreeMap ; 29 30 import edu.umd.cs.findbugs.ba.ClassHash; 31 import edu.umd.cs.findbugs.model.ClassNameRewriter; 32 33 48 public class FuzzyBugComparator implements WarningComparator { 49 private static final boolean DEBUG = false; 50 51 private static final boolean USE_HASHES = false; 53 54 private static final long serialVersionUID = 1L; 55 56 59 private static class FilteringBugAnnotationIterator implements Iterator <BugAnnotation> { 60 61 Iterator <BugAnnotation> iter; 62 BugAnnotation next; 63 64 public FilteringBugAnnotationIterator(Iterator <BugAnnotation> iter) { 65 this.iter = iter; 66 } 67 68 private void findNext() { 69 if (next == null) { 70 while (iter.hasNext()) { 71 BugAnnotation candidate = iter.next(); 72 if (!ignore(candidate)) { 73 next = candidate; 74 break; 75 } 76 } 77 } 78 } 79 80 83 public boolean hasNext() { 84 findNext(); 85 return next != null; 86 } 87 88 91 public BugAnnotation next() { 92 findNext(); 93 if (next == null) 94 throw new NoSuchElementException (); 95 BugAnnotation result = next; 96 next = null; 97 return result; 98 } 99 100 103 public void remove() { 104 throw new UnsupportedOperationException (); 105 } 106 } 107 108 109 private IdentityHashMap <BugInstance, BugCollection> bugCollectionMap; 110 111 private ClassNameRewriter classNameRewriter; 112 113 116 118 public FuzzyBugComparator() { 119 if (DEBUG) System.out.println("Created fuzzy comparator"); 120 this.bugCollectionMap = new IdentityHashMap <BugInstance, BugCollection>(); 121 } 123 124 130 public void registerBugCollection(BugCollection bugCollection) { 131 } 133 134 137 public void setClassNameRewriter(ClassNameRewriter classNameRewriter) { 138 this.classNameRewriter = classNameRewriter; 139 } 140 141 public int compare(BugInstance lhs, BugInstance rhs) { 142 int cmp; 143 144 if (DEBUG) System.out.println("Fuzzy comparison"); 145 146 BugPattern lhsPattern = lhs.getBugPattern(); 148 BugPattern rhsPattern = rhs.getBugPattern(); 149 150 if (lhsPattern == null || rhsPattern == null) { 151 if (DEBUG) { 152 if (lhsPattern == null) 153 System.out.println("Missing pattern: " + lhs.getType()); 154 if (rhsPattern == null) 155 System.out.println("Missing pattern: " + rhs.getType()); 156 } 157 String lhsCode = getCode(lhs.getType()); 158 String rhsCode = getCode(rhs.getType()); 159 if ((cmp = lhsCode.compareTo(rhsCode)) != 0) 160 return cmp; 161 } else { 162 if ((cmp = lhsPattern.getAbbrev().compareTo(rhsPattern.getAbbrev())) != 0) 163 return cmp; 164 } 165 166 BugCollection lhsCollection = bugCollectionMap.get(lhs); 167 BugCollection rhsCollection = bugCollectionMap.get(rhs); 168 169 171 Iterator <BugAnnotation> lhsIter = new FilteringBugAnnotationIterator(lhs.annotationIterator()); 172 Iterator <BugAnnotation> rhsIter = new FilteringBugAnnotationIterator(rhs.annotationIterator()); 173 174 while (lhsIter.hasNext() && rhsIter.hasNext()) { 175 BugAnnotation lhsAnnotation = lhsIter.next(); 176 BugAnnotation rhsAnnotation = rhsIter.next(); 177 178 if (DEBUG) System.out.println("Compare annotations: " + lhsAnnotation + "," + rhsAnnotation); 179 180 cmp = lhsAnnotation.getClass().getName().compareTo(rhsAnnotation.getClass().getName()); 182 if (cmp != 0) { 183 if (DEBUG) System.out.println("annotation class mismatch: " + lhsAnnotation.getClass().getName() + 184 "," + rhsAnnotation.getClass().getName()); 185 return cmp; 186 } 187 188 if (lhsAnnotation.getClass() == ClassAnnotation.class) 189 cmp = compareClasses(lhsCollection, rhsCollection, (ClassAnnotation) lhsAnnotation, (ClassAnnotation) rhsAnnotation); 190 else if (lhsAnnotation.getClass() == MethodAnnotation.class) 191 cmp = compareMethods(lhsCollection, rhsCollection, (MethodAnnotation) lhsAnnotation, (MethodAnnotation) rhsAnnotation); 192 else if (lhsAnnotation.getClass() == SourceLineAnnotation.class) 193 cmp = compareSourceLines(lhsCollection, rhsCollection, (SourceLineAnnotation) lhsAnnotation, (SourceLineAnnotation) rhsAnnotation); 194 else 195 cmp = lhsAnnotation.compareTo(rhsAnnotation); 197 198 if (cmp != 0) 199 return cmp; 200 } 201 202 if (!lhsIter.hasNext() && !rhsIter.hasNext()) { 204 if (DEBUG) System.out.println("Match!"); 205 return 0; 206 } else 207 return (lhsIter.hasNext() ? 1 : -1); 208 } 209 210 214 private String getCode(String type) { 215 int bar = type.indexOf('_'); 216 if (bar < 0) 217 return ""; 218 else 219 return type.substring(0, bar); 220 } 221 222 private static int compareNullElements(Object a, Object b) { 223 if (a != null) 224 return 1; 225 else if (b != null) 226 return -1; 227 else 228 return 0; 229 } 230 231 public int compareClasses(BugCollection lhsCollection, BugCollection rhsCollection, ClassAnnotation lhsClass, ClassAnnotation rhsClass) { 232 if (lhsClass == null || rhsClass == null) { 233 return compareNullElements(lhsClass, rhsClass); 234 } else { 235 return compareClassesByName(lhsCollection, rhsCollection, lhsClass.getClassName(), rhsClass.getClassName()); 236 } 237 } 238 239 public int compareClassesByName(BugCollection lhsCollection, BugCollection rhsCollection, String lhsClassName, String rhsClassName) { 241 242 lhsClassName = rewriteClassName(lhsClassName); 243 rhsClassName = rewriteClassName(rhsClassName); 244 245 return lhsClassName.compareTo(rhsClassName); 246 } 247 248 252 private String rewriteClassName(String className) { 253 if (classNameRewriter != null) { 254 className = classNameRewriter.rewriteClassName(className); 255 } 256 return className; 257 } 258 259 public int compareMethods(BugCollection lhsCollection, BugCollection rhsCollection, MethodAnnotation lhsMethod, MethodAnnotation rhsMethod) { 261 if (lhsMethod == null || rhsMethod == null) { 262 return compareNullElements(lhsMethod, rhsMethod); 263 } 264 265 int cmp = lhsMethod.compareTo(rhsMethod); 267 268 return cmp; 269 } 270 271 275 private static final int NUM_CONTEXT_OPCODES = 2; 276 277 286 public int compareSourceLines(BugCollection lhsCollection, BugCollection rhsCollection, SourceLineAnnotation lhs, SourceLineAnnotation rhs) { 287 if (lhs == null || rhs == null) { 288 return compareNullElements(lhs, rhs); 289 } 290 291 int cmp = compareClassesByName(lhsCollection, rhsCollection, lhs.getClassName(), rhs.getClassName()); 293 if (cmp != 0) 294 return cmp; 295 296 return 0; 297 } 298 299 private static final HashSet <String > significantDescriptionSet = new HashSet <String >(); 301 static { 302 significantDescriptionSet.add("CLASS_DEFAULT"); 304 significantDescriptionSet.add("CLASS_EXCEPTION"); 305 significantDescriptionSet.add("CLASS_REFTYPE"); 306 significantDescriptionSet.add("INTERFACE_TYPE"); 307 significantDescriptionSet.add("METHOD_DEFAULT"); 308 significantDescriptionSet.add("METHOD_CALLED"); 309 significantDescriptionSet.add("METHOD_DANGEROUS_TARGET"); significantDescriptionSet.add("METHOD_DECLARED_NONNULL"); 311 significantDescriptionSet.add("FIELD_DEFAULT"); 312 significantDescriptionSet.add("FIELD_ON"); 313 significantDescriptionSet.add("FIELD_SUPER"); 314 significantDescriptionSet.add("FIELD_MASKED"); 315 significantDescriptionSet.add("FIELD_MASKING"); 316 significantDescriptionSet.add("INT_NULL_ARG"); 319 significantDescriptionSet.add("INT_MAYBE_NULL_ARG"); 320 significantDescriptionSet.add("INT_NONNULL_PARAM"); 321 significantDescriptionSet.add("SOURCE_LINE_DEFAULT"); 323 } 324 325 public static boolean ignore(BugAnnotation annotation) { 326 return !significantDescriptionSet.contains(annotation.getDescription()); 327 } 328 } 329 | Popular Tags |