Search in sources :

Example 1 with FQMethod

use of com.mebigfatguy.fbcontrib.utils.FQMethod in project fb-contrib by mebigfatguy.

the class PresizeCollections method sawOpcode.

/**
 * implements the visitor to look for creation of collections that are then populated with a known number of elements usually based on another collection,
 * but the new collection is not presized.
 *
 * @param seen
 *            the opcode of the currently parsed instruction
 */
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "CLI_CONSTANT_LIST_INDEX", justification = "Constrained by FindBugs API")
@Override
public void sawOpcode(int seen) {
    PSCUserValue userValue = null;
    boolean sawAlloc = false;
    try {
        stack.precomputation(this);
        switch(seen) {
            case Const.INVOKESPECIAL:
                String clsName = getClassConstantOperand();
                if (PRESIZEABLE_COLLECTIONS.contains(clsName)) {
                    String methodName = getNameConstantOperand();
                    if (Values.CONSTRUCTOR.equals(methodName)) {
                        String signature = getSigConstantOperand();
                        if (SignatureBuilder.SIG_VOID_TO_VOID.equals(signature)) {
                            userValue = new PSCUserValue(Integer.valueOf(nextAllocNumber++));
                            sawAlloc = true;
                        } else if (guavaOnPath && (stack.getStackDepth() > 0)) {
                            FQMethod fqMethod = new FQMethod(clsName, methodName, signature);
                            if (HASHMAP_SIZED_CTOR.equals(fqMethod) || HASHSET_SIZED_CTOR.equals(fqMethod)) {
                                OpcodeStack.Item itm = stack.getStackItem(0);
                                XMethod xm = itm.getReturnValueOf();
                                if ((xm != null) && "size".equals(xm.getMethodDescriptor().getName())) {
                                    bugReporter.reportBug(new BugInstance(this, BugType.PSC_SUBOPTIMAL_COLLECTION_SIZING.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                                }
                            }
                        }
                    }
                }
                break;
            case Const.INVOKEINTERFACE:
                String methodName = getNameConstantOperand();
                if (ITERATOR_METHOD.equals(new QMethod(methodName, getSigConstantOperand()))) {
                    if (stack.getStackDepth() > 0) {
                        OpcodeStack.Item itm = stack.getStackItem(0);
                        userValue = isSizedSource(itm);
                    }
                } else if (ITERATOR_HASNEXT.equals(new FQMethod(getClassConstantOperand(), methodName, getSigConstantOperand()))) {
                    if (stack.getStackDepth() > 0) {
                        OpcodeStack.Item itm = stack.getStackItem(0);
                        userValue = (PSCUserValue) itm.getUserValue();
                    }
                } else if ("add".equals(methodName) || "addAll".equals(methodName)) {
                    String signature = getSigConstantOperand();
                    int numArguments = SignatureUtils.getNumParameters(signature);
                    if ((numArguments == 1) && (stack.getStackDepth() > 1)) {
                        OpcodeStack.Item item = stack.getStackItem(1);
                        PSCUserValue uv = (PSCUserValue) item.getUserValue();
                        if (uv != null) {
                            Integer allocNum = uv.getAllocationNumber();
                            if (allocNum != null) {
                                if ("addAll".equals(methodName)) {
                                    allocToAddPCs.remove(allocNum);
                                } else {
                                    List<Integer> lines = allocToAddPCs.get(allocNum);
                                    if (lines == null) {
                                        lines = new ArrayList<>();
                                        allocToAddPCs.put(allocNum, lines);
                                    }
                                    lines.add(Integer.valueOf(getPC()));
                                }
                            }
                        }
                    }
                } else if ("put".equals(methodName) || "putAll".equals(methodName)) {
                    String signature = getSigConstantOperand();
                    int numArguments = SignatureUtils.getNumParameters(signature);
                    if ((numArguments == 2) && (stack.getStackDepth() > 2)) {
                        OpcodeStack.Item item = stack.getStackItem(2);
                        PSCUserValue uv = (PSCUserValue) item.getUserValue();
                        if (uv != null) {
                            Integer allocNum = uv.getAllocationNumber();
                            if (allocNum != null) {
                                if ("putAll".equals(methodName)) {
                                    allocToAddPCs.remove(allocNum);
                                } else {
                                    List<Integer> lines = allocToAddPCs.get(allocNum);
                                    if (lines == null) {
                                        lines = new ArrayList<>();
                                        allocToAddPCs.put(allocNum, lines);
                                    }
                                    lines.add(Integer.valueOf(getPC()));
                                }
                            }
                        }
                    }
                }
                break;
            case Const.INVOKESTATIC:
                FQMethod fqm = new FQMethod(getClassConstantOperand(), getNameConstantOperand(), getSigConstantOperand());
                if (STATIC_COLLECTION_FACTORIES.contains(fqm)) {
                    userValue = new PSCUserValue(Integer.valueOf(nextAllocNumber++));
                    sawAlloc = true;
                }
                break;
            case Const.LOOKUPSWITCH:
            case Const.TABLESWITCH:
                int[] offsets = getSwitchOffsets();
                if (offsets.length >= 2) {
                    int pc = getPC();
                    int thisOffset = pc + offsets[0];
                    for (int o = 0; o < (offsets.length - 1); o++) {
                        int nextOffset = offsets[o + 1] + pc;
                        CodeRange db = new CodeRange(thisOffset, nextOffset, false);
                        optionalRanges.add(db);
                        thisOffset = nextOffset;
                    }
                }
                break;
            case Const.IFEQ:
            case Const.IFNE:
            case Const.IFLT:
            case Const.IFLE:
            case Const.IF_ICMPEQ:
            case Const.IF_ICMPNE:
            case Const.IF_ICMPLT:
            case Const.IF_ICMPGE:
            case Const.IF_ICMPGT:
            case Const.IF_ICMPLE:
            case Const.IF_ACMPEQ:
            case Const.IF_ACMPNE:
            case Const.GOTO:
            case Const.GOTO_W:
                if (getBranchOffset() < 0) {
                    if (branchBasedOnUnsizedObject(seen)) {
                        break;
                    }
                    int target = getBranchTarget();
                    Iterator<Map.Entry<Integer, List<Integer>>> it = allocToAddPCs.entrySet().iterator();
                    while (it.hasNext()) {
                        Map.Entry<Integer, List<Integer>> entry = it.next();
                        Integer allocLoc = allocLocation.get(entry.getKey());
                        if ((allocLoc != null) && (allocLoc.intValue() < target)) {
                            List<Integer> pcs = entry.getValue();
                            for (int pc : pcs) {
                                if (pc > target) {
                                    if (hasSinglePossiblySizedBranch(allocLoc.intValue(), pc)) {
                                        bugReporter.reportBug(new BugInstance(this, BugType.PSC_PRESIZE_COLLECTIONS.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this, pc));
                                        it.remove();
                                    }
                                    break;
                                }
                            }
                        }
                    }
                } else {
                    CodeRange db = new CodeRange(getPC(), getBranchTarget(), !branchBasedOnUnsizedObject(seen));
                    optionalRanges.add(db);
                }
                break;
            case Const.IFNULL:
            case Const.IFNONNULL:
            case Const.IFGE:
            case Const.IFGT:
                // null check and >, >= branches are hard to presize
                if (getBranchOffset() > 0) {
                    CodeRange db = new CodeRange(getPC(), getBranchTarget(), false);
                    optionalRanges.add(db);
                }
                break;
            case Const.ASTORE:
            case Const.ASTORE_0:
            case Const.ASTORE_1:
            case Const.ASTORE_2:
            case Const.ASTORE_3:
                {
                    if (stack.getStackDepth() > 0) {
                        PSCUserValue uv = (PSCUserValue) stack.getStackItem(0).getUserValue();
                        if (uv != null) {
                            storeToUserValue.put(getRegisterOperand(), uv);
                        }
                    }
                }
                break;
            case Const.ALOAD:
            case Const.ALOAD_0:
            case Const.ALOAD_1:
            case Const.ALOAD_2:
            case Const.ALOAD_3:
                {
                    userValue = storeToUserValue.get(getRegisterOperand());
                }
                break;
            case Const.PUTFIELD:
                {
                    if (stack.getStackDepth() > 0) {
                        PSCUserValue uv = (PSCUserValue) stack.getStackItem(0).getUserValue();
                        if (uv != null) {
                            storeToUserValue.put(getNameConstantOperand(), uv);
                        }
                    }
                }
                break;
            case Const.GETFIELD:
                {
                    userValue = storeToUserValue.get(getNameConstantOperand());
                }
        }
    } finally {
        stack.sawOpcode(this, seen);
        if ((userValue != null) && (stack.getStackDepth() > 0)) {
            OpcodeStack.Item item = stack.getStackItem(0);
            item.setUserValue(userValue);
            if (sawAlloc) {
                allocLocation.put(userValue.getAllocationNumber(), Integer.valueOf(getPC()));
            }
        }
    }
}
Also used : OpcodeStack(edu.umd.cs.findbugs.OpcodeStack) ArrayList(java.util.ArrayList) BugInstance(edu.umd.cs.findbugs.BugInstance) ToString(com.mebigfatguy.fbcontrib.utils.ToString) QMethod(com.mebigfatguy.fbcontrib.utils.QMethod) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod) XMethod(edu.umd.cs.findbugs.ba.XMethod) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod) ArrayList(java.util.ArrayList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map)

Example 2 with FQMethod

use of com.mebigfatguy.fbcontrib.utils.FQMethod in project fb-contrib by mebigfatguy.

the class PresizeCollections method branchBasedOnUnsizedObject.

/**
 * returns if the conditional is based on a method call from an object that has no sizing to determine what presize should be. it's possible the correct
 * implementation should just return true, if <code>if ((seen != IFNE) || (stack.getStackDepth() == 0))</code>
 *
 * @param seen
 *            the current visited opcode
 * @return whether this conditional is based on a unsized object
 */
private boolean branchBasedOnUnsizedObject(int seen) {
    if ((seen == Const.IF_ACMPEQ) || (seen == Const.IF_ACMPNE)) {
        return true;
    }
    if ((seen != Const.IFNE) || (stack.getStackDepth() == 0)) {
        return false;
    }
    OpcodeStack.Item itm = stack.getStackItem(0);
    XMethod xm = itm.getReturnValueOf();
    if (xm == null) {
        return false;
    }
    FQMethod fqm = new FQMethod(xm.getClassName().replace('.', '/'), xm.getName(), xm.getSignature());
    if (ITERATOR_HASNEXT.equals(fqm)) {
        PSCUserValue uv = (PSCUserValue) itm.getUserValue();
        if (uv == null) {
            return true;
        }
        return !uv.hasSizedSource();
    }
    return UNSIZED_SOURCES.contains(fqm);
}
Also used : OpcodeStack(edu.umd.cs.findbugs.OpcodeStack) XMethod(edu.umd.cs.findbugs.ba.XMethod) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod)

Example 3 with FQMethod

use of com.mebigfatguy.fbcontrib.utils.FQMethod in project fb-contrib by mebigfatguy.

the class UseCharacterParameterizedMethod method sawOpcode.

/**
 * implements the visitor to look for method calls that pass a constant string as a parameter when the string is only one character long, and there is an
 * alternate method passing a character.
 */
@Override
public void sawOpcode(int seen) {
    try {
        stack.precomputation(this);
        if ((seen == Const.INVOKEVIRTUAL) || (seen == Const.INVOKEINTERFACE)) {
            FQMethod key = new FQMethod(getClassConstantOperand(), getNameConstantOperand(), getSigConstantOperand());
            Object posObject = characterMethods.get(key);
            if (posObject instanceof Integer) {
                if (checkSingleParamMethod(((Integer) posObject).intValue()) && !isInlineAppend(key)) {
                    reportBug();
                }
            } else if ((posObject instanceof IntPair) && checkDoubleParamMethod((IntPair) posObject)) {
                reportBug();
            }
        } else if (seen == Const.DUP) {
            if (stack.getStackDepth() > 0) {
                OpcodeStack.Item itm = stack.getStackItem(0);
                String duppedSig = itm.getSignature();
                if ("Ljava/lang/StringBuilder;".equals(duppedSig) || "Ljava/lang/StringBuffer;".equals(duppedSig)) {
                    itm.setUserValue(UCPMUserValue.INLINE);
                }
            }
        } else if ((seen == Const.PUTFIELD) || (((seen == Const.PUTSTATIC) || OpcodeUtils.isAStore(seen)) && (stack.getStackDepth() > 0))) {
            OpcodeStack.Item itm = stack.getStackItem(0);
            itm.setUserValue(null);
        }
    } finally {
        UCPMUserValue uv = callHasInline(seen);
        stack.sawOpcode(this, seen);
        if ((uv == UCPMUserValue.INLINE) && (stack.getStackDepth() > 0)) {
            OpcodeStack.Item itm = stack.getStackItem(0);
            itm.setUserValue(uv);
        }
    }
}
Also used : OpcodeStack(edu.umd.cs.findbugs.OpcodeStack) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod) ToString(com.mebigfatguy.fbcontrib.utils.ToString)

Example 4 with FQMethod

use of com.mebigfatguy.fbcontrib.utils.FQMethod in project fb-contrib by mebigfatguy.

the class UnnecessaryApiConversion method sawOpcode.

@Override
public void sawOpcode(int seen) {
    try {
        switch(seen) {
            case INVOKEVIRTUAL:
                FQMethod conversionMethod = new FQMethod(getClassConstantOperand(), getNameConstantOperand(), getSigConstantOperand());
                LegacyInfo legacyInfo = conversions.get(conversionMethod);
                if ((legacyInfo != null) && (stack.getStackDepth() > 0)) {
                    OpcodeStack.Item itm = stack.getStackItem(0);
                    XMethod xm = itm.getReturnValueOf();
                    if ((xm != null) && (xm.getName().equals(legacyInfo.methodName) && (xm.getClassName().equals(conversionMethod.getClassName().replace('/', '.'))))) {
                        bugReporter.reportBug(new BugInstance(this, legacyInfo.bugType.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                    }
                }
                break;
            default:
                break;
        }
    } finally {
        stack.sawOpcode(this, seen);
    }
}
Also used : OpcodeStack(edu.umd.cs.findbugs.OpcodeStack) XMethod(edu.umd.cs.findbugs.ba.XMethod) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod) BugInstance(edu.umd.cs.findbugs.BugInstance)

Example 5 with FQMethod

use of com.mebigfatguy.fbcontrib.utils.FQMethod in project fb-contrib by mebigfatguy.

the class StringifiedTypes method sawOpcode.

@Override
public void sawOpcode(int seen) {
    String userValue = null;
    int[] checkParms = null;
    try {
        stack.precomputation(this);
        int stackDepth = stack.getStackDepth();
        switch(seen) {
            case Const.INVOKEVIRTUAL:
                {
                    String clsName = getClassConstantOperand();
                    String methodName = getNameConstantOperand();
                    String sig = getSigConstantOperand();
                    boolean isStringBuilder = SignatureUtils.isPlainStringConvertableClass(clsName);
                    if (Values.TOSTRING.equals(methodName) && SignatureBuilder.SIG_VOID_TO_STRING.equals(sig)) {
                        if (isStringBuilder) {
                            if (stackDepth > 0) {
                                OpcodeStack.Item item = stack.getStackItem(0);
                                userValue = (String) item.getUserValue();
                            }
                        } else {
                            userValue = Values.TOSTRING;
                        }
                    } else if (isStringBuilder) {
                        if ("append".equals(methodName)) {
                            if (stackDepth > 0) {
                                OpcodeStack.Item item = stack.getStackItem(0);
                                userValue = (String) item.getUserValue();
                                if ((userValue == null) && !Values.SIG_JAVA_LANG_STRING.equals(item.getSignature())) {
                                    userValue = Values.TOSTRING;
                                    if (stackDepth > 1) {
                                        item = stack.getStackItem(1);
                                        int reg = item.getRegisterNumber();
                                        if (reg >= 0) {
                                            toStringStringBuilders.set(reg);
                                        }
                                    }
                                }
                            }
                        } else if ((stackDepth > 1) && "setLength".equals(methodName)) {
                            OpcodeStack.Item item = stack.getStackItem(1);
                            item.setUserValue(null);
                            int reg = item.getRegisterNumber();
                            if (reg >= 0) {
                                toStringStringBuilders.clear(reg);
                            }
                        }
                    } else if (Values.SLASHED_JAVA_LANG_STRING.equals(clsName)) {
                        Integer priority = STRING_PARSE_METHODS.get(methodName);
                        if (priority != null) {
                            int numParameters = SignatureUtils.getNumParameters(sig);
                            if (stackDepth > numParameters) {
                                OpcodeStack.Item item = stack.getStackItem(numParameters);
                                if ((item.getXField() != null) || FROM_FIELD.equals(item.getUserValue())) {
                                    bugReporter.reportBug(new BugInstance(this, BugType.STT_STRING_PARSING_A_FIELD.name(), priority.intValue()).addClass(this).addMethod(this).addSourceLine(this));
                                }
                            }
                        }
                    }
                }
                break;
            case Const.INVOKEINTERFACE:
                {
                    String clsName = getClassConstantOperand();
                    String methodName = getNameConstantOperand();
                    String sig = getSigConstantOperand();
                    int numParameters = SignatureUtils.getNumParameters(sig);
                    if (stackDepth > numParameters) {
                        FQMethod cm = new FQMethod(clsName, methodName, sig);
                        checkParms = COLLECTION_PARMS.get(cm);
                        if (checkParms != null) {
                            OpcodeStack.Item item = stack.getStackItem(numParameters);
                            if (item.getXField() == null) {
                                if (MAP_PUT.equals(cm)) {
                                    OpcodeStack.Item itm = stack.getStackItem(1);
                                    XMethod xm = itm.getReturnValueOf();
                                    if (xm != null) {
                                        if (Values.DOTTED_JAVA_LANG_STRINGBUILDER.equals(xm.getClassName())) {
                                            bugReporter.reportBug(new BugInstance(this, BugType.STT_TOSTRING_MAP_KEYING.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                                        }
                                    }
                                }
                            } else {
                                for (int parm : checkParms) {
                                    if ((parm >= 0) && Values.TOSTRING.equals(stack.getStackItem(parm).getUserValue())) {
                                        bugReporter.reportBug(new BugInstance(this, BugType.STT_TOSTRING_STORED_IN_FIELD.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
                break;
            case Const.PUTFIELD:
                if (stackDepth > 0) {
                    OpcodeStack.Item item = stack.getStackItem(0);
                    if (Values.TOSTRING.equals(item.getUserValue())) {
                        bugReporter.reportBug(new BugInstance(this, BugType.STT_TOSTRING_STORED_IN_FIELD.name(), NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
                    }
                }
                break;
            case Const.ALOAD:
            case Const.ALOAD_0:
            case Const.ALOAD_1:
            case Const.ALOAD_2:
            case Const.ALOAD_3:
                {
                    int reg = RegisterUtils.getALoadReg(this, seen);
                    if (toStringStringBuilders.get(reg)) {
                        userValue = Values.TOSTRING;
                    }
                }
                break;
            case Const.ASTORE:
            case Const.ASTORE_0:
            case Const.ASTORE_1:
            case Const.ASTORE_2:
            case Const.ASTORE_3:
                {
                    int reg = RegisterUtils.getAStoreReg(this, seen);
                    toStringStringBuilders.clear(reg);
                }
                break;
            default:
                break;
        }
    } finally {
        stack.sawOpcode(this, seen);
        if ((userValue != null) && (stack.getStackDepth() > 0)) {
            OpcodeStack.Item item = stack.getStackItem(0);
            item.setUserValue(userValue);
        }
        if ((checkParms != null) && (checkParms[0] == -1) && (stack.getStackDepth() > 0)) {
            OpcodeStack.Item item = stack.getStackItem(0);
            item.setUserValue(FROM_FIELD);
        }
    }
}
Also used : OpcodeStack(edu.umd.cs.findbugs.OpcodeStack) XMethod(edu.umd.cs.findbugs.ba.XMethod) BugInstance(edu.umd.cs.findbugs.BugInstance) FQMethod(com.mebigfatguy.fbcontrib.utils.FQMethod)

Aggregations

FQMethod (com.mebigfatguy.fbcontrib.utils.FQMethod)25 OpcodeStack (edu.umd.cs.findbugs.OpcodeStack)15 BugInstance (edu.umd.cs.findbugs.BugInstance)13 XMethod (edu.umd.cs.findbugs.ba.XMethod)7 ToString (com.mebigfatguy.fbcontrib.utils.ToString)6 HashMap (java.util.HashMap)3 Map (java.util.Map)3 Method (org.apache.bcel.classfile.Method)3 MethodInfo (com.mebigfatguy.fbcontrib.collect.MethodInfo)2 QMethod (com.mebigfatguy.fbcontrib.utils.QMethod)2 JavaClass (org.apache.bcel.classfile.JavaClass)2 Statistics (com.mebigfatguy.fbcontrib.collect.Statistics)1 XField (edu.umd.cs.findbugs.ba.XField)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1 Matcher (java.util.regex.Matcher)1 Pattern (java.util.regex.Pattern)1 Nullable (javax.annotation.Nullable)1 AnnotationEntry (org.apache.bcel.classfile.AnnotationEntry)1 BootstrapMethod (org.apache.bcel.classfile.BootstrapMethod)1