| 1 19 20 package edu.umd.cs.findbugs; 21 22 import java.io.IOException ; 23 import java.io.Serializable ; 24 import java.math.BigInteger ; 25 import java.security.MessageDigest ; 26 import java.util.ArrayList ; 27 import java.util.Collection ; 28 import java.util.HashSet ; 29 import java.util.Iterator ; 30 import java.util.NoSuchElementException ; 31 import java.util.Set ; 32 import java.util.StringTokenizer ; 33 34 import org.apache.bcel.Constants; 35 import org.apache.bcel.classfile.JavaClass; 36 import org.apache.bcel.classfile.Method; 37 import org.apache.bcel.generic.ConstantPoolGen; 38 import org.apache.bcel.generic.InstructionHandle; 39 import org.apache.bcel.generic.InvokeInstruction; 40 import org.apache.bcel.generic.MethodGen; 41 42 import edu.umd.cs.findbugs.annotations.NonNull; 43 import edu.umd.cs.findbugs.annotations.Nullable; 44 import edu.umd.cs.findbugs.annotations.CheckForNull; 45 import edu.umd.cs.findbugs.ba.AnalysisContext; 46 import edu.umd.cs.findbugs.ba.ClassContext; 47 import edu.umd.cs.findbugs.ba.JavaClassAndMethod; 48 import edu.umd.cs.findbugs.ba.Location; 49 import edu.umd.cs.findbugs.ba.XFactory; 50 import edu.umd.cs.findbugs.ba.XField; 51 import edu.umd.cs.findbugs.ba.XMethod; 52 import edu.umd.cs.findbugs.ba.bcp.FieldVariable; 53 import edu.umd.cs.findbugs.classfile.ClassDescriptor; 54 import edu.umd.cs.findbugs.classfile.FieldDescriptor; 55 import edu.umd.cs.findbugs.classfile.MethodDescriptor; 56 import edu.umd.cs.findbugs.util.ClassName; 57 import edu.umd.cs.findbugs.visitclass.DismantleBytecode; 58 import edu.umd.cs.findbugs.visitclass.PreorderVisitor; 59 import edu.umd.cs.findbugs.xml.XMLAttributeList; 60 import edu.umd.cs.findbugs.xml.XMLOutput; 61 62 87 public class BugInstance implements Comparable <BugInstance>, XMLWriteableWithMessages, Serializable , Cloneable { 88 private static final long serialVersionUID = 1L; 89 90 private String type; 91 private int priority; 92 private ArrayList <BugAnnotation> annotationList; 93 private int cachedHashCode; 94 private @CheckForNull BugDesignation userDesignation; 95 private BugProperty propertyListHead, propertyListTail; 96 private String uniqueId; 97 private String oldInstanceHash; 98 private String instanceHash; 99 private int instanceOccurrenceNum; 100 private int instanceOccurrenceMax; 101 102 103 107 private long firstVersion = 0; 108 private long lastVersion = -1; 109 private boolean introducedByChangeOfExistingClass; 110 private boolean removedByChangeOfPersistingClass; 111 112 116 private static final int INVALID_HASH_CODE = 0; 117 118 122 private static boolean adjustExperimental = false; 123 124 130 public BugInstance(String type, int priority) { 131 this.type = type; 132 this.priority = priority < Detector.HIGH_PRIORITY 133 ? Detector.HIGH_PRIORITY : priority; 134 annotationList = new ArrayList <BugAnnotation>(4); 135 cachedHashCode = INVALID_HASH_CODE; 136 137 if (adjustExperimental && isExperimental()) 138 this.priority = Detector.EXP_PRIORITY; 139 } 140 141 @Override  143 public Object clone() { 144 BugInstance dup; 145 146 try { 147 dup = (BugInstance) super.clone(); 148 149 for (int i = 0; i < dup.annotationList.size(); ++i) { 151 dup.annotationList.set(i, (BugAnnotation) dup.annotationList.get(i).clone()); 152 } 153 dup.propertyListHead = dup.propertyListTail = null; 154 for (Iterator <BugProperty> i = propertyIterator(); i.hasNext(); ) { 155 dup.addProperty((BugProperty) i.next().clone()); 156 } 157 158 return dup; 159 } catch (CloneNotSupportedException e) { 160 throw new AssertionError (e); 161 } 162 } 163 164 172 public BugInstance(Detector detector, String type, int priority) { 173 this(type, priority); 174 175 if (detector != null) { 176 DetectorFactory factory = 178 DetectorFactoryCollection.instance().getFactoryByClassName(detector.getClass().getName()); 179 if (factory != null) { 180 this.priority += factory.getPriorityAdjustment(); 181 if (this.priority < 0) 182 this.priority = 0; 183 } 184 } 185 186 if (adjustExperimental && isExperimental()) 187 this.priority = Detector.EXP_PRIORITY; 188 } 189 190 public static void setAdjustExperimental(boolean adjust) { 191 adjustExperimental = adjust; 192 } 193 194 197 198 201 public String getType() { 202 return type; 203 } 204 205 208 public BugPattern getBugPattern() { 209 return I18N.instance().lookupBugPattern(getType()); 210 } 211 212 215 public int getPriority() { 216 return priority; 217 } 218 219 222 public void setPriority(int p) { 223 priority = Math.max(Detector.HIGH_PRIORITY, Math.min(Detector.IGNORE_PRIORITY, p)); 224 } 225 public void raisePriority() { 226 priority = Math.max(Detector.HIGH_PRIORITY, Math.min(Detector.IGNORE_PRIORITY, priority-1)); 227 } 228 public void lowerPriority() { 229 priority = Math.max(Detector.HIGH_PRIORITY, Math.min(Detector.IGNORE_PRIORITY, priority+1)); 230 } 231 232 public void lowerPriorityALot() { 233 priority = Math.max(Detector.HIGH_PRIORITY, Math.min(Detector.IGNORE_PRIORITY, priority+2)); 234 } 235 236 239 public boolean isExperimental() { 240 BugPattern pattern = I18N.instance().lookupBugPattern(type); 241 return (pattern != null) && pattern.isExperimental(); 242 } 243 244 247 public ClassAnnotation getPrimaryClass() { 248 return (ClassAnnotation) findAnnotationOfType(ClassAnnotation.class); 249 } 250 251 254 public MethodAnnotation getPrimaryMethod() { 255 return (MethodAnnotation) findAnnotationOfType(MethodAnnotation.class); 256 } 257 260 public FieldAnnotation getPrimaryField() { 261 return (FieldAnnotation) findAnnotationOfType(FieldAnnotation.class); 262 } 263 264 265 public BugInstance lowerPriorityIfDeprecated() { 266 MethodAnnotation m = getPrimaryMethod(); 267 if (m != null && AnalysisContext.currentXFactory().getDeprecated().contains(XFactory.createXMethod(m))) 268 priority++; 269 FieldAnnotation f = getPrimaryField(); 270 if (f != null && AnalysisContext.currentXFactory().getDeprecated().contains(XFactory.createXField(f))) 271 priority++; 272 return this; 273 } 274 282 private BugAnnotation findAnnotationOfType(Class <? extends BugAnnotation> cls) { 283 for (Iterator <BugAnnotation> i = annotationIterator(); i.hasNext();) { 284 BugAnnotation annotation = i.next(); 285 if (cls.isAssignableFrom(annotation.getClass())) 286 return annotation; 287 } 288 return null; 289 } 290 291 public LocalVariableAnnotation getPrimaryLocalVariableAnnotation() { 292 for (BugAnnotation annotation : annotationList) 293 if (annotation instanceof LocalVariableAnnotation) 294 return (LocalVariableAnnotation) annotation; 295 return null; 296 } 297 304 public SourceLineAnnotation getPrimarySourceLineAnnotation() { 305 for (BugAnnotation annotation : annotationList) { 307 if (annotation instanceof SourceLineAnnotation) 308 return (SourceLineAnnotation) annotation; 309 } 310 311 SourceLineAnnotation srcLine; 313 if ((srcLine = inspectPackageMemberSourceLines(getPrimaryMethod())) != null) 314 return srcLine; 315 if ((srcLine = inspectPackageMemberSourceLines(getPrimaryField())) != null) 316 return srcLine; 317 if ((srcLine = inspectPackageMemberSourceLines(getPrimaryClass())) != null) 318 return srcLine; 319 320 throw new IllegalStateException ("BugInstance must contain at least one class, method, or field annotation"); 322 } 323 324 public String getInstanceKey() { 325 StringBuffer buf = new StringBuffer (type); 326 for (BugAnnotation annotation : annotationList) { 327 if (annotation instanceof SourceLineAnnotation) { 328 } else { 330 buf.append(":"); 331 buf.append(annotation.format("hash", null)); 332 } 333 } 334 return buf.toString(); 335 } 336 345 private SourceLineAnnotation inspectPackageMemberSourceLines(PackageMemberAnnotation packageMember) { 346 return (packageMember != null) ? packageMember.getSourceLines() : null; 347 } 348 349 352 public Iterator <BugAnnotation> annotationIterator() { 353 return annotationList.iterator(); 354 } 355 356 361 public String getAbbrev() { 362 BugPattern pattern = I18N.instance().lookupBugPattern(getType()); 363 return pattern != null ? pattern.getAbbrev() : "<unknown bug pattern>"; 364 } 365 366 368 public void setUserDesignation(BugDesignation bd) { 369 userDesignation = bd; 370 } 371 377 @Nullable public BugDesignation getUserDesignation() { 378 return userDesignation; 379 } 380 385 @NonNull public BugDesignation getNonnullUserDesignation() { 386 if (userDesignation == null) 387 userDesignation = new BugDesignation(); 388 return userDesignation; 389 } 390 391 392 403 @NonNull public String getUserDesignationKey() { 404 BugDesignation userDesignation = this.userDesignation; 405 if (userDesignation == null) return BugDesignation.UNCLASSIFIED; 406 return userDesignation.getDesignationKey(); 407 } 408 409 414 public void setAnnotationText(String annotationText) { 415 getNonnullUserDesignation().setAnnotationText(annotationText); 416 } 417 418 423 @NonNull public String getAnnotationText() { 424 BugDesignation userDesignation = this.userDesignation; 425 if (userDesignation == null) return ""; 426 String s = userDesignation.getAnnotationText(); 427 if (s == null) return ""; 428 return s; 429 } 430 431 438 public boolean annotationTextContainsWord(String word) { 439 return getTextAnnotationWords().contains(word); 440 } 441 442 445 public Set <String > getTextAnnotationWords() { 446 HashSet <String > result = new HashSet <String >(); 447 448 StringTokenizer tok = new StringTokenizer (getAnnotationText(), " \t\r\n\f.,:;-"); 449 while (tok.hasMoreTokens()) { 450 result.add(tok.nextToken()); 451 } 452 return result; 453 } 454 455 462 @Deprecated  463 public String getUniqueId() { 464 return uniqueId; 465 } 466 467 474 @Deprecated  475 void setUniqueId(String uniqueId) { 476 this.uniqueId = uniqueId; 477 } 478 479 480 481 484 485 private class BugPropertyIterator implements Iterator <BugProperty> { 486 private BugProperty prev, cur; 487 private boolean removed; 488 489 492 public boolean hasNext() { 493 return findNext() != null; 494 } 495 498 public BugProperty next() { 499 BugProperty next = findNext(); 500 if (next == null) 501 throw new NoSuchElementException (); 502 prev = cur; 503 cur = next; 504 removed = false; 505 return cur; 506 } 507 508 511 public void remove() { 512 if (cur == null || removed) 513 throw new IllegalStateException (); 514 if (prev == null) { 515 propertyListHead = cur.getNext(); 516 } else { 517 prev.setNext(cur.getNext()); 518 } 519 if (cur == propertyListTail) { 520 propertyListTail = prev; 521 } 522 removed = true; 523 } 524 525 private BugProperty findNext() { 526 return cur == null ? propertyListHead : cur.getNext(); 527 } 528 529 } 530 531 538 public String getProperty(String name) { 539 BugProperty prop = lookupProperty(name); 540 return prop != null ? prop.getValue() : null; 541 } 542 543 552 public String getProperty(String name, String defaultValue) { 553 String value = getProperty(name); 554 return value != null ? value : defaultValue; 555 } 556 557 562 public Iterator <BugProperty> propertyIterator() { 563 return new BugPropertyIterator(); 564 } 565 566 573 public BugInstance setProperty(String name, String value) { 574 BugProperty prop = lookupProperty(name); 575 if (prop != null) { 576 prop.setValue(value); 577 } else { 578 prop = new BugProperty(name, value); 579 addProperty(prop); 580 } 581 return this; 582 } 583 584 591 public BugProperty lookupProperty(String name) { 592 BugProperty prop = propertyListHead; 593 594 while (prop != null) { 595 if (prop.getName().equals(name)) 596 break; 597 prop = prop.getNext(); 598 } 599 600 return prop; 601 } 602 603 610 public boolean deleteProperty(String name) { 611 BugProperty prev = null; 612 BugProperty prop = propertyListHead; 613 614 while (prop != null) { 615 if (prop.getName().equals(name)) 616 break; 617 prev = prop; 618 prop = prop.getNext(); 619 } 620 621 if (prop != null) { 622 if (prev != null) { 623 prev.setNext(prop.getNext()); 625 } else { 626 propertyListHead = prop.getNext(); 628 } 629 630 if (prop.getNext() == null) { 631 propertyListTail = prev; 633 } 634 635 return true; 636 } else { 637 return false; 639 } 640 } 641 642 private void addProperty(BugProperty prop) { 643 if (propertyListTail != null) { 644 propertyListTail.setNext(prop); 645 propertyListTail = prop; 646 } else { 647 propertyListHead = propertyListTail = prop; 648 } 649 prop.setNext(null); 650 } 651 652 655 656 661 public BugInstance addAnnotations(Collection <? extends BugAnnotation> annotationCollection) { 662 for (BugAnnotation annotation : annotationCollection) { 663 add(annotation); 664 } 665 return this; 666 } 667 668 671 672 public BugInstance addClassAndMethod(MethodDescriptor methodDescriptor) { 673 addClass(methodDescriptor.getClassName()); 674 add(MethodAnnotation.fromMethodDescriptor(methodDescriptor)); 675 return this; 676 } 677 678 685 public BugInstance addClassAndMethod(PreorderVisitor visitor) { 686 addClass(visitor); 687 addMethod(visitor); 688 return this; 689 } 690 691 697 public BugInstance addClassAndMethod(MethodAnnotation methodAnnotation) { 698 addClass(methodAnnotation.getClassName()); 699 addMethod(methodAnnotation); 700 return this; 701 } 702 703 710 public BugInstance addClassAndMethod(MethodGen methodGen, String sourceFile) { 711 addClass(methodGen.getClassName()); 712 addMethod(methodGen, sourceFile); 713 return this; 714 } 715 716 717 724 public BugInstance addClassAndMethod(JavaClass javaClass, Method method) { 725 addClass(javaClass.getClassName()); 726 addMethod(javaClass, method); 727 return this; 728 } 729 730 733 734 743 public BugInstance addClass(String className, String sourceFileName) { 744 ClassAnnotation classAnnotation = new ClassAnnotation(className); 745 add(classAnnotation); 746 return this; 747 } 748 749 756 public BugInstance addClass(String className) { 757 className = ClassName.toDottedClassName(className); 758 ClassAnnotation classAnnotation = new ClassAnnotation(className); 759 add(classAnnotation); 760 return this; 761 } 762 763 770 public BugInstance addClass(ClassDescriptor classDescriptor) { 771 add(ClassAnnotation.fromClassDescriptor(classDescriptor)); 772 return this; 773 } 774 775 782 public BugInstance addClass(JavaClass jclass) { 783 addClass(jclass.getClassName()); 784 return this; 785 } 786 787 793 public BugInstance addClass(PreorderVisitor visitor) { 794 String className = visitor.getDottedClassName(); 795 addClass(className); 796 return this; 797 } 798 799 806 public BugInstance addSuperclass(PreorderVisitor visitor) { 807 String className = visitor.getSuperclassName(); 808 addClass(className); 809 return this; 810 } 811 812 815 816 826 public BugInstance addType(String typeDescriptor) { 827 TypeAnnotation typeAnnotation = new TypeAnnotation(typeDescriptor); 828 add(typeAnnotation); 829 return this; 830 } 831 832 public BugInstance addTypeOfNamedClass(String typeName) { 833 TypeAnnotation typeAnnotation = new TypeAnnotation("L" + typeName.replace('.','/')+";"); 834 add(typeAnnotation); 835 return this; 836 } 837 840 841 850 public BugInstance addField(String className, String fieldName, String fieldSig, boolean isStatic) { 851 addField(new FieldAnnotation(className, fieldName, fieldSig, isStatic)); 852 return this; 853 } 854 855 861 public BugInstance addField(FieldAnnotation fieldAnnotation) { 862 add(fieldAnnotation); 863 return this; 864 } 865 866 872 public BugInstance addField(FieldVariable field) { 873 return addField(field.getClassName(), field.getFieldName(), field.getFieldSig(), field.isStatic()); 874 } 875 876 882 public BugInstance addField(XField xfield) { 883 return addField(xfield.getClassName(), xfield.getName(), xfield.getSignature(), xfield.isStatic()); 884 } 885 886 892 public BugInstance addField(FieldDescriptor fieldDescriptor) { 893 FieldAnnotation fieldAnnotation = FieldAnnotation.fromFieldDescriptor(fieldDescriptor); 894 add(fieldAnnotation); 895 return this; 896 } 897 898 907 public BugInstance addReferencedField(DismantleBytecode visitor) { 908 FieldAnnotation f = FieldAnnotation.fromReferencedField(visitor); 909 addField(f); 910 return this; 911 } 912 913 916 public BugInstance addReferencedField(FieldAnnotation fa) { 917 addField(fa); 918 return this; 919 } 920 921 928 public BugInstance addVisitedField(PreorderVisitor visitor) { 929 FieldAnnotation f = FieldAnnotation.fromVisitedField(visitor); 930 addField(f); 931 return this; 932 } 933 934 937 938 948 public BugInstance addMethod(String className, String methodName, String methodSig, boolean isStatic) { 949 addMethod(MethodAnnotation.fromForeignMethod(className, methodName, methodSig, isStatic)); 950 return this; 951 } 952 953 963 public BugInstance addMethod(MethodGen methodGen, String sourceFile) { 964 String className = methodGen.getClassName(); 965 MethodAnnotation methodAnnotation = 966 new MethodAnnotation(className, methodGen.getName(), methodGen.getSignature(), methodGen.isStatic()); 967 addMethod(methodAnnotation); 968 addSourceLinesForMethod(methodAnnotation, SourceLineAnnotation.fromVisitedMethod(methodGen, sourceFile)); 969 return this; 970 } 971 972 982 public BugInstance addMethod(JavaClass javaClass, Method method) { 983 MethodAnnotation methodAnnotation = 984 new MethodAnnotation(javaClass.getClassName(), method.getName(), method.getSignature(), method.isStatic()); 985 SourceLineAnnotation methodSourceLines = SourceLineAnnotation.forEntireMethod( 986 javaClass, 987 method); 988 methodAnnotation.setSourceLines(methodSourceLines); 989 addMethod(methodAnnotation); 990 return this; 991 } 992 993 1002 public BugInstance addMethod(JavaClassAndMethod classAndMethod) { 1003 return addMethod(classAndMethod.getJavaClass(), classAndMethod.getMethod()); 1004 } 1005 1006 1014 public BugInstance addMethod(PreorderVisitor visitor) { 1015 MethodAnnotation methodAnnotation = MethodAnnotation.fromVisitedMethod(visitor); 1016 addMethod(methodAnnotation); 1017 addSourceLinesForMethod(methodAnnotation, SourceLineAnnotation.fromVisitedMethod(visitor)); 1018 return this; 1019 } 1020 1021 1030 public BugInstance addCalledMethod(DismantleBytecode visitor) { 1031 return addMethod(MethodAnnotation.fromCalledMethod(visitor)); 1032 } 1033 1034 1043 public BugInstance addCalledMethod(String className, String methodName, String methodSig, boolean isStatic) { 1044 return addMethod(MethodAnnotation.fromCalledMethod(className, methodName, methodSig, isStatic)); 1045 } 1046 1047 1055 public BugInstance addCalledMethod(MethodGen methodGen, InvokeInstruction inv) { 1056 ConstantPoolGen cpg = methodGen.getConstantPool(); 1057 String className = inv.getClassName(cpg); 1058 String methodName = inv.getMethodName(cpg); 1059 String methodSig = inv.getSignature(cpg); 1060 addMethod(className, methodName, methodSig, inv.getOpcode() == Constants.INVOKESTATIC); 1061 describe("METHOD_CALLED"); 1062 return this; 1063 } 1064 1065 1071 public BugInstance addMethod(XMethod xmethod) { 1072 addMethod(MethodAnnotation.fromXMethod(xmethod)); 1073 return this; 1074 } 1075 1076 1083 public BugInstance addMethod(MethodAnnotation methodAnnotation) { 1084 add(methodAnnotation); 1085 return this; 1086 } 1087 1088 1091 1092 1098 public BugInstance addInt(int value) { 1099 add(new IntAnnotation(value)); 1100 return this; 1101 } 1102 1103 1109 public BugInstance addString(String value) { 1110 add(new StringAnnotation(value)); 1111 return this; 1112 } 1113 1114 1117 1118 1124 public BugInstance addSourceLine(SourceLineAnnotation sourceLine) { 1125 add(sourceLine); 1126 return this; 1127 } 1128 1129 1139 public BugInstance addSourceLine(BytecodeScanningDetector visitor, int pc) { 1140 SourceLineAnnotation sourceLineAnnotation = 1141 SourceLineAnnotation.fromVisitedInstruction(visitor.getClassContext(), visitor, pc); 1142 if (sourceLineAnnotation != null) 1143 add(sourceLineAnnotation); 1144 return this; 1145 } 1146 1147 1158 public BugInstance addSourceLine(ClassContext classContext, PreorderVisitor visitor, int pc) { 1159 SourceLineAnnotation sourceLineAnnotation = 1160 SourceLineAnnotation.fromVisitedInstruction(classContext, visitor, pc); 1161 if (sourceLineAnnotation != null) 1162 add(sourceLineAnnotation); 1163 return this; 1164 } 1165 1166 1177 public BugInstance addSourceLine(ClassContext classContext, MethodGen methodGen, String sourceFile, @NonNull InstructionHandle handle) { 1178 SourceLineAnnotation sourceLineAnnotation = 1179 SourceLineAnnotation.fromVisitedInstruction(classContext, methodGen, sourceFile, handle); 1180 if (sourceLineAnnotation != null) 1181 add(sourceLineAnnotation); 1182 return this; 1183 } 1184 1185 1195 public BugInstance addSourceLine(ClassContext classContext, MethodGen methodGen, String sourceFile, InstructionHandle start, InstructionHandle end) { 1196 if (start.getPosition() > end.getPosition()) { 1198 InstructionHandle tmp = start; 1199 start = end; 1200 end = tmp; 1201 } 1202 SourceLineAnnotation sourceLineAnnotation = 1203 SourceLineAnnotation.fromVisitedInstructionRange(classContext, methodGen, sourceFile, start, end); 1204 if (sourceLineAnnotation != null) 1205 add(sourceLineAnnotation); 1206 return this; 1207 } 1208 1209 1217 public BugInstance addSourceLine(ClassContext classContext, Method method, Location location) { 1218 MethodGen methodGen = classContext.getMethodGen(method); 1219 return addSourceLine( 1220 classContext, 1221 methodGen, 1222 classContext.getJavaClass().getSourceFileName(), 1223 location.getHandle()); 1224 } 1225 1226 1238 public BugInstance addSourceLineRange(BytecodeScanningDetector visitor, int startPC, int endPC) { 1239 SourceLineAnnotation sourceLineAnnotation = 1240 SourceLineAnnotation.fromVisitedInstructionRange(visitor.getClassContext(), visitor, startPC, endPC); 1241 if (sourceLineAnnotation != null) 1242 add(sourceLineAnnotation); 1243 return this; 1244 } 1245 1246 1259 public BugInstance addSourceLineRange(ClassContext classContext, PreorderVisitor visitor, int startPC, int endPC) { 1260 SourceLineAnnotation sourceLineAnnotation = 1261 SourceLineAnnotation.fromVisitedInstructionRange(classContext, visitor, startPC, endPC); 1262 if (sourceLineAnnotation != null) 1263 add(sourceLineAnnotation); 1264 return this; 1265 } 1266 1267 1276 public BugInstance addSourceLine(BytecodeScanningDetector visitor) { 1277 SourceLineAnnotation sourceLineAnnotation = 1278 SourceLineAnnotation.fromVisitedInstruction(visitor); 1279 if (sourceLineAnnotation != null) 1280 add(sourceLineAnnotation); 1281 return this; 1282 } 1283 1284 1292 public BugInstance addUnknownSourceLine(String className, String sourceFile) { 1293 SourceLineAnnotation sourceLineAnnotation = SourceLineAnnotation.createUnknown(className, sourceFile); 1294 if (sourceLineAnnotation != null) 1295 add(sourceLineAnnotation); 1296 return this; 1297 } 1298 1299 1302 1303 1308 public String getMessageWithoutPrefix() { 1309 BugPattern bugPattern = I18N.instance().lookupBugPattern(type); 1310 String pattern, shortPattern; 1311 if (bugPattern == null) 1312 shortPattern = pattern = "Error: missing bug pattern for key " + type; 1313 else { 1314 pattern = bugPattern.getLongDescription(); 1315 shortPattern = bugPattern.getShortDescription(); 1316 } 1317 try { 1318 FindBugsMessageFormat format = new FindBugsMessageFormat(pattern); 1319 return format.format(annotationList.toArray(new BugAnnotation[annotationList.size()]), getPrimaryClass()); 1320 } catch (RuntimeException e) { 1321 AnalysisContext.logError("Error generating bug msg ", e); 1322 return shortPattern + " [Error generating customized description]"; 1323 } 1324 } 1325 1330 public String getMessage() { 1331 String pattern = I18N.instance().getMessage(type); 1332 FindBugsMessageFormat format = new FindBugsMessageFormat(pattern); 1333 try { 1334 return format.format(annotationList.toArray(new BugAnnotation[annotationList.size()]), getPrimaryClass()); 1335 } catch (RuntimeException e) { 1336 AnalysisContext.logError("Error generating bug msg ", e); 1337 BugPattern bugPattern = I18N.instance().lookupBugPattern(type); 1338 if (bugPattern == null) 1339 return "Error: missing bug pattern for key " + type; 1340 return bugPattern.getShortDescription() + " [Error generating customized description]"; 1341 } 1342 } 1343 1344 1350 public BugInstance describe(String description) { 1351 annotationList.get(annotationList.size() - 1).setDescription(description); 1352 return this; 1353 } 1354 1355 1363 @Override  1364 public String toString() { 1365 return I18N.instance().getShortMessage(type); 1366 } 1367 1368 1371 1372 public void writeXML(XMLOutput xmlOutput) throws IOException { 1373 writeXML(xmlOutput, false); 1374 } 1375 1376 1377 public void writeXML(XMLOutput xmlOutput, boolean addMessages) throws IOException { 1378 XMLAttributeList attributeList = new XMLAttributeList() 1379 .addAttribute("type", type) 1380 .addAttribute("priority", String.valueOf(priority)); 1381 1382 BugPattern pattern = getBugPattern(); 1383 if (pattern != null) { 1384 attributeList.addAttribute("abbrev", pattern.getAbbrev()); 1390 attributeList.addAttribute("category", pattern.getCategory()); 1391 } 1392 1393 1394 if (addMessages) { 1395 if (getUniqueId() != null) { 1397 attributeList.addAttribute("uid", getUniqueId()); 1398 } 1399 attributeList.addAttribute("instanceHash", getInstanceHash()); 1400 attributeList.addAttribute("instanceOccurrenceNum", Integer.toString(getInstanceOccurrenceNum())); 1401 attributeList.addAttribute("instanceOccurrenceMax", Integer.toString(getInstanceOccurrenceMax())); 1402 1403 } 1404 if (firstVersion > 0) attributeList.addAttribute("first", Long.toString(firstVersion)); 1405 if (lastVersion >= 0) attributeList.addAttribute("last", Long.toString(lastVersion)); 1406 if (introducedByChangeOfExistingClass) 1407 attributeList.addAttribute("introducedByChange", "true"); 1408 if (removedByChangeOfPersistingClass) 1409 attributeList.addAttribute("removedByChange", "true"); 1410 1411 xmlOutput.openTag(ELEMENT_NAME, attributeList); 1412 1413 if (userDesignation != null) { 1414 userDesignation.writeXML(xmlOutput); 1415 } 1416 1417 if (addMessages) { 1418 BugPattern bugPattern = getBugPattern(); 1419 1420 xmlOutput.openTag("ShortMessage"); 1421 xmlOutput.writeText(bugPattern != null ? bugPattern.getShortDescription() : this.toString()); 1422 xmlOutput.closeTag("ShortMessage"); 1423 1424 xmlOutput.openTag("LongMessage"); 1425 xmlOutput.writeText(this.getMessageWithoutPrefix()); 1426 xmlOutput.closeTag("LongMessage"); 1427 } 1428 1429 boolean foundSourceAnnotation = false; 1430 for (BugAnnotation annotation : annotationList) { 1431 if (annotation instanceof SourceLineAnnotation) 1432 foundSourceAnnotation = true; 1433 annotation.writeXML(xmlOutput, addMessages); 1434 } 1435 if (!foundSourceAnnotation && addMessages) { 1436 SourceLineAnnotation synth = getPrimarySourceLineAnnotation(); 1437 if (synth != null) { 1438 synth.setSynthetic(true); 1439 synth.writeXML(xmlOutput, addMessages); 1440 } 1441 } 1442 1443 if (propertyListHead != null) { 1444 BugProperty prop = propertyListHead; 1445 while (prop != null) { 1446 prop.writeXML(xmlOutput); 1447 prop = prop.getNext(); 1448 } 1449 } 1450 1451 xmlOutput.closeTag(ELEMENT_NAME); 1452 } 1453 1454 private static final String ELEMENT_NAME = "BugInstance"; 1455 private static final String USER_ANNOTATION_ELEMENT_NAME = "UserAnnotation"; 1456 1457 1460 1461 public BugInstance add(BugAnnotation annotation) { 1462 if (annotation == null) 1463 throw new IllegalStateException ("Missing BugAnnotation!"); 1464 1465 annotationList.add(annotation); 1467 1468 cachedHashCode = INVALID_HASH_CODE; 1471 return this; 1472 } 1473 1474 private void addSourceLinesForMethod(MethodAnnotation methodAnnotation, SourceLineAnnotation sourceLineAnnotation) { 1475 if (sourceLineAnnotation != null) { 1476 methodAnnotation.setSourceLines(sourceLineAnnotation); 1483 } 1484 } 1485 1486 @Override  1487 public int hashCode() { 1488 if (cachedHashCode == INVALID_HASH_CODE) { 1489 int hashcode = type.hashCode() + priority; 1490 Iterator <BugAnnotation> i = annotationIterator(); 1491 while (i.hasNext()) 1492 hashcode += i.next().hashCode(); 1493 if (hashcode == INVALID_HASH_CODE) 1494 hashcode = INVALID_HASH_CODE+1; 1495 cachedHashCode = hashcode; 1496 } 1497 1498 return cachedHashCode; 1499 } 1500 1501 @Override  1502 public boolean equals(Object o) { 1503 if (!(o instanceof BugInstance)) 1504 return false; 1505 BugInstance other = (BugInstance) o; 1506 if (!type.equals(other.type) || priority != other.priority) 1507 return false; 1508 if (annotationList.size() != other.annotationList.size()) 1509 return false; 1510 int numAnnotations = annotationList.size(); 1511 for (int i = 0; i < numAnnotations; ++i) { 1512 BugAnnotation lhs = annotationList.get(i); 1513 BugAnnotation rhs = other.annotationList.get(i); 1514 if (!lhs.equals(rhs)) 1515 return false; 1516 } 1517 1518 return true; 1519 } 1520 1521 public int compareTo(BugInstance other) { 1522 int cmp; 1523 cmp = type.compareTo(other.type); 1524 if (cmp != 0) 1525 return cmp; 1526 cmp = priority - other.priority; 1527 if (cmp != 0) 1528 return cmp; 1529 1530 int pfxLen = Math.min(annotationList.size(), other.annotationList.size()); 1532 for (int i = 0; i < pfxLen; ++i) { 1533 BugAnnotation lhs = annotationList.get(i); 1534 BugAnnotation rhs = other.annotationList.get(i); 1535 cmp = lhs.compareTo(rhs); 1536 if (cmp != 0) 1537 return cmp; 1538 } 1539 1540 return annotationList.size() - other.annotationList.size(); 1543 } 1544 1545 1548 public void setFirstVersion(long firstVersion) { 1549 this.firstVersion = firstVersion; 1550 if (lastVersion >= 0 && firstVersion > lastVersion) 1551 throw new IllegalArgumentException ( 1552 firstVersion + ".." + lastVersion); 1553 } 1554 1555 1558 public long getFirstVersion() { 1559 return firstVersion; 1560 } 1561 1562 1565 public void setLastVersion(long lastVersion) { 1566 if (lastVersion >= 0 && firstVersion > lastVersion) 1567 throw new IllegalArgumentException ( 1568 firstVersion + ".." + lastVersion); 1569 this.lastVersion = lastVersion; 1570 } 1571 1572 1575 public long getLastVersion() { 1576 return lastVersion; 1577 } 1578 1579 1582 public void setIntroducedByChangeOfExistingClass(boolean introducedByChangeOfExistingClass) { 1583 this.introducedByChangeOfExistingClass = introducedByChangeOfExistingClass; 1584 } 1585 1586 1589 public boolean isIntroducedByChangeOfExistingClass() { 1590 return introducedByChangeOfExistingClass; 1591 } 1592 1593 1596 public void setRemovedByChangeOfPersistingClass(boolean removedByChangeOfPersistingClass) { 1597 this.removedByChangeOfPersistingClass = removedByChangeOfPersistingClass; 1598 } 1599 1600 1603 public boolean isRemovedByChangeOfPersistingClass() { 1604 return removedByChangeOfPersistingClass; 1605 } 1606 1607 1610 public void setInstanceHash(String instanceHash) { 1611 this.instanceHash = instanceHash; 1612 } 1613 1616 public void setOldInstanceHash(String oldInstanceHash) { 1617 this.oldInstanceHash = oldInstanceHash; 1618 } 1619 1622 public String getInstanceHash() { 1623 if (instanceHash != null) return instanceHash; 1624 MessageDigest digest = null; 1625 try { digest = MessageDigest.getInstance("MD5"); 1626 } catch (Exception e2) { 1627 } 1629 instanceHash = getInstanceKey(); 1630 if (digest != null) { 1631 byte [] data = digest.digest(instanceHash.getBytes()); 1632 String tmp = new BigInteger (1,data).toString(16); 1633 instanceHash = tmp; 1634 } 1635 return instanceHash; 1636 } 1637 1638 public boolean isInstanceHashConsistent() { 1639 return oldInstanceHash == null || instanceHash.equals(oldInstanceHash); 1640 } 1641 1644 public void setInstanceOccurrenceNum(int instanceOccurrenceNum) { 1645 this.instanceOccurrenceNum = instanceOccurrenceNum; 1646 } 1647 1648 1651 public int getInstanceOccurrenceNum() { 1652 return instanceOccurrenceNum; 1653 } 1654 1655 1658 public void setInstanceOccurrenceMax(int instanceOccurrenceMax) { 1659 this.instanceOccurrenceMax = instanceOccurrenceMax; 1660 } 1661 1662 1665 public int getInstanceOccurrenceMax() { 1666 return instanceOccurrenceMax; 1667 } 1668} 1669 1670 | Popular Tags |