KickJava   Java API By Example, From Geeks To Geeks.

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


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.detect;
21
22
23 import edu.umd.cs.findbugs.*;
24 import edu.umd.cs.findbugs.ba.AnalysisContext;
25 import edu.umd.cs.findbugs.ba.XFactory;
26 import edu.umd.cs.findbugs.ba.XField;
27 import edu.umd.cs.findbugs.visitclass.PreorderVisitor;
28
29 import java.util.*;
30 import java.util.regex.Pattern JavaDoc;
31 import org.apache.bcel.Repository;
32 import org.apache.bcel.classfile.*;
33 import org.apache.bcel.generic.Type;
34
35 public class UnreadFields extends BytecodeScanningDetector {
36     private static final boolean DEBUG = SystemProperties.getBoolean("unreadfields.debug");
37
38     static class ProgramPoint {
39         ProgramPoint(BytecodeScanningDetector v) {
40             method = MethodAnnotation.fromVisitedMethod(v);
41             sourceLine = SourceLineAnnotation
42                 .fromVisitedInstruction(v,v.getPC());
43             }
44         MethodAnnotation method;
45         SourceLineAnnotation sourceLine;
46         }
47
48     Map<XField,HashSet<ProgramPoint> >
49         assumedNonNull = new HashMap<XField,HashSet<ProgramPoint>>();
50     Set<XField> nullTested = new HashSet<XField>();
51     Set<XField> staticFields = new HashSet<XField>();
52     Set<XField> declaredFields = new TreeSet<XField>();
53     Set<XField> containerFields = new TreeSet<XField>();
54     Set<String JavaDoc> abstractClasses = new HashSet<String JavaDoc>();
55     Set<String JavaDoc> hasNonAbstractSubClass = new HashSet<String JavaDoc>();
56     Set<String JavaDoc> classesScanned = new HashSet<String JavaDoc>();
57     Set<XField> fieldsOfNativeClassed
58     = new HashSet<XField>();
59     Set<XField> fieldsOfSerializableOrNativeClassed
60             = new HashSet<XField>();
61     Set<XField> staticFieldsReadInThisMethod = new HashSet<XField>();
62     Set<XField> allMyFields = new TreeSet<XField>();
63     Set<XField> myFields = new TreeSet<XField>();
64     Set<XField> writtenFields = new HashSet<XField>();
65     Map<XField,SourceLineAnnotation> fieldAccess = new HashMap<XField, SourceLineAnnotation>();
66     Set<XField> writtenNonNullFields = new HashSet<XField>();
67     Set<String JavaDoc> calledFromConstructors = new HashSet<String JavaDoc>();
68     Set<XField> writtenInConstructorFields = new HashSet<XField>();
69     Set<XField> writtenOutsideOfConstructorFields = new HashSet<XField>();
70     
71     Set<XField> readFields = new HashSet<XField>();
72     Set<XField> constantFields = new HashSet<XField>();
73     Set<XField> finalFields = new HashSet<XField>();
74     Set<String JavaDoc> needsOuterObjectInConstructor = new HashSet<String JavaDoc>();
75     Set<String JavaDoc> innerClassCannotBeStatic = new HashSet<String JavaDoc>();
76     boolean hasNativeMethods;
77     boolean isSerializable;
78     boolean sawSelfCallInConstructor;
79     private BugReporter bugReporter;
80     boolean publicOrProtectedConstructor;
81     private XFactory xFactory = AnalysisContext.currentXFactory();
82
83     public Set<? extends XField> getReadFields() {
84         return readFields;
85     }
86     public Set<? extends XField> getWrittenFields() {
87         return writtenFields;
88     }
89     public Set<? extends XField> getWrittenOutsideOfConstructorFields() {
90         return writtenOutsideOfConstructorFields;
91     }
92     static final int doNotConsider = ACC_PUBLIC | ACC_PROTECTED;
93
94     public UnreadFields(BugReporter bugReporter) {
95         this.bugReporter = bugReporter;
96         AnalysisContext context = AnalysisContext.currentAnalysisContext();
97         context.setUnreadFields(this);
98     }
99
100
101     @Override JavaDoc
102          public void visit(JavaClass obj) {
103         calledFromConstructors.clear();
104         hasNativeMethods = false;
105         sawSelfCallInConstructor = false;
106         publicOrProtectedConstructor = false;
107         isSerializable = false;
108         if (obj.isAbstract()) {
109             abstractClasses.add(getDottedClassName());
110         }
111         else {
112             String JavaDoc superClass = obj.getSuperclassName();
113             if (superClass != null) hasNonAbstractSubClass.add(superClass);
114         }
115             
116         if (getSuperclassName().indexOf("$") >= 0
117                 || getSuperclassName().indexOf("+") >= 0) {
118             // System.out.println("hicfsc: " + betterClassName);
119
innerClassCannotBeStatic.add(getDottedClassName());
120             // System.out.println("hicfsc: " + betterSuperclassName);
121
innerClassCannotBeStatic.add(getDottedSuperclassName());
122         }
123         // Does this class directly implement Serializable?
124
String JavaDoc[] interface_names = obj.getInterfaceNames();
125         for (String JavaDoc interface_name : interface_names) {
126             if (interface_name.equals("java.io.Externalizable")) {
127                 isSerializable = true;
128             } else if (interface_name.equals("java.io.Serializable")) {
129                 isSerializable = true;
130                 break;
131             }
132         }
133
134         // Does this class indirectly implement Serializable?
135
if (!isSerializable) {
136             try {
137                 if (Repository.instanceOf(obj, "java.io.Externalizable"))
138                     isSerializable = true;
139                 if (Repository.instanceOf(obj, "java.io.Serializable"))
140                     isSerializable = true;
141                 if (Repository.instanceOf(obj, "java.rmi.Remote")) {
142                     isSerializable = true;
143                 }
144             } catch (ClassNotFoundException JavaDoc e) {
145                 bugReporter.reportMissingClass(e);
146             }
147         }
148
149         // System.out.println(getDottedClassName() + " is serializable: " + isSerializable);
150
super.visit(obj);
151     }
152
153     public static boolean classHasParameter(JavaClass obj) {
154         for(Attribute a : obj.getAttributes())
155             if (a instanceof Signature) {
156                 String JavaDoc sig = ((Signature)a).getSignature();
157                 return sig.charAt(0) == '<';
158             }
159         return false;
160     }
161     @Override JavaDoc
162          public void visitAfter(JavaClass obj) {
163         declaredFields.addAll(myFields);
164         if (hasNativeMethods) {
165             fieldsOfSerializableOrNativeClassed.addAll(myFields);
166             fieldsOfNativeClassed.addAll(myFields);
167         }
168         if (isSerializable) {
169             fieldsOfSerializableOrNativeClassed.addAll(myFields);
170         }
171         if (sawSelfCallInConstructor)
172             writtenInConstructorFields.addAll(myFields);
173         myFields.clear();
174         allMyFields.clear();
175         calledFromConstructors.clear();
176     }
177
178     @Override JavaDoc
179          public void visit(Field obj) {
180         super.visit(obj);
181         XField f = XFactory.createXField(this);
182         allMyFields.add(f);
183         int flags = obj.getAccessFlags();
184         if ((flags & doNotConsider) == 0
185                 && !getFieldName().equals("serialVersionUID")) {
186
187             myFields.add(f);
188             if (obj.isFinal()) finalFields.add(f);
189             if (obj.isStatic()) staticFields.add(f);
190             if (obj.getName().equals("_jspx_dependants"))
191                 containerFields.add(f);
192         }
193     }
194
195     @Override JavaDoc
196     public void visitAnnotation(String JavaDoc annotationClass,
197             Map<String JavaDoc, Object JavaDoc> map, boolean runtimeVisible) {
198         if (!visitingField()) return;
199         if (annotationClass.startsWith("javax.annotation.") || annotationClass.startsWith("javax.ejb")|| annotationClass.equals("org.jboss.seam.annotations.In") || annotationClass.startsWith("javax.persistence")) {
200             containerFields.add(XFactory.createXField(this));
201         }
202         
203
204     }
205     @Override JavaDoc
206          public void visit(ConstantValue obj) {
207         // ConstantValue is an attribute of a field, so the instance variables
208
// set during visitation of the Field are still valid here
209
XField f = XFactory.createXField(this);
210         constantFields.add(f);
211     }
212
213
214     int count_aload_1;
215
216     private OpcodeStack opcodeStack = new OpcodeStack();
217     private int previousOpcode;
218     private int previousPreviousOpcode;
219     @Override JavaDoc
220          public void visit(Code obj) {
221     
222         count_aload_1 = 0;
223         previousOpcode = -1;
224         previousPreviousOpcode = -1;
225         nullTested.clear();
226         seenInvokeStatic = false;
227         opcodeStack.resetForMethodEntry(this);
228         staticFieldsReadInThisMethod.clear();
229         super.visit(obj);
230         if (getMethodName().equals("<init>") && count_aload_1 > 1
231                 && (getClassName().indexOf('$') >= 0
232                 || getClassName().indexOf('+') >= 0)) {
233             needsOuterObjectInConstructor.add(getDottedClassName());
234             // System.out.println(betterClassName + " needs outer object in constructor");
235
}
236     }
237
238     @Override JavaDoc
239          public void visit(Method obj) {
240         if (DEBUG) System.out.println("Checking " + getClassName() + "." + obj.getName());
241         if (getMethodName().equals("<init>")
242             && (obj.isPublic()
243                 || obj.isProtected() ))
244             publicOrProtectedConstructor = true;
245         super.visit(obj);
246         int flags = obj.getAccessFlags();
247         if ((flags & ACC_NATIVE) != 0)
248             hasNativeMethods = true;
249     }
250
251     boolean seenInvokeStatic;
252
253     @Override JavaDoc
254          public void sawOpcode(int seen) {
255         
256         opcodeStack.mergeJumps(this);
257         if (seen == GETSTATIC) {
258             XField f = XFactory.createReferencedXField(this);
259                     staticFieldsReadInThisMethod.add(f);
260             }
261         else if (seen == INVOKESTATIC) {
262             seenInvokeStatic = true;
263             }
264         else if (seen == PUTSTATIC
265             && !getMethod().isStatic()) {
266             XField f = XFactory.createReferencedXField(this);
267                     if (!staticFieldsReadInThisMethod.contains(f)) {
268                 int priority = LOW_PRIORITY;
269                 if (!publicOrProtectedConstructor)
270                     priority--;
271                 if (!seenInvokeStatic
272                      && staticFieldsReadInThisMethod.isEmpty())
273                     priority--;
274                 if (getThisClass().isPublic()
275                     && getMethod().isPublic())
276                     priority--;
277                 if (getThisClass().isPrivate()
278                     || getMethod().isPrivate())
279                     priority++;
280                 if (getClassName().indexOf('$') != -1)
281                     priority++;
282                 bugReporter.reportBug(new BugInstance(this,
283                         "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD",
284                     priority
285                     )
286                         .addClassAndMethod(this)
287                         .addField(f)
288                         .addSourceLine(this)
289                     );
290                 }
291             }
292
293
294         if (seen == INVOKEVIRTUAL || seen == INVOKEINTERFACE
295                 || seen == INVOKESPECIAL || seen==INVOKESTATIC ) {
296
297             String JavaDoc sig = getSigConstantOperand();
298             String JavaDoc invokedClassName = getClassConstantOperand();
299             if (invokedClassName.equals(getClassName())
300                     && (getMethodName().equals("<init>") || getMethodName().equals("<clinit>"))) {
301                 
302                 calledFromConstructors.add(getNameConstantOperand()+":"+sig);
303             }
304             int pos = PreorderVisitor.getNumberArguments(sig);
305             if (opcodeStack.getStackDepth() > pos) {
306                 OpcodeStack.Item item = opcodeStack.getStackItem(pos);
307                 boolean superCall = seen == INVOKESPECIAL
308                 && !invokedClassName .equals(getClassName());
309
310                 if (DEBUG)
311                     System.out.println("In " + getFullyQualifiedMethodName()
312                             + " saw call on " + item);
313
314
315
316                 boolean selfCall = item.getRegisterNumber() == 0
317                 && !superCall;
318                 if (selfCall && getMethodName().equals("<init>")) {
319                     sawSelfCallInConstructor = true;
320                     if (DEBUG)
321                         System.out.println("Saw self call in " + getFullyQualifiedMethodName() + " to " + invokedClassName + "." + getNameConstantOperand()
322                         );
323                 }
324             }
325         }
326
327         if ((seen == IFNULL || seen == IFNONNULL)
328             && opcodeStack.getStackDepth() > 0) {
329             OpcodeStack.Item item = opcodeStack.getStackItem(0);
330             XField f = item.getXField();
331             if (f != null) {
332                 nullTested.add(f);
333                 if (DEBUG)
334                 System.out.println(f + " null checked in " +
335                     getFullyQualifiedMethodName());
336                 }
337             }
338
339         if (seen == GETFIELD || seen == INVOKEVIRTUAL
340                 || seen == INVOKEINTERFACE
341                 || seen == INVOKESPECIAL || seen == PUTFIELD
342                 || seen == IALOAD || seen == AALOAD || seen == BALOAD || seen == CALOAD || seen == SALOAD
343                 || seen == IASTORE || seen == AASTORE || seen == BASTORE || seen == CASTORE || seen == SASTORE
344                 || seen == ARRAYLENGTH) {
345             int pos = 0;
346             switch(seen) {
347             case ARRAYLENGTH:
348             case GETFIELD :
349                 pos = 0;
350                 break;
351             case INVOKEVIRTUAL :
352             case INVOKEINTERFACE:
353             case INVOKESPECIAL:
354                 String JavaDoc sig = getSigConstantOperand();
355                 pos = PreorderVisitor.getNumberArguments(sig);
356                 break;
357             case PUTFIELD :
358             case IALOAD :
359             case AALOAD:
360             case BALOAD:
361             case CALOAD:
362             case SALOAD:
363                 pos = 1;
364                 break;
365             case IASTORE :
366             case AASTORE:
367             case BASTORE:
368             case CASTORE:
369             case SASTORE:
370                 pos = 2;
371                 break;
372             default: throw new RuntimeException JavaDoc("Impossible");
373             }
374             if (opcodeStack.getStackDepth() >= pos) {
375             OpcodeStack.Item item = opcodeStack.getStackItem(pos);
376             XField f = item.getXField();
377             if (DEBUG) System.out.println("RRR: " + f + " " + nullTested.contains(f) + " " + writtenInConstructorFields.contains(f) + " " + writtenNonNullFields.contains(f));
378             if (f != null && !nullTested.contains(f)
379                     && ! (writtenInConstructorFields.contains(f)
380                          && writtenNonNullFields.contains(f))
381                     ) {
382                 ProgramPoint p = new ProgramPoint(this);
383                 HashSet <ProgramPoint> s = assumedNonNull.get(f);
384                 if (s == null) {
385                     s = new HashSet<ProgramPoint>();
386                     assumedNonNull.put(f,s);
387                     }
388                 s.add(p);
389                 if (DEBUG)
390                 System.out.println(f + " assumed non-null in " +
391                     getFullyQualifiedMethodName());
392                 }
393             }
394             }
395
396         if (seen == ALOAD_1) {
397             count_aload_1++;
398         } else if (seen == GETFIELD || seen == GETSTATIC) {
399             XField f = XFactory.createReferencedXField(this);
400             if (DEBUG) System.out.println("get: " + f);
401             readFields.add(f);
402             if (!fieldAccess.containsKey(f))
403                 fieldAccess.put(f, SourceLineAnnotation.fromVisitedInstruction(this));
404         } else if (seen == PUTFIELD || seen == PUTSTATIC) {
405             XField f = XFactory.createReferencedXField(this);
406             OpcodeStack.Item item = null;
407             if (opcodeStack.getStackDepth() > 0) {
408                 item = opcodeStack.getStackItem(0);
409                 if (!item.isNull()) nullTested.add(f);
410             }
411             writtenFields.add(f);
412             if (!fieldAccess.containsKey(f))
413                 fieldAccess.put(f, SourceLineAnnotation.fromVisitedInstruction(this));
414             if (previousOpcode != ACONST_NULL || previousPreviousOpcode == GOTO ) {
415                 writtenNonNullFields.add(f);
416                 if (DEBUG) System.out.println("put nn: " + f);
417             }
418             else if (DEBUG) System.out.println("put: " + f);
419             
420             if ( getMethod().isStatic() == f.isStatic() && (
421                     calledFromConstructors.contains(getMethodName()+":"+getMethodSig())
422                     || getMethodName().equals("<init>")
423                     || getMethodName().equals("init")
424                     || getMethodName().equals("init")
425                     || getMethodName().equals("initialize")
426                     || getMethodName().equals("<clinit>")
427                     || getMethod().isPrivate())) {
428                 writtenInConstructorFields.add(f);
429                 if (previousOpcode != ACONST_NULL || previousPreviousOpcode == GOTO )
430                     assumedNonNull.remove(f);
431             } else {
432                 writtenOutsideOfConstructorFields.add(f);
433             }
434             
435             
436         }
437         opcodeStack.sawOpcode(this, seen);
438         previousPreviousOpcode = previousOpcode;
439         previousOpcode = seen;
440         if (false && DEBUG) {
441         System.out.println("After " + OPCODE_NAMES[seen] + " opcode stack is");
442         System.out.println(opcodeStack);
443         }
444         
445     }
446
447     Pattern JavaDoc dontComplainAbout = Pattern.compile("class[$]");
448     @Override JavaDoc
449          public void report() {
450         Set<String JavaDoc> fieldNamesSet = new HashSet<String JavaDoc>();
451         for(XField f : writtenNonNullFields)
452             fieldNamesSet.add(f.getName());
453         if (DEBUG) {
454             System.out.println("read fields:" );
455             for(XField f : readFields)
456                 System.out.println(" " + f);
457             if (!containerFields.isEmpty()) {
458                 System.out.println("ejb3 fields:" );
459                 for(XField f : containerFields)
460                     System.out.println(" " + f);
461             }
462         
463         
464             System.out.println("written fields:" );
465             for (XField f : writtenFields)
466                 System.out.println(" " + f);
467             System.out.println("written nonnull fields:" );
468             for (XField f : writtenNonNullFields)
469                 System.out.println(" " + f);
470         
471             System.out.println("assumed nonnull fields:" );
472             for (XField f : assumedNonNull.keySet())
473                 System.out.println(" " + f);
474         }
475         // Don't report anything about ejb3Fields
476
declaredFields.removeAll(containerFields);
477         
478         TreeSet<XField> notInitializedInConstructors =
479                 new TreeSet<XField>(declaredFields);
480         notInitializedInConstructors.retainAll(readFields);
481         notInitializedInConstructors.retainAll(writtenFields);
482         notInitializedInConstructors.retainAll(assumedNonNull.keySet());
483         notInitializedInConstructors.removeAll(staticFields);
484         notInitializedInConstructors.removeAll(writtenInConstructorFields);
485         // notInitializedInConstructors.removeAll(staticFields);
486

487         TreeSet<XField> readOnlyFields =
488                 new TreeSet<XField>(declaredFields);
489         readOnlyFields.removeAll(writtenFields);
490
491         readOnlyFields.retainAll(readFields);
492         
493         TreeSet<XField> nullOnlyFields =
494             new TreeSet<XField>(declaredFields);
495         nullOnlyFields.removeAll(writtenNonNullFields);
496
497         nullOnlyFields.retainAll(readFields);
498         
499         Set<XField> writeOnlyFields = declaredFields;
500         writeOnlyFields.removeAll(readFields);
501
502
503         for (XField f : notInitializedInConstructors) {
504             String JavaDoc fieldName = f.getName();
505             String JavaDoc className = f.getClassName();
506             String JavaDoc fieldSignature = f.getSignature();
507             if (f.isResolved()
508                     && !fieldsOfNativeClassed.contains(f)
509                     && (fieldSignature.charAt(0) == 'L' || fieldSignature.charAt(0) == '[')
510                     ) {
511                 int priority = LOW_PRIORITY;
512                 if (assumedNonNull.containsKey(f))
513                 bugReporter.reportBug(new BugInstance(this,
514                         "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR",
515                         priority)
516                         .addClass(className)
517                         .addField(f));
518             }
519         }
520
521
522         for (XField f : readOnlyFields) {
523             String JavaDoc fieldName = f.getName();
524             String JavaDoc className = f.getClassName();
525             String JavaDoc fieldSignature = f.getSignature();
526             if (f.isResolved()
527                     && !fieldsOfNativeClassed.contains(f)) {
528                 int priority = NORMAL_PRIORITY;
529                 if (!(fieldSignature.charAt(0) == 'L' || fieldSignature.charAt(0) == '['))
530                     priority++;
531
532                 bugReporter.reportBug(addClassFieldAndAccess(new BugInstance(this,
533                         "UWF_UNWRITTEN_FIELD",
534                         priority),f));
535             }
536
537         }
538         for (XField f : nullOnlyFields) {
539             String JavaDoc fieldName = f.getName();
540             String JavaDoc className = f.getClassName();
541             String JavaDoc fieldSignature = f.getSignature();
542             if (DEBUG) {
543                 System.out.println("Null only: " + f);
544                 System.out.println(" : " + assumedNonNull.containsKey(f));
545                 System.out.println(" : " + fieldsOfSerializableOrNativeClassed.contains(f));
546                 System.out.println(" : " + fieldNamesSet.contains(f.getName()));
547                 System.out.println(" : " + abstractClasses.contains(f.getClassName()));
548                 System.out.println(" : " + hasNonAbstractSubClass.contains(f.getClassName()));
549                 System.out.println(" : " + f.isResolved());
550             }
551             if (!f.isResolved()) continue;
552             if (fieldsOfNativeClassed.contains(f)) continue;
553             if (DEBUG) {
554                 System.out.println("Ready to report");
555             }
556             int priority = NORMAL_PRIORITY;
557             if (abstractClasses.contains(f.getClassName())) {
558                 priority++;
559                 if (! hasNonAbstractSubClass.contains(f.getClassName())) priority++;
560             }
561             // if (fieldNamesSet.contains(f.getName())) priority++;
562
if (assumedNonNull.containsKey(f)) {
563                 priority--;
564                 for (ProgramPoint p : assumedNonNull.get(f))
565                     bugReporter.reportBug(new BugInstance(this,
566                             "NP_UNWRITTEN_FIELD",
567                             NORMAL_PRIORITY)
568                             .addClassAndMethod(p.method)
569                             .addField(f)
570                             .addSourceLine(p.sourceLine)
571                     );
572             } else {
573                 if (f.isStatic()) priority++;
574                 if (finalFields.contains(f)) priority++;
575                 if (fieldsOfSerializableOrNativeClassed.contains(f)) priority++;
576             }
577             if (!readOnlyFields.contains(f))
578                 bugReporter.reportBug(
579                         addClassFieldAndAccess(new BugInstance(this,"UWF_NULL_FIELD",priority), f).lowerPriorityIfDeprecated()
580                     );
581         }
582
583         for (XField f : writeOnlyFields) {
584             String JavaDoc fieldName = f.getName();
585             String JavaDoc className = f.getClassName();
586             int lastDollar =
587                     Math.max(className.lastIndexOf('$'),
588                             className.lastIndexOf('+'));
589             boolean isAnonymousInnerClass =
590                     (lastDollar > 0)
591                             && (lastDollar < className.length() - 1)
592                             && Character.isDigit(className.charAt(className.length() - 1));
593
594             if (DEBUG) {
595                 System.out.println("Checking write only field " + className
596                         + "." + fieldName
597                         + "\t" + constantFields.contains(f)
598                         + "\t" + f.isStatic()
599                 );
600             }
601             if (!f.isResolved()) continue;
602             if (dontComplainAbout.matcher(fieldName).find()) continue;
603             if (fieldName.startsWith("this$")
604                     || fieldName.startsWith("this+")) {
605                 String JavaDoc outerClassName = className.substring(0, lastDollar);
606
607                 try {
608                     JavaClass outerClass = Repository.lookupClass(outerClassName);
609                     if (classHasParameter(outerClass)) continue;
610                 } catch (ClassNotFoundException JavaDoc e) {
611                     bugReporter.reportMissingClass(e);
612                 }
613                 if (!innerClassCannotBeStatic.contains(className)) {
614                     boolean easyChange = !needsOuterObjectInConstructor.contains(className);
615                     if (easyChange || !isAnonymousInnerClass) {
616
617                         // easyChange isAnonymousInnerClass
618
// true false medium, SIC
619
// true true low, SIC_ANON
620
// false true not reported
621
// false false low, SIC_THIS
622
int priority = LOW_PRIORITY;
623                         if (easyChange && !isAnonymousInnerClass)
624                             priority = NORMAL_PRIORITY;
625
626                         String JavaDoc bug = "SIC_INNER_SHOULD_BE_STATIC";
627                         if (isAnonymousInnerClass)
628                             bug = "SIC_INNER_SHOULD_BE_STATIC_ANON";
629                         else if (!easyChange)
630                             bug = "SIC_INNER_SHOULD_BE_STATIC_NEEDS_THIS";
631
632                         bugReporter.reportBug(new BugInstance(this, bug, priority)
633                                 .addClass(className));
634                     }
635                 }
636             } else {
637                 if (constantFields.contains(f)) {
638                     if (!f.isStatic())
639                         bugReporter.reportBug(addClassFieldAndAccess(new BugInstance(this,
640                                 "SS_SHOULD_BE_STATIC",
641                                 NORMAL_PRIORITY), f));
642                 } else if (fieldsOfSerializableOrNativeClassed.contains(f)) {
643                     // ignore it
644
} else if (!writtenFields.contains(f) && f.isResolved())
645                     bugReporter.reportBug(new BugInstance(this, "UUF_UNUSED_FIELD", NORMAL_PRIORITY)
646                             .addClass(className)
647                             .addField(f).lowerPriorityIfDeprecated());
648                 else if (f.getName().toLowerCase().indexOf("guardian") < 0) {
649                     int priority = NORMAL_PRIORITY;
650                     if (f.isStatic()) priority++;
651                     if (finalFields.contains(f)) priority++;
652                     bugReporter.reportBug(addClassFieldAndAccess(new BugInstance(this, "URF_UNREAD_FIELD", priority),f));
653                 }
654             }
655         }
656
657     }
658     /**
659      * @param instance
660      * @return
661      */

662     private BugInstance addClassFieldAndAccess(BugInstance instance, XField f) {
663         instance.addClass(f.getClassName()).addField(f);
664         if (fieldAccess.containsKey(f))
665             instance.add(fieldAccess.get(f));
666         return instance;
667     }
668     
669 }
670
Popular Tags