Search in sources :

Example 6 with MethodInfo

use of com.mebigfatguy.fbcontrib.collect.MethodInfo 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)

Example 7 with MethodInfo

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

the class ModifyingUnmodifiableCollection method sawOpcode.

/**
 * overrides the visitor to find method mutations on collections that have previously been determined to have been created as immutable collections
 *
 * @param seen
 *            the currently parsed opcode
 */
@Override
public void sawOpcode(int seen) {
    ImmutabilityType imType = null;
    try {
        stack.precomputation(this);
        switch(seen) {
            case INVOKESTATIC:
            case INVOKEINTERFACE:
            case INVOKESPECIAL:
            case INVOKEVIRTUAL:
                {
                    String className = getClassConstantOperand();
                    String methodName = getNameConstantOperand();
                    String signature = getSigConstantOperand();
                    MethodInfo mi = Statistics.getStatistics().getMethodStatistics(className, methodName, signature);
                    imType = mi.getImmutabilityType();
                    if (seen == INVOKEINTERFACE) {
                        Integer collectionOffset = MODIFYING_METHODS.get(new QMethod(methodName, signature));
                        if ((collectionOffset != null) && CollectionUtils.isListSetMap(className) && (stack.getStackDepth() > collectionOffset.intValue())) {
                            OpcodeStack.Item item = stack.getStackItem(collectionOffset.intValue());
                            ImmutabilityType type = (ImmutabilityType) item.getUserValue();
                            if ((type == ImmutabilityType.IMMUTABLE) || ((type == ImmutabilityType.POSSIBLY_IMMUTABLE) && (reportedType != ImmutabilityType.POSSIBLY_IMMUTABLE))) {
                                bugReporter.reportBug(new BugInstance(this, BugType.MUC_MODIFYING_UNMODIFIABLE_COLLECTION.name(), (type == ImmutabilityType.IMMUTABLE) ? HIGH_PRIORITY : NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                                if (type == ImmutabilityType.IMMUTABLE) {
                                    throw new StopOpcodeParsingException();
                                }
                                reportedType = type;
                            }
                        }
                    }
                }
                break;
            default:
                break;
        }
    } catch (ClassNotFoundException cnfe) {
        bugReporter.reportMissingClass(cnfe);
    } finally {
        stack.sawOpcode(this, seen);
        if ((imType != null) && (stack.getStackDepth() > 0)) {
            OpcodeStack.Item item = stack.getStackItem(0);
            item.setUserValue(imType);
        }
    }
}
Also used : QMethod(com.mebigfatguy.fbcontrib.utils.QMethod) OpcodeStack(edu.umd.cs.findbugs.OpcodeStack) ImmutabilityType(com.mebigfatguy.fbcontrib.collect.ImmutabilityType) StopOpcodeParsingException(com.mebigfatguy.fbcontrib.utils.StopOpcodeParsingException) BugInstance(edu.umd.cs.findbugs.BugInstance) MethodInfo(com.mebigfatguy.fbcontrib.collect.MethodInfo)

Example 8 with MethodInfo

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

the class AnnotationIssues method visitCode.

@Override
public void visitCode(Code obj) {
    Method method = getMethod();
    String sig = method.getSignature();
    String returnType = sig.substring(sig.indexOf(')') + 1);
    char returnTypeChar = returnType.charAt(0);
    if ((returnTypeChar != 'L') && (returnTypeChar != '[')) {
        return;
    }
    if (method.isSynthetic() && !isCollecting()) {
        return;
    }
    if (Values.SIG_JAVA_LANG_VOID.equals(returnType)) {
        return;
    }
    if (methodHasNullableAnnotation(method)) {
        if (isCollecting()) {
            MethodInfo methodInfo = Statistics.getStatistics().getMethodStatistics(getClassName(), method.getName(), method.getSignature());
            methodInfo.setCanReturnNull(true);
        }
        return;
    }
    MethodInfo methodInfo = Statistics.getStatistics().getMethodStatistics(getClassName(), method.getName(), method.getSignature());
    if (!isCollecting() && methodInfo.getCanReturnNull()) {
        bugReporter.reportBug(new BugInstance(this, BugType.AI_ANNOTATION_ISSUES_NEEDS_NULLABLE.name(), LOW_PRIORITY).addClass(this).addMethod(this));
    } else {
        methodIsNullable = false;
        stack.resetForMethodEntry(this);
        assumedNullTill.clear();
        assumedNonNullTill.clear();
        noAssumptionsPossible.clear();
        super.visitCode(obj);
        if (methodIsNullable) {
            if (isCollecting()) {
                methodInfo.setCanReturnNull(true);
            } else {
                bugReporter.reportBug(new BugInstance(this, BugType.AI_ANNOTATION_ISSUES_NEEDS_NULLABLE.name(), LOW_PRIORITY).addClass(this).addMethod(this));
            }
        }
    }
}
Also used : BugInstance(edu.umd.cs.findbugs.BugInstance) MethodInfo(com.mebigfatguy.fbcontrib.collect.MethodInfo) Method(org.apache.bcel.classfile.Method) XMethod(edu.umd.cs.findbugs.ba.XMethod)

Example 9 with MethodInfo

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

the class BloatedAssignmentScope method sawInstanceCall.

/**
 * processes a instance method call to see if that call is modifies state or is otherwise'risky', if so mark the variable(s) associated with the caller as
 * not reportable
 *
 * @param pc
 *            the current program counter
 *
 * @return a user object to place on the return value's OpcodeStack item
 */
@Nullable
private UserObject sawInstanceCall(int pc) {
    String signature = getSigConstantOperand();
    String name = getNameConstantOperand();
    // this is kind of a wart. there should be a more seamless way to check this
    if ("wasNull".equals(getNameConstantOperand()) && SignatureBuilder.SIG_VOID_TO_BOOLEAN.equals(signature)) {
        dontReport = true;
    }
    if (signature.endsWith(Values.SIG_VOID)) {
        return null;
    }
    MethodInfo mi = Statistics.getStatistics().getMethodStatistics(getClassConstantOperand(), name, signature);
    UserObject uo = new UserObject(getCallingObject(), mi.getModifiesState() || isRiskyMethodCall());
    if (uo.caller != null) {
        ScopeBlock sb = findScopeBlock(rootScopeBlock, pc);
        if (sb != null) {
            sb.removeByAssoc(uo.caller);
        }
    }
    return uo;
}
Also used : MethodInfo(com.mebigfatguy.fbcontrib.collect.MethodInfo) ToString(com.mebigfatguy.fbcontrib.utils.ToString) Nullable(javax.annotation.Nullable)

Example 10 with MethodInfo

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

the class BloatedSynchronizedBlock method sawOpcode.

/**
 * implement the visitor to find bloated sync blocks. This implementation only checks the outer most block
 *
 * @param seen
 *            the opcode of the currently parsed instruction
 */
@Override
public void sawOpcode(int seen) {
    try {
        stack.precomputation(this);
        if (unsafeCallOccurred && OpcodeUtils.isAStore(seen)) {
            int storeReg = RegisterUtils.getAStoreReg(this, seen);
            if (storeReg >= 0) {
                unsafeAliases.set(storeReg);
            }
        }
        if ((seen == Const.INVOKEVIRTUAL) || (seen == Const.INVOKESPECIAL) || (seen == Const.INVOKEINTERFACE) || (seen == Const.INVOKEDYNAMIC)) {
            String methodSig = getSigConstantOperand();
            MethodInfo mi = Statistics.getStatistics().getMethodStatistics(getClassConstantOperand(), getNameConstantOperand(), methodSig);
            if (mi.getModifiesState()) {
                unsafeCallOccurred = true;
            } else {
                if (!Values.SIG_VOID.equals(SignatureUtils.getReturnSignature(methodSig))) {
                    int parmCount = SignatureUtils.getNumParameters(methodSig);
                    if (stack.getStackDepth() > parmCount) {
                        OpcodeStack.Item itm = stack.getStackItem(parmCount);
                        unsafeCallOccurred = unsafeAliases.get(itm.getRegisterNumber());
                    } else {
                        unsafeCallOccurred = false;
                    }
                } else {
                    unsafeCallOccurred = false;
                }
            }
        } else if (seen == Const.INVOKESTATIC) {
            unsafeCallOccurred = getDottedClassConstantOperand().equals(this.getClassContext().getJavaClass().getClassName());
        } else if (((seen >= Const.IFEQ) && (seen <= Const.GOTO)) || (seen == Const.GOTO_W)) {
            Integer from = Integer.valueOf(getPC());
            Integer to = Integer.valueOf(getBranchTarget());
            branchInfo.put(from, to);
            unsafeCallOccurred = false;
        } else {
            unsafeCallOccurred = false;
        }
        if (seen == Const.MONITORENTER) {
            if (syncPC < 0) {
                syncPC = getPC();
                if (stack.getStackDepth() > 0) {
                    OpcodeStack.Item itm = stack.getStackItem(0);
                    int monitorReg = itm.getRegisterNumber();
                    if (monitorReg >= 0) {
                        unsafeAliases.set(monitorReg);
                    }
                }
            }
        } else if (seen == Const.MONITOREXIT) {
            syncPC = -1;
        } else if (syncPC >= 0) {
            processSyncBlockInstruction(seen);
        }
    } finally {
        stack.sawOpcode(this, seen);
    }
}
Also used : OpcodeStack(edu.umd.cs.findbugs.OpcodeStack) MethodInfo(com.mebigfatguy.fbcontrib.collect.MethodInfo)

Aggregations

MethodInfo (com.mebigfatguy.fbcontrib.collect.MethodInfo)10 BugInstance (edu.umd.cs.findbugs.BugInstance)5 OpcodeStack (edu.umd.cs.findbugs.OpcodeStack)4 FQMethod (com.mebigfatguy.fbcontrib.utils.FQMethod)3 ToString (com.mebigfatguy.fbcontrib.utils.ToString)2 XMethod (edu.umd.cs.findbugs.ba.XMethod)2 BootstrapMethod (org.apache.bcel.classfile.BootstrapMethod)2 Method (org.apache.bcel.classfile.Method)2 ImmutabilityType (com.mebigfatguy.fbcontrib.collect.ImmutabilityType)1 Statistics (com.mebigfatguy.fbcontrib.collect.Statistics)1 QMethod (com.mebigfatguy.fbcontrib.utils.QMethod)1 StopOpcodeParsingException (com.mebigfatguy.fbcontrib.utils.StopOpcodeParsingException)1 XField (edu.umd.cs.findbugs.ba.XField)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 Nullable (javax.annotation.Nullable)1 ConstantCP (org.apache.bcel.classfile.ConstantCP)1 ConstantClass (org.apache.bcel.classfile.ConstantClass)1 ConstantInvokeDynamic (org.apache.bcel.classfile.ConstantInvokeDynamic)1 ConstantMethodHandle (org.apache.bcel.classfile.ConstantMethodHandle)1