KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > detect > FindMaskedFields


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

20
21 package edu.umd.cs.findbugs.detect;
22
23
24 import java.util.Collection JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.HashSet JavaDoc;
27 import java.util.LinkedList JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.Set JavaDoc;
30
31 import org.apache.bcel.classfile.Field;
32 import org.apache.bcel.classfile.JavaClass;
33 import org.apache.bcel.classfile.LocalVariable;
34 import org.apache.bcel.classfile.LocalVariableTable;
35 import org.apache.bcel.classfile.Method;
36
37 import edu.umd.cs.findbugs.BugInstance;
38 import edu.umd.cs.findbugs.BugReporter;
39 import edu.umd.cs.findbugs.BytecodeScanningDetector;
40 import edu.umd.cs.findbugs.FieldAnnotation;
41 import edu.umd.cs.findbugs.Priorities;
42 import edu.umd.cs.findbugs.SystemProperties;
43 import edu.umd.cs.findbugs.ba.AnalysisContext;
44 import edu.umd.cs.findbugs.ba.ClassContext;
45 import edu.umd.cs.findbugs.ba.XFactory;
46 import edu.umd.cs.findbugs.ba.XField;
47
48 public class FindMaskedFields extends BytecodeScanningDetector {
49     private BugReporter bugReporter;
50     private int numParms;
51     private Set JavaDoc<Field> maskedFields = new HashSet JavaDoc<Field>();
52     private Map JavaDoc<String JavaDoc, Field> classFields = new HashMap JavaDoc<String JavaDoc, Field>();
53     private boolean staticMethod;
54
55     private Collection JavaDoc<RememberedBug>
56         rememberedBugs = new LinkedList JavaDoc<RememberedBug>();
57         
58     static class RememberedBug {
59         BugInstance bug;
60         XField maskingField, maskedField;
61         RememberedBug(BugInstance bug,
62                 FieldAnnotation maskingField, FieldAnnotation maskedField) {
63             this.bug = bug;
64             this.maskingField = XFactory.createXField(maskingField);
65             this.maskedField = XFactory.createXField(maskedField);
66         }
67     }
68     public FindMaskedFields(BugReporter bugReporter) {
69         this.bugReporter = bugReporter;
70     }
71
72     @Override JavaDoc
73          public void visitClassContext(ClassContext classContext) {
74         JavaClass obj = classContext.getJavaClass();
75         if (!obj.isInterface())
76             classContext.getJavaClass().accept(this);
77     }
78
79     @Override JavaDoc
80          public void visit(JavaClass obj) {
81         classFields.clear();
82
83         Field[] fields = obj.getFields();
84         String JavaDoc fieldName;
85         for (Field field : fields) if (!field.isStatic() && !field.isPrivate()){
86             fieldName = field.getName();
87             classFields.put(fieldName, field);
88         }
89         
90         // Walk up the super class chain, looking for name collisions
91
try {
92             JavaClass[] superClasses = org.apache.bcel.Repository.getSuperClasses(obj);
93             for (JavaClass superClass : superClasses) {
94                 fields = superClass.getFields();
95                 for (Field fld : fields) {
96                     if (!fld.isStatic()
97                             && !maskedFields.contains(fld)
98                             && (fld.isPublic() || fld.isProtected())) {
99                         fieldName = fld.getName();
100                         if (fieldName.length() == 1)
101                             continue;
102                         if (fieldName.equals("serialVersionUID"))
103                             continue;
104                         String JavaDoc superClassName = superClass.getClassName();
105                         if (superClassName.startsWith("java.io") &&
106                                 (superClassName.endsWith("InputStream")
107                                 && fieldName.equals("in")
108                                 || superClassName.endsWith("OutputStream")
109                                 && fieldName.equals("out"))
110                                 ) continue;
111                         if (classFields.containsKey(fieldName)) {
112                             maskedFields.add(fld);
113                             Field maskingField = classFields.get(fieldName);
114                             String JavaDoc mClassName = getDottedClassName();
115                             FieldAnnotation fa = new FieldAnnotation(mClassName, maskingField.getName(),
116                                     maskingField.getSignature(),
117                                     maskingField.isStatic());
118                             int priority = NORMAL_PRIORITY;
119                             if (maskingField.isStatic()
120                                     || maskingField.isFinal())
121                                 priority++;
122                             else if (fld.getSignature().charAt(0) == 'L'
123                                     && !fld.getSignature().startsWith("Ljava/lang/")
124                                     || fld.getSignature().charAt(0) == '[')
125                                 priority--;
126                             if (fld.getAccessFlags()
127                                     != maskingField.getAccessFlags())
128                                 priority++;
129                             if (!fld.getSignature().equals(maskingField.getSignature()))
130                                 priority++;
131
132                             FieldAnnotation maskedFieldAnnotation
133                                     = FieldAnnotation.fromBCELField(superClassName, fld);
134                             BugInstance bug = new BugInstance(this, "MF_CLASS_MASKS_FIELD",
135                                     priority)
136                                     .addClass(this)
137                                     .addField(fa)
138                                     .describe("FIELD_MASKING")
139                                     .addField(maskedFieldAnnotation)
140                                     .describe("FIELD_MASKED");
141                             rememberedBugs.add(new RememberedBug(bug, fa, maskedFieldAnnotation));
142                                 
143                         }
144                     }
145                 }
146             }
147         } catch (ClassNotFoundException JavaDoc e) {
148             bugReporter.reportMissingClass(e);
149         }
150
151         super.visit(obj);
152     }
153
154     @Override JavaDoc
155          public void visit(Method obj) {
156         super.visit(obj);
157         numParms = getNumberMethodArguments();
158         if (!obj.isStatic()) numParms++;
159         // System.out.println(obj);
160
// System.out.println(numParms);
161
staticMethod = obj.isStatic();
162     }
163
164     /**
165      * This property enables production of warnings for
166      * locals which obscure fields.
167      */

168     private static final boolean ENABLE_LOCALS =
169         SystemProperties.getBoolean("findbugs.maskedfields.locals");
170
171     @Override JavaDoc
172          public void visit(LocalVariableTable obj) {
173         if (ENABLE_LOCALS) {
174             if (staticMethod)
175                 return;
176
177             LocalVariable[] vars = obj.getLocalVariableTable();
178             // System.out.println("Num params = " + numParms);
179
for (LocalVariable var : vars) {
180                 if (var.getIndex() < numParms)
181                     continue;
182                 String JavaDoc varName = var.getName();
183                 if (varName.equals("serialVersionUID"))
184                     continue;
185                 Field f = classFields.get(varName);
186                 // System.out.println("Checking " + varName);
187
// System.out.println(" got " + f);
188
// TODO: we could distinguish between obscuring a field in the same class
189
// vs. obscuring a field in a superclass. Not sure how important that is.
190
if (f != null) {
191                     FieldAnnotation fa
192                             = FieldAnnotation.fromBCELField(getClassName(), f);
193                     if (true || var.getStartPC() > 0)
194                         bugReporter.reportBug(new BugInstance(this, "MF_METHOD_MASKS_FIELD", LOW_PRIORITY)
195                                 .addClassAndMethod(this)
196                                 .addField(fa)
197                                 .addSourceLine(this, var.getStartPC() - 1));
198                 }
199             }
200         }
201         super.visit(obj);
202     }
203     
204     @Override JavaDoc
205     public void report() {
206         UnreadFields unreadFields = AnalysisContext.currentAnalysisContext().getUnreadFields();
207         for(RememberedBug rb : rememberedBugs) {
208             BugInstance bug = rb.bug;
209             int score = 0;
210             int priority = bug.getPriority();
211             if (unreadFields.classesScanned.contains(rb.maskedField.getClassName())) {
212                 if (unreadFields.getReadFields().contains(rb.maskedField))
213                     score++;
214                 if (unreadFields.getWrittenFields().contains(rb.maskedField))
215                     score++;
216                 if (unreadFields.getWrittenOutsideOfConstructorFields().contains(rb.maskedField))
217                     score++;
218             } else score += 2;
219             if (unreadFields.getReadFields().contains(rb.maskingField))
220                 score++;
221                 if (unreadFields.getWrittenFields().contains(rb.maskingField))
222                 score++;
223             if (unreadFields.getWrittenOutsideOfConstructorFields().contains(rb.maskingField))
224                 score++;
225             if (score >= 5)
226                 bug.setPriority(priority-1);
227             else if (score < 3)
228                 bug.setPriority(priority+1);
229             bugReporter.reportBug(bug);
230     }
231     }
232 }
233
234 // vim:ts=4
235
Popular Tags