1 package net.jaekl.cfb.xml;
3 import java.io.PrintWriter;
4 import java.util.ArrayList;
5 import java.util.Collections;
8 import org.xml.sax.Attributes;
10 import net.jaekl.cfb.util.Util;
11 import net.jaekl.qd.xml.MissingAttributeException;
12 import net.jaekl.qd.xml.ParseResult;
13 import net.jaekl.qd.xml.XmlParseException;
15 public class BugInstance extends ParseResult {
17 static final String TAG = "BugInstance";
18 static final String[] INTERNAL = { };
19 static final Object[][] EXTERNAL = { { BugClass.TAG, BugClass.class},
20 { BugMethod.TAG, BugMethod.class},
21 { LocalVariable.TAG, LocalVariable.class},
22 { SourceLine.TAG, SourceLine.class} };
23 static final String CATEGORY = "category";
24 static final String TYPE = "type";
28 ArrayList<BugClass> m_classes;
29 ArrayList<BugMethod> m_methods;
30 ArrayList<LocalVariable> m_locals;
31 ArrayList<SourceLine> m_lines;
33 public BugInstance() {
34 super(TAG, INTERNAL, EXTERNAL);
36 m_category = m_type = null;
37 m_classes = new ArrayList<BugClass>();
38 m_methods = new ArrayList<BugMethod>();
39 m_locals = new ArrayList<LocalVariable>();
40 m_lines = new ArrayList<SourceLine>();
43 public String getCategory() { return m_category; }
44 public String getType() { return m_type; }
45 public List<BugClass> getClasses() { return Collections.unmodifiableList(m_classes); }
46 public List<BugMethod> getMethods() { return Collections.unmodifiableList(m_methods); }
47 public List<SourceLine> getLines() { return Collections.unmodifiableList(m_lines); }
48 public List<LocalVariable> getVariables() { return Collections.unmodifiableList(m_locals); }
51 public void endContents(String uri, String localName, String qName, String chars)
52 throws XmlParseException
58 public void endExternal(String uri, String localName, String qName)
59 throws XmlParseException
61 if (BugClass.TAG.equals(localName)) {
62 ParseResult[] collected = collectParsedChildren(BugClass.class);
63 for (ParseResult pr : collected) {
64 assert(pr instanceof BugClass);
65 m_classes.add((BugClass) pr);
68 else if (BugMethod.TAG.equals(localName)) {
69 ParseResult[] collected = collectParsedChildren(BugMethod.class);
70 for (ParseResult pr : collected) {
71 assert(pr instanceof BugMethod);
72 m_methods.add((BugMethod)pr);
75 else if (LocalVariable.TAG.equals(localName)) {
76 ParseResult[] collected = collectParsedChildren(LocalVariable.class);
77 for (ParseResult pr : collected) {
78 assert(pr instanceof LocalVariable);
79 m_locals.add((LocalVariable)pr);
82 else if (SourceLine.TAG.equals(localName)) {
83 ParseResult[] collected = collectParsedChildren(SourceLine.class);
84 for (ParseResult pr : collected) {
85 assert(pr instanceof SourceLine);
86 m_lines.add((SourceLine)pr);
92 public void handleMainAttributes(Attributes attr) throws MissingAttributeException
94 m_type = this.getRequiredAttr(TAG, attr, TYPE);
95 m_category = this.getRequiredAttr(TAG, attr, CATEGORY);
99 public void dump(PrintWriter pw, int indent)
101 int childIndent = indent + 2;
102 String margin = String.format("%" + indent + "s", "");
104 pw.println(margin + TAG + " (" + m_type + ")");
105 pw.println(margin + CATEGORY + " (" + m_category + ")");
106 for (BugClass bc : m_classes) {
107 bc.dump(pw, childIndent);
109 for (BugMethod bm : m_methods) {
110 bm.dump(pw, childIndent);
112 for (LocalVariable lv : m_locals) {
113 lv.dump(pw, childIndent);
115 for (SourceLine sl : m_lines) {
116 sl.dump(pw, childIndent);
120 // Note that this is a heuristic, "fuzzy", equals.
121 // Two BugInstances will be considered equal if:
122 // - they refer to the same bug type
123 // - they took place in the same class and method
124 // - the variable names referred to (if any) match
125 // In particular, this equality test does not check
126 // for line numbers being equal. This is by design;
127 // we want to consider two bugs to be the "same bug"
128 // even if other changes in the file have shifted
129 // line numbers a bit.
131 public boolean equals(Object obj)
136 if (obj instanceof BugInstance) {
137 BugInstance that = (BugInstance)obj;
139 if (! Util.objsAreEqual(this.m_type, that.m_type)) {
143 if (! Util.objsAreEqual(this.m_category, that.m_category)) {
147 BugMethod thisMethod = this.getPrincipalMethod();
148 BugMethod thatMethod = that.getPrincipalMethod();
149 if (null == thisMethod) {
150 if (null == thatMethod) {
155 if (! Util.objsAreEqual(thisMethod.getClassName(), thatMethod.getClassName())) {
158 if (! Util.objsAreEqual(thisMethod.getMethodName(), thatMethod.getMethodName())) {
163 if (! Util.objsAreEqual(this.getVariables(), that.getVariables())) {
173 public int hashCode()
175 int code = Util.objHashCode(m_type)
176 * Util.objHashCode(m_category)
177 * Util.objHashCode(getPrincipalMethod())
178 * Util.objHashCode(getVariables());
182 // Get the "principal" method.
183 // This should be the place where the bug is reported.
184 BugMethod getPrincipalMethod()
186 List<BugMethod> bugMethods = getMethods();
187 if ((null == bugMethods) || (0 == bugMethods.size())) {
190 return bugMethods.get(0);