Search in sources :

Example 1 with Statistics

use of com.mebigfatguy.fbcontrib.collect.Statistics in project fb-contrib by mebigfatguy.

the class PossiblyRedundantMethodCalls method sawOpcode.

/**
 * implements the visitor to look for repetitive calls to the same method on the same object using the same constant parameters. These methods must return a
 * value.
 *
 * @param seen
 *            the opcode of the currently parsed instruction
 */
@Override
public void sawOpcode(int seen) {
    String userValue = null;
    try {
        stack.precomputation(this);
        int pc = getPC();
        if (branchTargets.get(pc)) {
            localMethodCalls.clear();
            fieldMethodCalls.clear();
            branchTargets.clear(pc);
        }
        if (((seen >= Const.IFEQ) && (seen <= Const.GOTO)) || ((seen >= Const.IFNULL) && (seen <= Const.GOTO_W))) {
            branchTargets.set(getBranchTarget());
        } else if ((seen == Const.TABLESWITCH) || (seen == Const.LOOKUPSWITCH)) {
            int[] offsets = getSwitchOffsets();
            for (int offset : offsets) {
                branchTargets.set(offset + pc);
            }
            branchTargets.set(getDefaultSwitchOffset() + pc);
        } else if (OpcodeUtils.isAStore(seen)) {
            localMethodCalls.remove(Integer.valueOf(RegisterUtils.getAStoreReg(this, seen)));
        } else if (seen == Const.PUTFIELD) {
            String fieldSource = "";
            if (stack.getStackDepth() > 0) {
                OpcodeStack.Item item = stack.getStackItem(0);
                fieldSource = (String) item.getUserValue();
                if (fieldSource == null) {
                    fieldSource = "";
                }
            }
            fieldMethodCalls.remove(new FieldInfo(fieldSource, getNameConstantOperand()));
        } else if (seen == Const.GETFIELD) {
            if (stack.getStackDepth() > 0) {
                OpcodeStack.Item item = stack.getStackItem(0);
                userValue = (String) item.getUserValue();
                if (userValue == null) {
                    int reg = item.getRegisterNumber();
                    if (reg >= 0) {
                        userValue = String.valueOf(reg);
                    } else {
                        XField xf = item.getXField();
                        if (xf != null) {
                            userValue = xf.getName();
                        }
                    }
                }
            }
        } else if ((seen == Const.INVOKEVIRTUAL) || (seen == Const.INVOKEINTERFACE) || (seen == Const.INVOKESTATIC)) {
            String className = getClassConstantOperand();
            String methodName = getNameConstantOperand();
            String signature = getSigConstantOperand();
            int parmCount = SignatureUtils.getNumParameters(signature);
            int reg = -1;
            XField field = null;
            MethodCall mc = null;
            String fieldSource = null;
            if (seen == Const.INVOKESTATIC) {
                XMethod xm = XFactory.createXMethod(getDottedClassConstantOperand(), methodName, signature, true);
                String genericSignature = xm.getSourceSignature();
                if ((genericSignature != null) && genericSignature.endsWith(">;")) {
                    return;
                }
            } else if (stack.getStackDepth() > parmCount) {
                OpcodeStack.Item obj = stack.getStackItem(parmCount);
                reg = obj.getRegisterNumber();
                field = obj.getXField();
                if (reg >= 0) {
                    mc = localMethodCalls.get(Integer.valueOf(reg));
                    MethodInfo mi = Statistics.getStatistics().getMethodStatistics(className, getNameConstantOperand(), signature);
                    if ((mi != null) && mi.getModifiesState()) {
                        clearFieldMethods(String.valueOf(reg));
                        return;
                    }
                } else if (field != null) {
                    fieldSource = (String) obj.getUserValue();
                    if (fieldSource == null) {
                        fieldSource = "";
                    }
                    mc = fieldMethodCalls.get(new FieldInfo(fieldSource, field.getName()));
                    MethodInfo mi = Statistics.getStatistics().getMethodStatistics(className, getNameConstantOperand(), signature);
                    if ((mi != null) && mi.getModifiesState()) {
                        clearFieldMethods(fieldSource);
                        return;
                    }
                }
            }
            int neededStackSize = parmCount + ((seen == Const.INVOKESTATIC) ? 0 : 1);
            if (stack.getStackDepth() >= neededStackSize) {
                Object[] parmConstants = new Object[parmCount];
                for (int i = 0; i < parmCount; i++) {
                    OpcodeStack.Item parm = stack.getStackItem(i);
                    parmConstants[i] = parm.getConstant();
                    if (parm.getSignature().startsWith(Values.SIG_ARRAY_PREFIX)) {
                        if (!Values.ZERO.equals(parm.getConstant())) {
                            return;
                        }
                        XField f = parm.getXField();
                        if (f != null) {
                            // Two different fields holding a 0 length array should be considered different
                            parmConstants[i] = f.getName() + ':' + parmConstants[i];
                        }
                    }
                    if (parmConstants[i] == null) {
                        return;
                    }
                }
                if (seen == Const.INVOKESTATIC) {
                    mc = staticMethodCalls.get(className);
                } else if ((reg < 0) && (field == null)) {
                    return;
                }
                if (mc != null) {
                    if (!signature.endsWith(Values.SIG_VOID) && methodName.equals(mc.getName()) && signature.equals(mc.getSignature()) && !isRiskyName(className, methodName) && !commonMethods.contains(new FQMethod(getClassConstantOperand(), methodName, signature))) {
                        Object[] parms = mc.getParms();
                        if (Arrays.equals(parms, parmConstants)) {
                            int ln = getLineNumber(pc);
                            if ((ln != mc.getLineNumber()) || (Math.abs(pc - mc.getPC()) < 10)) {
                                Statistics statistics = Statistics.getStatistics();
                                MethodInfo mi = statistics.getMethodStatistics(getClassConstantOperand(), methodName, signature);
                                bugReporter.reportBug(new BugInstance(this, BugType.PRMC_POSSIBLY_REDUNDANT_METHOD_CALLS.name(), getBugPriority(methodName, mi)).addClass(this).addMethod(this).addSourceLine(this).addString(methodName + signature));
                            }
                        }
                    }
                    if (seen == Const.INVOKESTATIC) {
                        staticMethodCalls.remove(className);
                    } else {
                        if (reg >= 0) {
                            localMethodCalls.remove(Integer.valueOf(reg));
                        } else if (fieldSource != null) {
                            fieldMethodCalls.remove(new FieldInfo(fieldSource, field.getName()));
                        }
                    }
                } else {
                    int ln = getLineNumber(pc);
                    if (seen == Const.INVOKESTATIC) {
                        staticMethodCalls.put(className, new MethodCall(methodName, signature, parmConstants, pc, ln));
                    } else {
                        if (reg >= 0) {
                            localMethodCalls.put(Integer.valueOf(reg), new MethodCall(methodName, signature, parmConstants, pc, ln));
                        } else if (field != null) {
                            OpcodeStack.Item obj = stack.getStackItem(parmCount);
                            fieldSource = (String) obj.getUserValue();
                            if (fieldSource == null) {
                                fieldSource = "";
                            }
                            fieldMethodCalls.put(new FieldInfo(fieldSource, field.getName()), new MethodCall(methodName, signature, parmConstants, pc, ln));
                        }
                    }
                }
            }
        } else if (OpcodeUtils.isReturn(seen)) {
            localMethodCalls.clear();
            fieldMethodCalls.clear();
            branchTargets.clear(pc);
        }
    } finally {
        stack.sawOpcode(this, seen);
        if ((userValue != null) && (stack.getStackDepth() > 0)) {
            OpcodeStack.Item item = stack.getStackItem(0);
            item.setUserValue(userValue);
        }
    }
}
Also used : OpcodeStack(edu.umd.cs.findbugs.OpcodeStack) BugInstance(edu.umd.cs.findbugs.BugInstance) ToString(com.mebigfatguy.fbcontrib.utils.ToString) Statistics(com.mebigfatguy.fbcontrib.collect.Statistics) XField(edu.umd.cs.findbugs.ba.XField) XMethod(edu.umd.cs.findbugs.ba.XMethod) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod) MethodInfo(com.mebigfatguy.fbcontrib.collect.MethodInfo)

Aggregations

MethodInfo (com.mebigfatguy.fbcontrib.collect.MethodInfo)1 Statistics (com.mebigfatguy.fbcontrib.collect.Statistics)1 FQMethod (com.mebigfatguy.fbcontrib.utils.FQMethod)1 ToString (com.mebigfatguy.fbcontrib.utils.ToString)1 BugInstance (edu.umd.cs.findbugs.BugInstance)1 OpcodeStack (edu.umd.cs.findbugs.OpcodeStack)1 XField (edu.umd.cs.findbugs.ba.XField)1 XMethod (edu.umd.cs.findbugs.ba.XMethod)1