KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > VersionInsensitiveBugComparator


1 /*
2  * FindBugs - Find bugs in Java programs
3  * Copyright (C) 2003,2004 University of Maryland
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19
20 package edu.umd.cs.findbugs;
21
22 import java.util.Iterator JavaDoc;
23 import java.util.NoSuchElementException JavaDoc;
24
25 import edu.umd.cs.findbugs.model.ClassNameRewriter;
26 import edu.umd.cs.findbugs.model.ClassNameRewriterUtil;
27 import edu.umd.cs.findbugs.model.IdentityClassNameRewriter;
28
29 /**
30  * Compare bug instances by only those criteria which we would expect to
31  * remain constant between versions.
32  */

33 public class VersionInsensitiveBugComparator implements WarningComparator {
34     
35     private ClassNameRewriter classNameRewriter = IdentityClassNameRewriter.instance();
36     
37     private boolean exactBugPatternMatch = true;
38     
39     private boolean comparePriorities = false;
40     public VersionInsensitiveBugComparator() {
41     }
42     
43     public void setClassNameRewriter(ClassNameRewriter classNameRewriter) {
44         this.classNameRewriter = classNameRewriter;
45     }
46     public void setComparePriorities(boolean b) {
47         comparePriorities = b;
48     }
49
50     /**
51      * Wrapper for BugAnnotation iterators, which filters out
52      * annotations we don't care about.
53      */

54     private class FilteringAnnotationIterator implements Iterator JavaDoc<BugAnnotation> {
55         private Iterator JavaDoc<BugAnnotation> iter;
56         private BugAnnotation next;
57
58         public FilteringAnnotationIterator(Iterator JavaDoc<BugAnnotation> iter) {
59             this.iter = iter;
60             this.next = null;
61         }
62
63         public boolean hasNext() {
64             findNext();
65             return next != null;
66         }
67
68         public BugAnnotation next() {
69             findNext();
70             if (next == null)
71                 throw new NoSuchElementException JavaDoc();
72             BugAnnotation result = next;
73             next = null;
74             return result;
75         }
76
77         public void remove() {
78             throw new UnsupportedOperationException JavaDoc();
79         }
80
81         private void findNext() {
82             while (next == null) {
83                 if (!iter.hasNext())
84                     break;
85                 BugAnnotation candidate = iter.next();
86                 if (!isBoring(candidate)) {
87                     next = candidate;
88                     break;
89                 }
90             }
91         }
92
93     }
94
95     private boolean isBoring(BugAnnotation annotation) {
96         // We ignore int annotations.
97
if (annotation.getClass() == IntAnnotation.class) {
98             if (annotation.getDescription().equals(IntAnnotation.INT_SYNC_PERCENT))
99                 return true;
100         }
101
102         // Ignore all source line annotations
103
if (annotation instanceof SourceLineAnnotation) {
104             return true;
105         }
106
107         return false;
108     }
109
110     private static int compareNullElements(Object JavaDoc a, Object JavaDoc b) {
111         if (a != null)
112             return 1;
113         else if (b != null)
114             return -1;
115         else
116             return 0;
117     }
118     
119     private static String JavaDoc getCode(String JavaDoc pattern) {
120         int sep = pattern.indexOf('_');
121         if (sep < 0)
122             return "";
123         return pattern.substring(0, sep);
124     }
125
126     public int compare(BugInstance lhs, BugInstance rhs) {
127         // Attributes of BugInstance.
128
// Compare abbreviation
129
// Compare class and method annotations (ignoring line numbers).
130
// Compare field annotations.
131

132         int cmp;
133         
134         BugPattern lhsPattern = lhs.getBugPattern();
135         BugPattern rhsPattern = rhs.getBugPattern();
136         
137         if (lhsPattern == null || rhsPattern == null) {
138             // One of the patterns is missing.
139
// However, we can still accurately match by abbrev (usually) by comparing
140
// the part of the type before the first '_' character.
141
// This is almost always equivalent to the abbrev.
142

143             String JavaDoc lhsCode = getCode(lhs.getType());
144             String JavaDoc rhsCode = getCode(rhs.getType());
145             
146             if ((cmp = lhsCode.compareTo(rhsCode)) != 0) {
147                 return cmp;
148             }
149         } else {
150             // Compare by abbrev instead of type. The specific bug type can change
151
// (e.g., "definitely null" to "null on simple path"). Also, we often
152
// change bug pattern types from one version of FindBugs to the next.
153
//
154
// Source line and field name are still matched precisely, so this shouldn't
155
// cause loss of precision.
156
if ((cmp = lhsPattern.getAbbrev().compareTo(rhsPattern.getAbbrev())) != 0)
157                 return cmp;
158             if (isExactBugPatternMatch() && (cmp = lhsPattern.getType().compareTo(rhsPattern.getType())) != 0)
159                 return cmp;
160         }
161         
162
163
164
165         if (comparePriorities) {
166             cmp = lhs.getPriority() - rhs.getPriority();
167             if (cmp != 0) return cmp;
168         }
169
170
171         Iterator JavaDoc<BugAnnotation> lhsIter = new FilteringAnnotationIterator(lhs.annotationIterator());
172         Iterator JavaDoc<BugAnnotation> rhsIter = new FilteringAnnotationIterator(rhs.annotationIterator());
173
174         while (lhsIter.hasNext() && rhsIter.hasNext()) {
175             BugAnnotation lhsAnnotation = lhsIter.next();
176             BugAnnotation rhsAnnotation = rhsIter.next();
177
178             // Different annotation types obviously cannot be equal,
179
// so just compare by class name.
180
if (lhsAnnotation.getClass() != rhsAnnotation.getClass())
181                 return lhsAnnotation.getClass().getName().compareTo(rhsAnnotation.getClass().getName());
182
183             if (lhsAnnotation.getClass() == ClassAnnotation.class) {
184                 // ClassAnnotations should have their class names rewritten to
185
// handle moved and renamed classes.
186

187                 String JavaDoc lhsClassName = classNameRewriter.rewriteClassName(
188                         ((ClassAnnotation)lhsAnnotation).getClassName());
189                 String JavaDoc rhsClassName = classNameRewriter.rewriteClassName(
190                         ((ClassAnnotation)rhsAnnotation).getClassName());
191                 
192                 return lhsClassName.compareTo(rhsClassName);
193                 
194             } else if(lhsAnnotation.getClass() == MethodAnnotation.class ) {
195                 // Rewrite class names in MethodAnnotations
196
MethodAnnotation lhsMethod = ClassNameRewriterUtil.convertMethodAnnotation(
197                         classNameRewriter, (MethodAnnotation) lhsAnnotation);
198                 MethodAnnotation rhsMethod = ClassNameRewriterUtil.convertMethodAnnotation(
199                         classNameRewriter, (MethodAnnotation) rhsAnnotation);
200                 
201                 cmp = lhsMethod.compareTo(rhsMethod);
202                 if (cmp != 0)
203                     return cmp;
204                 
205             } else if(lhsAnnotation.getClass() == FieldAnnotation.class) {
206                 // Rewrite class names in FieldAnnotations
207
FieldAnnotation lhsField = ClassNameRewriterUtil.convertFieldAnnotation(
208                         classNameRewriter, (FieldAnnotation) lhsAnnotation);
209                 FieldAnnotation rhsField = ClassNameRewriterUtil.convertFieldAnnotation(
210                         classNameRewriter, (FieldAnnotation) rhsAnnotation);
211                 
212                 cmp = lhsField.compareTo(rhsField);
213                 if (cmp != 0)
214                     return cmp;
215             } else if (isBoring(lhsAnnotation)) {
216                 throw new IllegalStateException JavaDoc("Impossible");
217             } else
218                 throw new IllegalStateException JavaDoc("Unknown annotation type: " + lhsAnnotation.getClass().getName());
219         }
220
221         if (rhsIter.hasNext())
222             return -1;
223         else if (lhsIter.hasNext())
224             return 1;
225         else
226             return 0;
227     }
228
229     /**
230      * @param exactBugPatternMatch The exactBugPatternMatch to set.
231      */

232     public void setExactBugPatternMatch(boolean exactBugPatternMatch) {
233         this.exactBugPatternMatch = exactBugPatternMatch;
234     }
235
236     /**
237      * @return Returns the exactBugPatternMatch.
238      */

239     public boolean isExactBugPatternMatch() {
240         return exactBugPatternMatch;
241     }
242 }
243
244
245
246 // vim:ts=4
247
Popular Tags