Update of /cvsroot/fb-contrib/fb-contrib/src/com/mebigfatguy/fbcontrib/detect
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3019/src/com/mebigfatguy/fbcontrib/detect
Modified Files:
PossibleMemoryBloat.java
Log Message:
don't report static collections that have no 'increasing' methods eg. .add in methods other then constructors of static initializers. Also report the line number of this first increasing method.
Index: PossibleMemoryBloat.java
===================================================================
RCS file: /cvsroot/fb-contrib/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/PossibleMemoryBloat.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- PossibleMemoryBloat.java 7 Mar 2006 06:28:33 -0000 1.2
+++ PossibleMemoryBloat.java 8 Mar 2006 04:38:31 -0000 1.3
@@ -1,11 +1,14 @@
package com.mebigfatguy.fbcontrib.detect;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
import org.apache.bcel.classfile.Code;
import org.apache.bcel.classfile.Field;
import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.Type;
import edu.umd.cs.findbugs.BugInstance;
@@ -13,6 +16,7 @@
import edu.umd.cs.findbugs.BytecodeScanningDetector;
import edu.umd.cs.findbugs.FieldAnnotation;
import edu.umd.cs.findbugs.OpcodeStack;
+import edu.umd.cs.findbugs.SourceLineAnnotation;
import edu.umd.cs.findbugs.StatelessDetector;
import edu.umd.cs.findbugs.ba.ClassContext;
@@ -45,18 +49,35 @@
bloatableSigs.add("Ljava/util/TreeSet;");
bloatableSigs.add("Ljava/util/Vector;");
}
- private static final Set<String> clearingMethods = new HashSet<String>();
+ private static final Set<String> decreasingMethods = new HashSet<String>();
static {
- clearingMethods.add("clear");
- clearingMethods.add("delete");
- clearingMethods.add("deleteCharAt");
- clearingMethods.add("pop");
- clearingMethods.add("remove");
- clearingMethods.add("setLength");
+ decreasingMethods.add("clear");
+ decreasingMethods.add("delete");
+ decreasingMethods.add("deleteCharAt");
+ decreasingMethods.add("pop");
+ decreasingMethods.add("remove");
+ decreasingMethods.add("removeAll");
+ decreasingMethods.add("removeAllElements");
+ decreasingMethods.add("removeElementAt");
+ decreasingMethods.add("removeRange");
+ decreasingMethods.add("setLength");
+ }
+
+ private static final Set<String> increasingMethods = new HashSet<String>();
+ static {
+ increasingMethods.add("add");
+ increasingMethods.add("addAll");
+ increasingMethods.add("addElement");
+ increasingMethods.add("addFirst");
+ increasingMethods.add("addLast");
+ increasingMethods.add("append");
+ increasingMethods.add("insertElementAt");
+ increasingMethods.add("put");
}
private BugReporter bugReporter;
- private Set<FieldAnnotation> bloatableFields = new HashSet<FieldAnnotation>();
+ private Map<FieldAnnotation, SourceLineAnnotation> bloatableFields = new HashMap<FieldAnnotation, SourceLineAnnotation>();
private OpcodeStack stack = new OpcodeStack();
+ private String methodName;
/**
* constructs a PMB detector given the reporter to report bugs on
@@ -91,7 +112,7 @@
if (f.isStatic()) {
String sig = f.getSignature();
if (bloatableSigs.contains(sig)) {
- bloatableFields.add(FieldAnnotation.fromBCELField(cls.getClassName(), f));
+ bloatableFields.put(FieldAnnotation.fromBCELField(cls.getClassName(), f), null);
}
}
}
@@ -99,15 +120,29 @@
if (bloatableFields.size() > 0) {
super.visitClassContext(classContext);
- for (FieldAnnotation fa : bloatableFields) {
- bugReporter.reportBug(new BugInstance(this, "PMB_POSSIBLE_MEMORY_BLOAT", NORMAL_PRIORITY)
- .addClass(this)
- .addField(fa));
+ for (Map.Entry<FieldAnnotation, SourceLineAnnotation> entry : bloatableFields.entrySet()) {
+ SourceLineAnnotation sla = entry.getValue();
+ if (sla != null) {
+ bugReporter.reportBug(new BugInstance(this, "PMB_POSSIBLE_MEMORY_BLOAT", NORMAL_PRIORITY)
+ .addClass(this)
+ .addSourceLine(sla)
+ .addField(entry.getKey()));
+ }
}
}
}
/**
+ * implements the visitor to collect the method name
+ *
+ * @param obj the context object of the currently parsed method
+ */
+ @Override
+ public void visitMethod(Method obj) {
+ methodName = obj.getName();
+ }
+
+ /**
* implements the visitor to reset the opcode stack
*
* @param obj the context object of the currently parsed code block
@@ -115,6 +150,11 @@
@Override
public void visitCode(Code obj) {
stack.resetForMethodEntry(this);
+
+ if ("<clinit>".equals(methodName)
+ || "<init>".equals(methodName))
+ return;
+
if (bloatableFields.size() > 0)
super.visitCode(obj);
}
@@ -141,10 +181,15 @@
OpcodeStack.Item itm = stack.getStackItem(argCount);
FieldAnnotation fa = itm.getField();
if (fa != null) {
- if (bloatableFields.contains(fa)) {
+ if (bloatableFields.containsKey(fa)) {
String methodName = getNameConstantOperand();
- if (clearingMethods.contains(methodName)) {
+ if (decreasingMethods.contains(methodName)) {
bloatableFields.remove(fa);
+ } else if (increasingMethods.contains(methodName)) {
+ if (bloatableFields.get(fa) == null) {
+ SourceLineAnnotation sla = SourceLineAnnotation.fromVisitedInstruction(this);
+ bloatableFields.put(fa, sla);
+ }
}
}
}
|