[Fb-contrib-commit] fb-contrib/src/com/mebigfatguy/fbcontrib/detect StaticMethodInstanceInvocation.j
Brought to you by:
dbrosius
|
From: Dave B. <dbr...@us...> - 2005-11-17 05:23:22
|
Update of /cvsroot/fb-contrib/fb-contrib/src/com/mebigfatguy/fbcontrib/detect In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3178/src/com/mebigfatguy/fbcontrib/detect Modified Files: StaticMethodInstanceInvocation.java Log Message: baseing SMII on aload/pop pattern is small minded, so drop the aload requirement. Now check types to see if static method is defined. False positives still possible, perhaps need to check sourceline annotations to make sure the pop is on the same line as the INVOKESTATIC. Index: StaticMethodInstanceInvocation.java =================================================================== RCS file: /cvsroot/fb-contrib/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/StaticMethodInstanceInvocation.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- StaticMethodInstanceInvocation.java 16 Nov 2005 06:48:47 -0000 1.2 +++ StaticMethodInstanceInvocation.java 17 Nov 2005 05:23:15 -0000 1.3 @@ -18,6 +18,12 @@ */ package com.mebigfatguy.fbcontrib.detect; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.Method; import org.apache.bcel.generic.Type; @@ -27,14 +33,9 @@ import edu.umd.cs.findbugs.OpcodeStack; public class StaticMethodInstanceInvocation extends BytecodeScanningDetector { - private static final int SEEN_NOTHING = 0; - private static final int SEEN_ALOAD = 1; - private static final int SEEN_POP = 2; - private BugReporter bugReporter; private OpcodeStack stack = new OpcodeStack(); - private int state; - private int popDepth; + private List<PopInfo> popStack = new ArrayList<PopInfo>(); public StaticMethodInstanceInvocation(BugReporter bugReporter) { this.bugReporter = bugReporter; @@ -47,63 +48,97 @@ @Override public void visitMethod(Method obj) { - state = SEEN_NOTHING; stack.resetForMethodEntry(this); + popStack.clear(); super.visitMethod(obj); } @Override public void sawOpcode(int seen) { try { - switch (state) { - case SEEN_NOTHING: - if ((seen == ALOAD) || ((seen >= ALOAD_0) && (seen <= ALOAD_3))) - state = SEEN_ALOAD; - break; - - case SEEN_ALOAD: - if (seen == POP) { - state = SEEN_POP; - popDepth = stack.getStackDepth()-1; - } - else - state = SEEN_NOTHING; - break; - - case SEEN_POP: - if (stack.getStackDepth() < popDepth) - state = SEEN_NOTHING; - else if (seen == INVOKESTATIC) { - String sig = getSigConstantOperand(); - Type[] args = Type.getArgumentTypes(getSigConstantOperand()); - if (args.length == (stack.getStackDepth() - popDepth)) { + int sDepth = stack.getStackDepth(); + Iterator<PopInfo> it = popStack.iterator(); + + while (it.hasNext()) { + if (sDepth < it.next().popDepth) + it.remove(); + } + + if ((seen == INVOKESTATIC) && (popStack.size() > 0)) { + PopInfo pInfo = popStack.get(0); + Type[] args = Type.getArgumentTypes(getSigConstantOperand()); + if ((args.length > 0) || (pInfo.popPC == (getPC() - 1))) { + if (args.length == (stack.getStackDepth() - pInfo.popDepth)) { + if (classDefinesStaticMethod(pInfo.popSignature.substring(1, pInfo.popSignature.length() - 1))) { bugReporter.reportBug(new BugInstance(this, "SMII_STATIC_METHOD_INSTANCE_INVOCATION", NORMAL_PRIORITY) .addClass(this) .addMethod(this) .addSourceLine(this)); - state = SEEN_NOTHING; - } else { - Type result = Type.getReturnType(sig); - if ("V".equals(result.getSignature())) - state = SEEN_NOTHING; + popStack.clear(); } - } else if ((seen == ASTORE) - || ((seen >= ASTORE_0) && (seen <= ASTORE_3)) - || (seen == PUTFIELD) - || (seen == ATHROW) - || (seen == GOTO)) { - state = SEEN_NOTHING; - } else if ((seen == INVOKESPECIAL) - || (seen == INVOKEINTERFACE) - || (seen == INVOKEVIRTUAL)) { - Type result = Type.getReturnType(getSigConstantOperand()); - if ("V".equals(result.getSignature())) - state = SEEN_NOTHING; - } - break; + } + } } + + + if ((seen == ASTORE) + || ((seen >= ASTORE_0) && (seen <= ASTORE_3)) + || (seen == PUTFIELD) + || (seen == ATHROW) + || (seen == GOTO)) { + popStack.clear(); + } else if ((seen == INVOKESPECIAL) + || (seen == INVOKEINTERFACE) + || (seen == INVOKEVIRTUAL) + || (seen == INVOKESTATIC)) { + Type result = Type.getReturnType(getSigConstantOperand()); + if ("V".equals(result.getSignature())) + popStack.clear(); + } + + if (seen == POP) { + if (stack.getStackDepth() > 0) { + OpcodeStack.Item itm = stack.getStackItem(0); + String popSig = itm.getSignature(); + if (popSig.charAt(0) == 'L') + popStack.add(new PopInfo(getPC(), popSig, sDepth - 1)); + } + } + } catch (ClassNotFoundException cnfe) { + bugReporter.reportMissingClass(cnfe); + popStack.clear(); } finally { stack.sawOpcode(this, seen); } } + + boolean classDefinesStaticMethod(String popSignature) throws ClassNotFoundException { + popSignature = popSignature.replace('/', '.'); + if ("java.lang.Object".equals(popSignature)) + return false; + + JavaClass cls = Repository.lookupClass(popSignature); + Method[] methods = cls.getMethods(); + for (Method m : methods) { + if (m.isStatic()) { + if (m.getName().equals(getNameConstantOperand()) + && m.getSignature().equals(getSigConstantOperand())) + return true; + } + } + + return classDefinesStaticMethod(cls.getSuperclassName()); + } + + static class PopInfo { + int popPC; + String popSignature; + int popDepth; + + public PopInfo(int pc, String signature, int depth) { + popPC = pc; + popSignature = signature; + popDepth = depth; + } + } } |