1 19 20 package edu.umd.cs.findbugs; 21 22 import java.io.FileReader ; 23 import java.util.ArrayList ; 24 import java.util.regex.Pattern ; 25 26 import org.xml.sax.Attributes ; 27 import org.xml.sax.InputSource ; 28 import org.xml.sax.SAXException ; 29 import org.xml.sax.XMLReader ; 30 import org.xml.sax.helpers.DefaultHandler ; 31 import org.xml.sax.helpers.XMLReaderFactory ; 32 33 import edu.umd.cs.findbugs.ba.ClassHash; 34 import edu.umd.cs.findbugs.model.ClassFeatureSet; 35 36 43 public class SAXBugCollectionHandler extends DefaultHandler { 44 private BugCollection bugCollection; 45 private Project project; 46 47 private ArrayList <String > elementStack; 48 private StringBuffer textBuffer; 49 private BugInstance bugInstance; 50 private PackageMemberAnnotation packageMemberAnnotation; 51 private AnalysisError analysisError; 52 private ClassFeatureSet classFeatureSet; 54 private ArrayList <String > stackTrace; 55 private int nestingOfIgnoredElements = 0; 56 57 public SAXBugCollectionHandler(BugCollection bugCollection, Project project) { 58 this.bugCollection = bugCollection; 59 this.project = project; 60 61 this.elementStack = new ArrayList <String >(); 62 this.textBuffer = new StringBuffer (); 63 this.stackTrace = new ArrayList <String >(); 64 } 65 66 Pattern ignoredElement = Pattern.compile("Message|ShortMessage|LongMessage|BugCategory|BugPattern|BugCode"); 67 68 public boolean discardedElement(String qName) { 69 return ignoredElement.matcher(qName).matches(); 70 71 } 72 73 @Override 74 public void startElement(String uri, String name, String qName, Attributes attributes) 75 throws SAXException { 76 79 if (discardedElement(qName)) { 80 nestingOfIgnoredElements++; 81 } else if (nestingOfIgnoredElements > 0) { 82 } else if (elementStack.isEmpty()) { 84 if (!qName.equals("BugCollection")) 86 throw new SAXException ( 87 "Invalid top-level element (expected BugCollection, saw " + qName + ")"); 88 89 String sequence = attributes.getValue("sequence"); 91 long seqval = parseLong(sequence, 0L); 92 bugCollection.setSequenceNumber(seqval); 93 94 String timestamp = attributes.getValue("timestamp"); 96 long tsval = parseLong(timestamp, -1L); 97 bugCollection.setTimestamp(tsval); 98 99 String releaseName = attributes.getValue("release"); 101 bugCollection.setReleaseName((releaseName != null) ? releaseName : ""); 102 } else { 103 String outerElement = elementStack.get(elementStack.size() - 1); 104 105 if (outerElement.equals("BugCollection")) { 106 if (qName.equals("Project")) { 108 String filename = attributes.getValue(Project.FILENAME_ATTRIBUTE_NAME); 110 if (filename != null) 111 project.setProjectFileName(filename); 112 } else if (qName.equals("BugInstance")) { 113 String type = getRequiredAttribute(attributes, "type", qName); 115 String priority = getRequiredAttribute(attributes, "priority", qName); 116 117 try { 118 int prio = Integer.parseInt(priority); 119 bugInstance = new BugInstance(type, prio); 120 } catch (NumberFormatException e) { 121 throw new SAXException ("BugInstance with invalid priority value \"" + 122 priority + "\"", e); 123 } 124 125 String uniqueId = attributes.getValue("uid"); 126 if (uniqueId != null) { 127 bugInstance.setUniqueId(uniqueId); 128 } 129 130 String firstVersion = attributes.getValue("first"); 131 if (firstVersion != null) { 132 bugInstance.setFirstVersion(Long.parseLong(firstVersion)); 133 } 134 String lastVersion = attributes.getValue("last"); 135 if (lastVersion != null) { 136 bugInstance.setLastVersion(Long.parseLong(lastVersion)); 137 } 138 139 if (bugInstance.getLastVersion() >= 0 && 140 bugInstance.getFirstVersion() > bugInstance.getLastVersion()) 141 throw new IllegalStateException ("huh"); 142 143 String introducedByChange = attributes.getValue("introducedByChange"); 144 if (introducedByChange != null) { 145 bugInstance.setIntroducedByChangeOfExistingClass(TigerSubstitutes.parseBoolean(introducedByChange)); 146 } 147 String removedByChange = attributes.getValue("removedByChange"); 148 if (removedByChange != null) { 149 bugInstance.setRemovedByChangeOfPersistingClass(TigerSubstitutes.parseBoolean(removedByChange)); 150 } 151 String oldInstanceHash = attributes.getValue("instanceHash"); 152 if (oldInstanceHash != null) { 153 bugInstance.setOldInstanceHash(oldInstanceHash); 154 } 155 156 157 } else if (qName.equals("FindBugsSummary")) { 158 String timestamp = getRequiredAttribute(attributes, "timestamp", qName); 159 try { 160 bugCollection.getProjectStats().setTimestamp(timestamp); 161 } catch (java.text.ParseException e) { 162 throw new SAXException ("Unparseable sequence number: '" + timestamp + "'", e); 163 } 164 } 165 } else if (outerElement.equals("BugInstance")) { 166 BugAnnotation bugAnnotation = null; 168 if (qName.equals("Class")) { 169 String className = getRequiredAttribute(attributes, "classname", qName); 170 bugAnnotation = packageMemberAnnotation = new ClassAnnotation(className); 171 } else if (qName.equals("Type")) { 172 String typeDescriptor = getRequiredAttribute(attributes, "descriptor", qName); 173 bugAnnotation = new TypeAnnotation(typeDescriptor); 174 } else if (qName.equals("Method") || qName.equals("Field")) { 175 String classname = getRequiredAttribute(attributes, "classname", qName); 176 String fieldOrMethodName = getRequiredAttribute(attributes, "name", qName); 177 String signature = getRequiredAttribute(attributes, "signature", qName); 178 if (qName.equals("Method")) { 179 String isStatic = attributes.getValue("isStatic"); 180 if (isStatic == null) { 181 isStatic = "false"; } 183 184 bugAnnotation = packageMemberAnnotation = 185 new MethodAnnotation(classname, fieldOrMethodName, signature, Boolean.valueOf(isStatic)); 186 187 } else { 188 String isStatic = getRequiredAttribute(attributes, "isStatic", qName); 189 bugAnnotation = packageMemberAnnotation = 190 new FieldAnnotation(classname, fieldOrMethodName, signature, Boolean.valueOf(isStatic)); 191 } 192 193 } else if (qName.equals("SourceLine")) { 194 SourceLineAnnotation sourceAnnotation = createSourceLineAnnotation(qName, attributes); 195 if (!sourceAnnotation.isSynthetic()) 196 bugAnnotation = sourceAnnotation; 197 } else if (qName.equals("Int")) { 198 try { 199 String value = getRequiredAttribute(attributes, "value", qName); 200 bugAnnotation = new IntAnnotation(Integer.parseInt(value)); 201 } catch (NumberFormatException e) { 202 throw new SAXException ("Bad integer value in Int"); 203 } 204 } else if (qName.equals("String")) { 205 String value = getRequiredAttribute(attributes, "value", qName); 206 bugAnnotation = new StringAnnotation(value); 207 } else if (qName.equals("LocalVariable")) { 208 try { 209 String varName = getRequiredAttribute(attributes, "name", qName); 210 int register = Integer.parseInt(getRequiredAttribute(attributes, "register", qName)); 211 int pc = Integer.parseInt(getRequiredAttribute(attributes, "pc", qName)); 212 bugAnnotation = new LocalVariableAnnotation(varName, register, pc); 213 } catch (NumberFormatException e) { 214 throw new SAXException ("Invalid integer value in attribute of LocalVariable element"); 215 } 216 } else if (qName.equals("Property")) { 217 String propName = getRequiredAttribute(attributes, "name", qName); 219 String propValue = getRequiredAttribute(attributes, "value", qName); 220 bugInstance.setProperty(propName, propValue); 221 } else if (qName.equals("UserAnnotation")) { 222 String s = attributes.getValue("designation"); BugDesignation userDesignation = bugInstance.getNonnullUserDesignation(); 225 if (s != null) userDesignation.setDesignationKey(s); 226 s = attributes.getValue("user"); if (s != null) userDesignation.setUser(s); 228 s = attributes.getValue("timestamp"); if (s != null) try { 230 long timestamp = Long.valueOf(s); 231 userDesignation.setTimestamp(timestamp); 232 } 233 catch (NumberFormatException nfe) { 234 } 237 } else throw new SAXException ("Unknown bug annotation named " + qName); 238 239 if (bugAnnotation != null) { 240 String role = attributes.getValue("role"); 241 if (role != null) 242 bugAnnotation.setDescription(role); 243 setAnnotationRole(attributes, bugAnnotation); 244 bugInstance.add(bugAnnotation); 245 } 246 } else if (outerElement.equals("Method") || outerElement.equals("Field") || outerElement.equals("Class")) { 247 if (qName.equals("SourceLine")) { 248 packageMemberAnnotation.setSourceLines(createSourceLineAnnotation(qName, attributes)); 250 } 251 } else if (outerElement.equals(BugCollection.ERRORS_ELEMENT_NAME)) { 252 if (qName.equals(BugCollection.ANALYSIS_ERROR_ELEMENT_NAME) || 253 qName.equals(BugCollection.ERROR_ELEMENT_NAME)) { 254 analysisError = new AnalysisError("Unknown error"); 255 stackTrace.clear(); 256 } 257 } else if (outerElement.equals("PackageStats")) { 258 if (qName.equals("ClassStats")) { 259 String className = getRequiredAttribute(attributes, "class", qName); 260 Boolean isInterface = Boolean.valueOf( 261 getRequiredAttribute(attributes, "interface", qName)); 262 int size = Integer.valueOf( 263 getRequiredAttribute(attributes, "size", qName)); 264 bugCollection.getProjectStats().addClass(className, isInterface, size); 265 } 266 } else if (outerElement.equals("ClassFeatures")) { 267 if (qName.equals(ClassFeatureSet.ELEMENT_NAME)) { 268 String className = getRequiredAttribute(attributes, "class", qName); 269 classFeatureSet = new ClassFeatureSet(); 270 classFeatureSet.setClassName(className); 271 } 272 } else if (outerElement.equals(ClassFeatureSet.ELEMENT_NAME)) { 273 if (qName.equals(ClassFeatureSet.FEATURE_ELEMENT_NAME)) { 274 String value = getRequiredAttribute(attributes, "value", qName); 275 classFeatureSet.addFeature(value); 276 } 277 } else if (outerElement.equals(BugCollection.HISTORY_ELEMENT_NAME)) { 278 if (qName.equals(AppVersion.ELEMENT_NAME)) { 279 try { 280 String sequence = getRequiredAttribute(attributes, "sequence", qName); 281 String timestamp = attributes.getValue("timestamp"); 282 String releaseName = attributes.getValue("release"); 283 String codeSize = attributes.getValue("codeSize"); 284 String numClasses = attributes.getValue("numClasses"); 285 AppVersion appVersion = new AppVersion(Long.valueOf(sequence)); 286 if (timestamp != null) 287 appVersion.setTimestamp(Long.valueOf(timestamp)); 288 if (releaseName != null) 289 appVersion.setReleaseName(releaseName); 290 if (codeSize != null) 291 appVersion.setCodeSize(Integer.parseInt(codeSize)); 292 if (numClasses != null) 293 appVersion.setNumClasses(Integer.parseInt(numClasses)); 294 295 bugCollection.addAppVersion(appVersion); 296 } catch (NumberFormatException e) { 297 throw new SAXException ("Invalid AppVersion element", e); 298 } 299 } 300 } 301 } 302 303 textBuffer.delete(0, textBuffer.length()); 304 elementStack.add(qName); 305 } 306 307 private long parseLong(String s, long defaultValue) { 308 long value; 309 try { 310 value = (s != null) ? Long.parseLong(s) : defaultValue; 311 } catch (NumberFormatException e) { 312 value = defaultValue; 313 } 314 return value; 315 } 316 317 325 private byte[] extractHash(String qName, Attributes attributes) throws SAXException { 326 String encodedHash = getRequiredAttribute(attributes, "value", qName); 327 byte[] hash; 328 try { 329 hash= ClassHash.stringToHash(encodedHash); 331 } catch (IllegalArgumentException e) { 332 throw new SAXException ("Invalid class hash", e); 333 } 334 return hash; 335 } 336 337 private void setAnnotationRole(Attributes attributes, BugAnnotation bugAnnotation) { 338 String role = attributes.getValue("role"); 339 if (role != null) 340 bugAnnotation.setDescription(role); 341 } 342 343 private SourceLineAnnotation createSourceLineAnnotation(String qName, Attributes attributes) 344 throws SAXException { 345 String classname = getRequiredAttribute(attributes, "classname", qName); 346 String sourceFile = attributes.getValue("sourcefile"); 347 if (sourceFile == null) 348 sourceFile = SourceLineAnnotation.UNKNOWN_SOURCE_FILE; 349 String startLine = attributes.getValue("start"); String endLine = attributes.getValue("end"); String startBytecode = attributes.getValue("startBytecode"); 352 String endBytecode = attributes.getValue("endBytecode"); 353 354 try { 355 int sl = startLine != null ? Integer.parseInt(startLine) : -1; 356 int el = endLine != null ? Integer.parseInt(endLine) : -1; 357 int sb = startBytecode != null ? Integer.parseInt(startBytecode) : -1; 358 int eb = endBytecode != null ? Integer.parseInt(endBytecode) : -1; 359 360 SourceLineAnnotation annotation = 361 new SourceLineAnnotation(classname, sourceFile, sl, el, sb, eb); 362 363 return annotation; 364 } catch (NumberFormatException e) { 365 throw new SAXException ("Bad integer value in SourceLine element", e); 366 } 367 } 368 369 370 @Override 371 public void endElement(String uri, String name, String qName) throws SAXException { 372 375 if (discardedElement(qName)) { 376 nestingOfIgnoredElements--; 377 } else if (nestingOfIgnoredElements > 0) { 378 } else if (elementStack.size() > 1) { 380 String outerElement = elementStack.get(elementStack.size() - 2); 381 382 if (outerElement.equals("BugCollection")) { 383 if (qName.equals("BugInstance")) { 384 bugCollection.add(bugInstance, false); 385 if (bugInstance.getLastVersion() == -1) 387 bugCollection.getProjectStats().addBug(bugInstance); 388 } 389 } else if (outerElement.equals("Project")) { 390 if (qName.equals("Jar")) 392 project.addFile(textBuffer.toString()); 393 else if (qName.equals("SrcDir")) 394 project.addSourceDir(textBuffer.toString()); 395 else if (qName.equals("AuxClasspathEntry")) 396 project.addAuxClasspathEntry(textBuffer.toString()); 397 } else if (outerElement.equals("BugInstance")) { 398 if (qName.equals("UserAnnotation")) { 399 bugInstance.setAnnotationText(textBuffer.toString()); 400 } 401 } else if (outerElement.equals(BugCollection.ERRORS_ELEMENT_NAME)) { 402 if (qName.equals(BugCollection.ANALYSIS_ERROR_ELEMENT_NAME)) { 403 analysisError.setMessage(textBuffer.toString()); 404 bugCollection.addError(analysisError); 405 } else if (qName.equals(BugCollection.ERROR_ELEMENT_NAME)) { 406 if (stackTrace.size() > 0) { 407 analysisError.setStackTrace(stackTrace.toArray(new String [stackTrace.size()])); 408 } 409 bugCollection.addError(analysisError); 410 } else if (qName.equals(BugCollection.MISSING_CLASS_ELEMENT_NAME)) { 411 bugCollection.addMissingClass(textBuffer.toString()); 412 } 413 414 } else if (outerElement.equals(BugCollection.ERROR_ELEMENT_NAME)) { 415 if (qName.equals(BugCollection.ERROR_MESSAGE_ELEMENT_NAME)) { 416 analysisError.setMessage(textBuffer.toString()); 417 } else if (qName.equals(BugCollection.ERROR_EXCEPTION_ELEMENT_NAME)) { 418 analysisError.setExceptionMessage(textBuffer.toString()); 419 } else if (qName.equals(BugCollection.ERROR_STACK_TRACE_ELEMENT_NAME)) { 420 stackTrace.add(textBuffer.toString()); 421 } 422 } else if (outerElement.equals("ClassFeatures")) { 423 if (qName.equals(ClassFeatureSet.ELEMENT_NAME)) { 424 bugCollection.setClassFeatureSet(classFeatureSet); 425 classFeatureSet = null; 426 } 427 } 428 } 429 430 elementStack.remove(elementStack.size() - 1); 431 } 432 433 @Override 434 public void characters(char[] ch, int start, int length) { 435 textBuffer.append(ch, start, length); 436 } 437 438 private static String getRequiredAttribute(Attributes attributes, String attrName, String elementName) 439 throws SAXException { 440 String value = attributes.getValue(attrName); 441 if (value == null) 442 throw new SAXException (elementName + " element missing " + attrName + " attribute"); 443 return value; 444 } 445 446 public static void main(String [] argv) throws Exception { 448 XMLReader xr = XMLReaderFactory.createXMLReader(); 449 450 BugCollection bugCollection = new SortedBugCollection(); 451 Project project = new Project(); 452 453 SAXBugCollectionHandler handler = new SAXBugCollectionHandler(bugCollection, project); 454 xr.setContentHandler(handler); 455 xr.setErrorHandler(handler); 456 457 for (String aArgv : argv) { 460 FileReader r = new FileReader (aArgv); 461 xr.parse(new InputSource (r)); 462 } 463 } 464 } 465 466 | Popular Tags |