Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * fb-contrib - Auxiliary detectors for Java programs
   * Copyright (C) 2005-2015 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;
 
 
 
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.
 
     private static final Set<StringdangerousAssignmentClassSources = new HashSet<String>(7);
     private static final Set<StringdangerousAssignmentMethodSources = new HashSet<String>(4);
     private static final Set<PatterndangerousAssignmentMethodPatterns = new HashSet<Pattern>(1);
 
     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("javax/nio/channels/Channel");
         .add("io/netty/channel/Channel");
         
         .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");
         
         .add(Pattern.compile(".*serial.*".));
     }
 
     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(pcfindCatchHandlerFor(pc));
                sb.setTry();
                .addChild(sb);
            }
            if (OpcodeUtils.isStore(seen)) {
                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 == ) {
                int reg = getRegisterOperand();
                if (!.get(reg)) {
                    ScopeBlock sb = findScopeBlock(pc);
                    if (sb != null) {
                        sb.addLoad(regpc);
                    } 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 (OpcodeUtils.isLoad(seen)) {
                int reg = RegisterUtils.getLoadReg(thisseen);
                if (!.get(reg)) {
                    ScopeBlock sb = findScopeBlock(pc);
                    if (sb != null) {
                        sb.addLoad(regpc);
                    } else {
                        .set(reg);
                    }
                }
            } else if (((seen >= ) && (seen <= )) || (seen == ) || (seen == ) || (seen == )) {
                int target = getBranchTarget();
                if (target > pc) {
                    if ((seen == ) || (seen == )) {
                        int nextPC = getNextPC();
                        if (!.get(nextPC)) {
                            ScopeBlock sb = findScopeBlockWithTarget(pcnextPC);
                            if (sb == null) {
                                sb = new ScopeBlock(pctarget);
                                sb.setLoop();
                                sb.setGoto();
                                .addChild(sb);
                            } else {
                                sb = new ScopeBlock(nextPCtarget);
                                sb.setGoto();
                                .addChild(sb);
                            }
                        }
                    } else {
                        ScopeBlock sb = findScopeBlockWithTarget(pctarget);
                        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(pctarget);
                                .addChild(sb);
                            } else {
                                sb.pushUpLoadStores();
                                sb.setStart(pc);
                            }
                        } else {
                            sb = new ScopeBlock(pctarget);
                            .addChild(sb);
                        }
                    }
                } else {
                    ScopeBlock sb = findScopeBlock(pc);
                    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 == ) || (seen == )) {
                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 == ) || (seen == )) {
                if ("wasNull".equals(getNameConstantOperand()) && "()Z".equals(getSigConstantOperand())) {
                     = true;
                }
                uo = new UserObject();
                uo.isRisky = isRiskyMethodCall();
                uo.caller = getCallingObject();
                if (uo.caller != null) {
                    ScopeBlock sb = findScopeBlock(pc);
                    if (sb != null) {
                        sb.removeByAssoc(uo.caller);
                    }
                }
            } else if ((seen == ) || (seen == )) {
                uo = new UserObject();
                uo.isRisky = isRiskyMethodCall();
            } else if (seen == ) {
                .add(Integer.valueOf(pc));
                ScopeBlock sb = new ScopeBlock(pc.);
                sb.setSync();
                .addChild(sb);
            } else if (seen == ) {
                if (.size() > 0) {
                    ScopeBlock sb = findSynchronizedScopeBlock(.get(0).intValue());
                    if (sb != null)
                        sb.setFinish(pc);
                    .remove(.size() - 1);
                }
            }
             = (seen == );
             = (seen == );
        } 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 ToString.build(this);
        }

        
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..name(), )
                                    .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();
        if (.contains(key)) {
            return true;
        }
        
        for (Pattern p : ) {
            Matcher m = p.matcher(key);
            if (m.matches()) {
                return true;
            }
        }
        
        
        return false;
    }
    static class UserObject {
        Comparable<?> caller;
        boolean isRisky;
        @Override
        public String toString() {
        	return ToString.build(this);
        }
    }