Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * fb-contrib - Auxiliary detectors for Java programs
   * Copyright (C) 2005-2012 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;
 
 
 import  edu.umd.cs.findbugs.BugInstance;
 import  edu.umd.cs.findbugs.BugReporter;
 import  edu.umd.cs.findbugs.BytecodeScanningDetector;
 import  edu.umd.cs.findbugs.OpcodeStack;
 import  edu.umd.cs.findbugs.ba.ClassContext;
 import  edu.umd.cs.findbugs.ba.XField;

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>();
 	private static final Set<StringdangerousAssignmentMethodSources = new HashSet<String>();
 
 	static {
 		.add("java/io/InputStream");
 		.add("java/io/ObjectInput");
 				.add("java/lang/System.currentTimeMillis()J");
 	}
 
 	BugReporter bugReporter;
 	private OpcodeStack stack;
 	private Set<IntegerignoreRegs;
 	private Set<IntegercatchHandlers;
 	private Set<IntegerswitchTargets;
 	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
 
 	public void visitClassContext(ClassContext classContext) {
 		try {
 			 = new HashSet<Integer>();
 			 = new OpcodeStack();
 			super.visitClassContext(classContext);
 		} finally {
 			 = 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
	public void visitCode(Code obj) {
		try {
			Method method = getMethod();
			if (!method.isStatic()) {
				.add(Integer.valueOf(0));
			}
			int[] parmRegs = RegisterUtils.getParameterRegisters(method);
			for (int parm : parmRegs) {
				.add(Integer.valueOf(parm));
			}
			 = new ScopeBlock(0, obj.getLength());
			CodeException[] exceptions = obj.getExceptionTable();
			if (exceptions != null) {
				for (CodeException ex : exceptions) {
					.add(Integer.valueOf(ex.getHandlerPC()));
				}
			}
			.resetForMethodEntry(this);
			 = false;
			 = false;
			 = false;
			super.visitCode(obj);
			if (!) {
			}
finally {
		}
	}

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
	public void sawOpcode(int seen) {
		UserObject uo = null;
		try {
			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);
				Integer iReg = Integer.valueOf(reg);
				int pc = getPC();
				if (.contains(Integer.valueOf(pc))) {
else if (.size() > 0) {
else if () {
				}
				if (!.contains(iReg)) {
					if (sb != null) {
						UserObject assoc = null;
						if (.getStackDepth() > 0) {
							assoc = (UserObject.getStackItem(0)
									.getUserValue();
						}
						if ((assoc != null) && assoc.isRisky) {
else {
							sb.addStore(regpcassoc);
							if () {
								sb.addLoad(regpc);
							}
						}
else {
					}
				}
else if (seen == IINC) {
				int reg = getRegisterOperand();
				Integer iReg = Integer.valueOf(reg);
				if (!.contains(iReg)) {
					if (sb != null) {
						sb.addLoad(reggetPC());
else {
					}
				}
				int pc = getPC();
				if (.contains(Integer.valueOf(pc))) {
else if (.size() > 0) {
else if () {
				}
				if (!.contains(iReg)) {
					if (sb != null) {
						sb.addStore(regpcnull);
						if () {
							sb.addLoad(regpc);
						}
else {
					}
				}
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 (!.contains(Integer.valueOf(reg))) {
					if (sb != null) {
						sb.addLoad(reggetPC());
else {
						.add(Integer.valueOf(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)) {
						Integer nextPC = Integer.valueOf(getNextPC());
						if (!.contains(nextPC)) {
							if (sb == null) {
								sb = new ScopeBlock(getPC(), target);
								sb.setLoop();
								sb.setGoto();
else {
								sb = new ScopeBlock(getPC(), target);
								sb.setGoto();
							}
						}
else {
								getPC(), target);
						if ((sb != null) && (!sb.isLoop) && !sb.hasChildren()) {
							if (sb.isGoto()) {
								ScopeBlock parent = sb.getParent();
								if (parent != null) {
									parent.removeChild(sb);
								}
								sb = new ScopeBlock(getPC(), target);
else {
								sb.setFinish(target);
							}
else {
							sb = new ScopeBlock(getPC(), target);
						}
					}
else {
					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 pc = getPC();
				int[] offsets = getSwitchOffsets();
				List<Integertargets = new ArrayList<Integer>();
				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());
					lastTarget = nextTarget;
				}
else if ((seen == INVOKEVIRTUAL) || (seen == INVOKEINTERFACE)) {
					 = true;
				}
				uo = new UserObject();
				uo.isRisky = isRiskyMethodCall();
				uo.caller = getCallingObject();
				if (uo.caller != null) {
					if (sb != null) {
						sb.removeByAssoc(uo.caller);
					}
				}
else if ((seen == INVOKESTATIC) || (seen == INVOKESPECIAL)) {
				uo = new UserObject();
				uo.isRisky = isRiskyMethodCall();
else if (seen == MONITORENTER) {
else if (seen == MONITOREXIT) {
				if (.size() > 0) {
				}
			}
			 = (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() {
		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
			int 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(childstart,
						target);
				if (targetBlock != null) {
					return targetBlock;
				}
			}
		}
		return parentBlock;
	}

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 Map<IntegerIntegerloads;
		private Map<IntegerIntegerstores;
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;
			 = null;
			 = null;
			 = null;
			 = null;
		}

returns a string representation of the scope block

Returns:
a string representation
		public String toString() {
			return "Start=" +  + " Finish=" + 
" Loop=" +  + " Loads=" +  + " Stores="
		}

returns the scope blocks parent

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

returns the start of the block

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

returns the end of the block

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

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 ;
		}

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) {
			}
			.put(Integer.valueOf(reg), Integer.valueOf(pc));
			if ( == null) {
			}
			.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) {
					}
					if ( != null) {
					}
				}
			}
		}

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) {
			}
			.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.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;
			}
			.add(newChild);
		}

removes a child from this node

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

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(parentUsedRegs);
				if (.size() > 0) {
					if ( != null) {
						for (Map.Entry<IntegerIntegerentry : 
								.entrySet()) {
							int childUseCount = 0;
							boolean inLoop = false;
							Integer reg = entry.getKey();
							for (ScopeBlock child : ) {
								if (child.usesReg(reg)) {
									if (child.isLoop) {
										inLoop = true;
										break;
									}
									childUseCount++;
								}
							}
							if ((!inLoop) && (childUseCount == 1)) {
								.reportBug(new BugInstance(
										"BAS_BLOATED_ASSIGNMENT_SCOPE",
										NORMAL_PRIORITY)
										.addClass(BloatedAssignmentScope.this)
										.addMethod(BloatedAssignmentScope.this)
										.addSourceLine(
												entry.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) {
else {
					}
				}
				if ( != null) {
					if (. != null) {
else {
					}
				}
				 = null;
				 = null;
			}
		}
	}
	public boolean isRiskyMethodCall() {
			return true;
		}
		String key = clsName + "." + getNameConstantOperand()
	}
	class UserObject {
		boolean isRisky;
	}
New to GrepCode? Check out our FAQ X