1 20 21 package edu.umd.cs.findbugs.detect; 22 23 24 import java.util.Collection ; 25 import java.util.HashMap ; 26 import java.util.HashSet ; 27 import java.util.LinkedList ; 28 import java.util.Map ; 29 import java.util.Set ; 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 <Field> maskedFields = new HashSet <Field>(); 52 private Map <String , Field> classFields = new HashMap <String , Field>(); 53 private boolean staticMethod; 54 55 private Collection <RememberedBug> 56 rememberedBugs = new LinkedList <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 73 public void visitClassContext(ClassContext classContext) { 74 JavaClass obj = classContext.getJavaClass(); 75 if (!obj.isInterface()) 76 classContext.getJavaClass().accept(this); 77 } 78 79 @Override 80 public void visit(JavaClass obj) { 81 classFields.clear(); 82 83 Field[] fields = obj.getFields(); 84 String fieldName; 85 for (Field field : fields) if (!field.isStatic() && !field.isPrivate()){ 86 fieldName = field.getName(); 87 classFields.put(fieldName, field); 88 } 89 90 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 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 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 e) { 148 bugReporter.reportMissingClass(e); 149 } 150 151 super.visit(obj); 152 } 153 154 @Override 155 public void visit(Method obj) { 156 super.visit(obj); 157 numParms = getNumberMethodArguments(); 158 if (!obj.isStatic()) numParms++; 159 staticMethod = obj.isStatic(); 162 } 163 164 168 private static final boolean ENABLE_LOCALS = 169 SystemProperties.getBoolean("findbugs.maskedfields.locals"); 170 171 @Override 172 public void visit(LocalVariableTable obj) { 173 if (ENABLE_LOCALS) { 174 if (staticMethod) 175 return; 176 177 LocalVariable[] vars = obj.getLocalVariableTable(); 178 for (LocalVariable var : vars) { 180 if (var.getIndex() < numParms) 181 continue; 182 String varName = var.getName(); 183 if (varName.equals("serialVersionUID")) 184 continue; 185 Field f = classFields.get(varName); 186 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 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 | Popular Tags |