Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * fb-contrib - Auxiliary detectors for Java programs
   * Copyright (C) 2005-2014 Dave Brosius
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 package com.mebigfatguy.fbcontrib.detect;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import  org.apache.bcel.classfile.Code;
 import  org.apache.bcel.classfile.CodeException;
 import  org.apache.bcel.classfile.Method;
 import  org.apache.bcel.generic.Type;
 
 
looks for variable assignments at a scope larger than its use. In this case, the assignment can be pushed down into the smaller scope to reduce the performance impact of that assignment.
 
 public class BloatedAssignmentScope extends BytecodeScanningDetector {
     private static final Set<StringdangerousAssignmentClassSources = new HashSet<String>(7);
     private static final Set<StringdangerousAssignmentMethodSources = new HashSet<String>(4);
 
     static {
         .add("java/io/BufferedInputStream");
         .add("java/io/DataInputStream");
         .add("java/io/InputStream");
         .add("java/io/ObjectInputStream");
         .add("java/io/BufferedReader");
         .add("java/io/FileReader");
         .add("java/io/Reader");
         .add("java/lang/System.currentTimeMillis()J");
         .add("java/lang/System.nanoTime()J");
         .add("java/util/Calendar.get(I)I");
         .add("java/util/GregorianCalendar.get(I)I");
         .add("java/util/Iterator.next()Ljava/lang/Object;");
         .add("java/util/regex/Matcher.start()I");
     }
 
     private OpcodeStack stack;
     private BitSet ignoreRegs;
     private ScopeBlock rootScopeBlock;
     private BitSet tryBlocks;
     private BitSet catchHandlers;
     private BitSet switchTargets;
     private List<IntegermonitorSyncPCs;
     private boolean dontReport;
     private boolean sawDup;
     private boolean sawNull;

    
constructs a BAS detector given the reporter to report bugs on

Parameters:
bugReporter the sync of bug reports
 
     public BloatedAssignmentScope(BugReporter bugReporter) {
         this. = bugReporter;
     }

    
implements the visitor to create and the clear the register to location map

Parameters:
classContext the context object of the currently parsed class
    @Override
    public void visitClassContext(ClassContext classContext) {
        try {
             = new BitSet();
             = new BitSet();
             = new BitSet();
             = new BitSet();
             = new ArrayList<Integer>(5);
             = new OpcodeStack();
            super.visitClassContext(classContext);
        } finally {
             = null;
             = null;
             = null;
             = null;
             = null;
             = null;
        }
    }

    
implements the visitor to reset the register to location map

Parameters:
obj the context object of the currently parsed code block
    @Override
    public void visitCode(Code obj) {
        try {
            .clear();
            Method method = getMethod();
            if (!method.isStatic()) {
                .set(0);
            }
            int[] parmRegs = RegisterUtils.getParameterRegisters(method);
            for (int parm : parmRegs) {
                .set(parm);
            }
             = new ScopeBlock(0, obj.getLength());
            .clear();
            .clear();
            CodeException[] exceptions = obj.getExceptionTable();
            if (exceptions != null) {
                for (CodeException ex : exceptions) {
                    .set(ex.getStartPC());
                    .set(ex.getHandlerPC());
                }
            }
            .clear();
            .resetForMethodEntry(this);
             = false;
             = false;
             = false;
            super.visitCode(obj);
            if (!) {
                .findBugs(new HashSet<Integer>());
            }
        } finally {
             = null;
        }
    }

    
implements the visitor to look for variables assigned below the scope in which they are used.

Parameters:
seen the opcode of the currently parsed instruction
    @Override
    public void sawOpcode(int seen) {
        UserObject uo = null;
        try {
            .precomputation(this);
            int pc = getPC();
            if (.get(pc)) {
                ScopeBlock sb = new ScopeBlock(getPC(), findCatchHandlerFor(pc));
                sb.setTry();
                .addChild(sb);
            }
            if ((seen == ASTORE) || (seen == ISTORE) || (seen == LSTORE) || (seen == FSTORE) || (seen == DSTORE) || ((seen >= ASTORE_0) && (seen <= ASTORE_3))
                    || ((seen >= ISTORE_0) && (seen <= ISTORE_3)) || ((seen >= LSTORE_0) && (seen <= LSTORE_3)) || ((seen >= FSTORE_0) && (seen <= FSTORE_1))
                    || ((seen >= DSTORE_0) && (seen <= DSTORE_1))) {
                int reg = RegisterUtils.getStoreReg(thisseen);
                if (.get(pc)) {
                    .set(reg);
                } else if (.size() > 0) {
                    .set(reg);
                } else if () {
                    .set(reg);
                }
                if (!.get(reg)) {
                    ScopeBlock sb = findScopeBlock(pc);
                    if (sb != null) {
                        UserObject assoc = null;
                        if (.getStackDepth() > 0) {
                            assoc = (UserObject.getStackItem(0).getUserValue();
                        }
                        if ((assoc != null) && assoc.isRisky) {
                            .set(reg);
                        } else {
                            sb.addStore(regpcassoc);
                            if () {
                                sb.addLoad(regpc);
                            }
                        }
                    } else {
                        .set(reg);
                    }
                }
            } else if (seen == IINC) {
                int reg = getRegisterOperand();
                if (!.get(reg)) {
                    ScopeBlock sb = findScopeBlock(getPC());
                    if (sb != null) {
                        sb.addLoad(reggetPC());
                    } else {
                        .set(reg);
                    }
                }
                if (.get(pc)) {
                    .set(reg);
                } else if (.size() > 0) {
                    .set(reg);
                } else if () {
                    .set(reg);
                }
                if (!.get(reg)) {
                    ScopeBlock sb = findScopeBlock(pc);
                    if (sb != null) {
                        sb.addStore(regpcnull);
                        if () {
                            sb.addLoad(regpc);
                        }
                    } else {
                        .set(reg);
                    }
                }
            } else if ((seen == ALOAD) || (seen == ILOAD) || (seen == LLOAD) || (seen == FLOAD) || (seen == DLOAD) || ((seen >= ALOAD_0) && (seen <= ALOAD_3))
                    || ((seen >= ILOAD_0) && (seen <= ILOAD_3)) || ((seen >= LLOAD_0) && (seen <= LLOAD_3)) || ((seen >= FLOAD_0) && (seen <= FLOAD_1))
                    || ((seen >= DLOAD_0) && (seen <= DLOAD_1))) {
                int reg = RegisterUtils.getLoadReg(thisseen);
                if (!.get(reg)) {
                    ScopeBlock sb = findScopeBlock(getPC());
                    if (sb != null) {
                        sb.addLoad(reggetPC());
                    } else {
                        .set(reg);
                    }
                }
            } else if (((seen >= IFEQ) && (seen <= GOTO)) || (seen == IFNULL) || (seen == IFNONNULL) || (seen == GOTO_W)) {
                int target = getBranchTarget();
                if (target > getPC()) {
                    if ((seen == GOTO) || (seen == GOTO_W)) {
                        int nextPC = getNextPC();
                        if (!.get(nextPC)) {
                            ScopeBlock sb = findScopeBlockWithTarget(getPC(), nextPC);
                            if (sb == null) {
                                sb = new ScopeBlock(getPC(), target);
                                sb.setLoop();
                                sb.setGoto();
                                .addChild(sb);
                            } else {
                                sb = new ScopeBlock(getPC(), target);
                                sb.setGoto();
                                .addChild(sb);
                            }
                        }
                    } else {
                        ScopeBlock sb = findScopeBlockWithTarget(getPC(), target);
                        if ((sb != null) && (!sb.isLoop()) && !sb.isCase() && !sb.hasChildren()) {
                            if (sb.isGoto()) {
                                ScopeBlock parent = sb.getParent();
                                sb.pushUpLoadStores();
                                if (parent != null) {
                                    parent.removeChild(sb);
                                }
                                sb = new ScopeBlock(getPC(), target);
                                .addChild(sb);
                            } else {
                                sb.pushUpLoadStores();
                                sb.setStart(getPC());
                                sb.setFinish(target);
                            }
                        } else {
                            sb = new ScopeBlock(getPC(), target);
                            .addChild(sb);
                        }
                    }
                } else {
                    ScopeBlock sb = findScopeBlock(getPC());
                    if (sb != null) {
                        ScopeBlock parentSB = sb.getParent();
                        while (parentSB != null) {
                            if (parentSB.getStart() >= target) {
                                sb = parentSB;
                                parentSB = parentSB.getParent();
                            } else {
                                break;
                            }
                        }
                        sb.setLoop();
                    }
                }
            } else if ((seen == TABLESWITCH) || (seen == LOOKUPSWITCH)) {
                int[] offsets = getSwitchOffsets();
                List<Integertargets = new ArrayList<Integer>(offsets.length);
                for (int offset : offsets) {
                    targets.add(Integer.valueOf(offset + pc));
                }
                Integer defOffset = Integer.valueOf(getDefaultSwitchOffset() + pc);
                if (!targets.contains(defOffset)) {
                    targets.add(defOffset);
                }
                Collections.sort(targets);
                Integer lastTarget = targets.get(0);
                for (int i = 1; i < targets.size(); i++) {
                    Integer nextTarget = targets.get(i);
                    ScopeBlock sb = new ScopeBlock(lastTarget.intValue(), nextTarget.intValue());
                    sb.setCase();
                    .addChild(sb);
                    lastTarget = nextTarget;
                }
                for (Integer target : targets) {
                    .set(target.intValue());
                }
            } else if ((seen == INVOKEVIRTUAL) || (seen == INVOKEINTERFACE)) {
                if ("wasNull".equals(getNameConstantOperand()) && "()Z".equals(getSigConstantOperand())) {
                     = true;
                }
                uo = new UserObject();
                uo.isRisky = isRiskyMethodCall();
                uo.caller = getCallingObject();
                if (uo.caller != null) {
                    ScopeBlock sb = findScopeBlock(getPC());
                    if (sb != null) {
                        sb.removeByAssoc(uo.caller);
                    }
                }
            } else if ((seen == INVOKESTATIC) || (seen == INVOKESPECIAL)) {
                uo = new UserObject();
                uo.isRisky = isRiskyMethodCall();
            } else if (seen == MONITORENTER) {
                .add(Integer.valueOf(getPC()));
                ScopeBlock sb = new ScopeBlock(getPC(), .);
                sb.setSync();
                .addChild(sb);
            } else if (seen == MONITOREXIT) {
                if (.size() > 0) {
                    ScopeBlock sb = findSynchronizedScopeBlock(.get(0));
                    if (sb != null)
                        sb.setFinish(getPC());
                    .remove(.size() - 1);
                }
            }
             = (seen == DUP);
             = (seen == ACONST_NULL);
        } finally {
            TernaryPatcher.pre(seen);
            .sawOpcode(thisseen);
            TernaryPatcher.post(seen);
            if (uo != null) {
                if (.getStackDepth() > 0) {
                    OpcodeStack.Item item = .getStackItem(0);
                    item.setUserValue(uo);
                }
            }
        }
    }

    
returns either a register number of a field reference of the object that a method is being called on, or null, if it can't be determined.

Returns:
either an Integer for a register, or a String for the field name, or null
    private Comparable<?> getCallingObject() {
        String sig = getSigConstantOperand();
        if ("V".equals(Type.getReturnType(sig).getSignature())) {
            return null;
        }
        Type[] types = Type.getArgumentTypes(sig);
        if (.getStackDepth() <= types.length) {
            return null;
        }
        OpcodeStack.Item caller = .getStackItem(types.length);
        int reg = caller.getRegisterNumber();
        if (reg >= 0) {
            return Integer.valueOf(reg);
        }
        /*
         * We ignore the possibility of two fields with the same name in
         * different classes
         */
        XField f = caller.getXField();
        if (f != null) {
            return f.getName();
        }
        return null;
    }

    
returns the scope block in which this register was assigned, by traversing the scope block tree

Parameters:
sb the scope block to start searching in
pc the current program counter
Returns:
the scope block or null if not found
    private ScopeBlock findScopeBlock(ScopeBlock sbint pc) {
        if ((pc > sb.getStart()) && (pc < sb.getFinish())) {
            if (sb.children != null) {
                for (ScopeBlock child : sb.children) {
                    ScopeBlock foundSb = findScopeBlock(childpc);
                    if (foundSb != null) {
                        return foundSb;
                    }
                }
            }
            return sb;
        }
        return null;
    }

    
returns an existing scope block that has the same target as the one looked for

Parameters:
sb the scope block to start with
target the target to look for
Returns:
the scope block found or null
    private ScopeBlock findScopeBlockWithTarget(ScopeBlock sbint startint target) {
        ScopeBlock parentBlock = null;
        if ((sb.startLocation < start) && (sb.finishLocation >= start)) {
            if ((sb.finishLocation <= target) || (sb.isGoto() && !sb.isLoop())) {
                parentBlock = sb;
            }
        }
        if (sb.children != null) {
            for (ScopeBlock child : sb.children) {
                ScopeBlock targetBlock = findScopeBlockWithTarget(childstarttarget);
                if (targetBlock != null) {
                    return targetBlock;
                }
            }
        }
        return parentBlock;
    }

    
finds the scope block that is the active synchronized block

Returns:
the scope block
    private ScopeBlock findSynchronizedScopeBlock(ScopeBlock sbint monitorEnterPC) {
        ScopeBlock monitorBlock = sb;
        if (sb.hasChildren()) {
            for (ScopeBlock child : sb.getChildren()) {
                if (child.isSync()) {
                    if (child.getStart() > monitorBlock.getStart()) {
                        monitorBlock = child;
                        monitorBlock = findSynchronizedScopeBlock(monitorBlockmonitorEnterPC);
                    }
                }
            }
        }
        return monitorBlock;
    }

    
returns the catch handler for a given try block

Parameters:
pc the current instruction
Returns:
the pc of the handler for this pc if it's the start of a try block, or -1
    private int findCatchHandlerFor(int pc) {
        CodeException[] exceptions = getMethod().getCode().getExceptionTable();
        if (exceptions != null) {
            for (CodeException ex : exceptions) {
                if (ex.getStartPC() == pc)
                    return ex.getHandlerPC();
            }
        }
        return -1;
    }

    
holds the description of a scope { } block, be it a for, if, while block
    private class ScopeBlock {
        private ScopeBlock parent;
        private int startLocation;
        private int finishLocation;
        private boolean isLoop;
        private boolean isGoto;
        private boolean isSync;
        private boolean isTry;
        private boolean isCase;
        private Map<IntegerIntegerloads;
        private Map<IntegerIntegerstores;
        private Map<UserObjectIntegerassocs;
        private List<ScopeBlockchildren;

        
construts a new scope block

Parameters:
start the beginning of the block
finish the end of the block
        public ScopeBlock(int startint finish) {
             = null;
             = start;
             = finish;
             = false;
             = false;
             = false;
             = false;
             = false;
             = null;
             = null;
             = null;
             = null;
        }

        
returns a string representation of the scope block

Returns:
a string representation
        @Override
        public String toString() {
            return "Start=" +  + " Finish=" +  + " Loads=" +  + " Stores=" +  + " Loop=" +  + " Goto=" +  + " Sync=" +  + " Try=" +  + " Case=" + ;
        }

        
returns the scope blocks parent

Returns:
the parent of this scope block
        public ScopeBlock getParent() {
            return ;
        }

        
returns the children of this scope block

Returns:
the scope blocks children
        public List<ScopeBlockgetChildren() {
            return ;
        }

        
returns the start of the block

Returns:
the start of the block
        public int getStart() {
            return ;
        }

        
returns the end of the block

Returns:
the end of the block
        public int getFinish() {
            return ;
        }

        
sets the start pc of the block

Parameters:
start the start pc
        public void setStart(int start) {
             = start;
        }

        
sets the finish pc of the block

Parameters:
finish the finish pc
        public void setFinish(int finish) {
             = finish;
        }
        public boolean hasChildren() {
            return  != null;
        }

        
sets that this block is a loop
        public void setLoop() {
             = true;
        }

        
returns whether this scope block is a loop

Returns:
whether this block is a loop
        public boolean isLoop() {
            return ;
        }

        
sets that this block was caused from a goto, (an if block exit)
        public void setGoto() {
             = true;
        }

        
returns whether this block was caused from a goto

Returns:
whether this block was caused by a goto
        public boolean isGoto() {
            return ;
        }

        
sets that this block was caused from a synchronized block
        public void setSync() {
             = true;
        }

        
returns whether this block was caused from a synchronized block

Returns:
whether this block was caused by a synchronized block
        public boolean isSync() {
            return ;
        }

        
sets that this block was caused from a try block
        public void setTry() {
             = true;
        }

        
returns whether this block was caused from a try block

Returns:
whether this block was caused by a try block
        public boolean isTry() {
            return ;
        }

        
sets that this block was caused from a case block
        public void setCase() {
             = true;
        }

        
returns whether this block was caused from a case block

Returns:
whether this block was caused by a case block
        public boolean isCase() {
            return ;
        }

        
adds the register as a store in this scope block

Parameters:
reg the register that was stored
pc the instruction that did the store
        public void addStore(int regint pcUserObject assocObject) {
            if ( == null) {
                 = new HashMap<IntegerInteger>(6);
            }
            .put(Integer.valueOf(reg), Integer.valueOf(pc));
            if ( == null) {
                 = new HashMap<UserObjectInteger>(6);
            }
            .put(assocObject, Integer.valueOf(reg));
        }

        
removes stores to registers that where retrieved from method calls on assocObject

Parameters:
assocObject the object that a method call was just performed on
        public void removeByAssoc(Object assocObject) {
            if ( != null) {
                Integer reg = .remove(assocObject);
                if (reg != null) {
                    if ( != null) {
                        .remove(reg);
                    }
                    if ( != null) {
                        .remove(reg);
                    }
                }
            }
        }

        
adds the register as a load in this scope block

Parameters:
reg the register that was loaded
pc the instruction that did the load
        public void addLoad(int regint pc) {
            if ( == null) {
                 = new HashMap<IntegerInteger>(10);
            }
            .put(Integer.valueOf(reg), Integer.valueOf(pc));
        }

        
adds a scope block to this subtree by finding the correct place in the hierarchy to store it

Parameters:
newChild the scope block to add to the tree
        public void addChild(ScopeBlock newChild) {
            newChild.parent = this;
            if ( != null) {
                for (ScopeBlock child : ) {
                    if ((newChild.startLocation > child.startLocation) && (newChild.startLocation < child.finishLocation)) {
                        if (newChild.finishLocation > child.finishLocation)
                            newChild.finishLocation = child.finishLocation;
                        child.addChild(newChild);
                        return;
                    }
                }
                int pos = 0;
                for (ScopeBlock child : ) {
                    if (newChild.startLocation < child.startLocation) {
                        .add(posnewChild);
                        return;
                    }
                    pos++;
                }
                .add(newChild);
                return;
            }
             = new ArrayList<ScopeBlock>();
            .add(newChild);
        }

        
removes a child from this node

Parameters:
child the child to remove
        public void removeChild(ScopeBlock child) {
            if ( != null) {
                .remove(child);
            }
        }

        
report stores that occur at scopes higher than associated loads that are not involved with loops
        public void findBugs(Set<IntegerparentUsedRegs) {
            if () {
                return;
            }
            Set<IntegerusedRegs = new HashSet<Integer>(parentUsedRegs);
            if ( != null) {
                usedRegs.addAll(.keySet());
            }
            if ( != null) {
                usedRegs.addAll(.keySet());
            }
            if ( != null) {
                if ( != null) {
                    .keySet().removeAll(.keySet());
                }
                .keySet().removeAll(parentUsedRegs);
                for (int r = .nextSetBit(0); r >= 0; r = .nextSetBit(r + 1)) {
                    .remove(Integer.valueOf(r));
                }
                if ((.size() > 0) && ( != null)) {
                    for (Map.Entry<IntegerIntegerentry : .entrySet()) {
                        int childUseCount = 0;
                        boolean inIgnoreSB = false;
                        Integer reg = entry.getKey();
                        for (ScopeBlock child : ) {
                            if (child.usesReg(reg)) {
                                if (child.isLoop || child.isSync() || child.isTry()) {
                                    inIgnoreSB = true;
                                    break;
                                }
                                childUseCount++;
                            }
                        }
                        if ((!inIgnoreSB) && (childUseCount == 1)) {
                            .reportBug(new BugInstance(BloatedAssignmentScope.this"BAS_BLOATED_ASSIGNMENT_SCOPE", NORMAL_PRIORITY)
                                    .addClass(BloatedAssignmentScope.this).addMethod(BloatedAssignmentScope.this)
                                    .addSourceLine(BloatedAssignmentScope.thisentry.getValue().intValue()));
                        }
                    }
                }
            }
            if ( != null) {
                for (ScopeBlock child : ) {
                    child.findBugs(usedRegs);
                }
            }
        }

        
returns whether this block either loads or stores into the register in question

Parameters:
reg the register to look for loads or stores
Returns:
whether the block uses the register
        public boolean usesReg(Integer reg) {
            if (( != null) && (.containsKey(reg))) {
                return true;
            }
            if (( != null) && (.containsKey(reg))) {
                return true;
            }
            if ( != null) {
                for (ScopeBlock child : ) {
                    if (child.usesReg(reg)) {
                        return true;
                    }
                }
            }
            return false;
        }

        
push all loads and stores to this block up to the parent
        public void pushUpLoadStores() {
            if ( != null) {
                if ( != null) {
                    if (. != null) {
                        ..putAll();
                    } else {
                        . = ;
                    }
                }
                if ( != null) {
                    if (. != null) {
                        ..putAll();
                    } else {
                        . = ;
                    }
                }
                 = null;
                 = null;
            }
        }
    }
    public boolean isRiskyMethodCall() {
        String clsName = getClassConstantOperand();
        if (.contains(clsName)) {
            return true;
        }
        String key = clsName + "." + getNameConstantOperand() + getSigConstantOperand();
        return .contains(key);
    }
    static class UserObject {
        Comparable<?> caller;
        boolean isRisky;
        @Override
        public String toString() {
            return "Caller: " +  + " isRisky: " + ;
        }
    }
New to GrepCode? Check out our FAQ X