Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * fb-contrib - Auxiliary detectors for Java programs
   * Copyright (C) 2005-2013 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.Set;
 
 import  org.apache.bcel.Constants;
 import  org.apache.bcel.classfile.Code;
 import  org.apache.bcel.classfile.Method;
 
 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 for loops that iterate over a java.util.List using an integer index, and get, rather than using an Iterator. An iterator may perform better depending List implementation, but more importantly will allow the code to be converted to other collections type.
 
 public class ListIndexedIterating extends BytecodeScanningDetector
 {
 	enum State {SAW_NOTHING, SAW_IINC}
 	enum LoopState {LOOP_NOT_STARTED, LOOP_INDEX_LOADED_FOR_TEST, LOOP_IN_BODY, LOOP_IN_BODY_WITH_GET}
 	enum Stage {FIND_LOOP_STAGE, FIND_BUG_STAGE}
 	
 	private BugReporter bugReporter;
 	private OpcodeStack stack;
 	private Stage stage;
 	private State state;
 	private int loopReg;
 	private boolean sawListSize;

constructs a LII detector given the reporter to report bugs on

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

overrides the interface to create and clear the stack and loops tracker

Parameters:
classContext the context object for the currently parsed class
 
 	public void visitClassContext(ClassContext classContext) {
 		try {
 			 = new OpcodeStack();
 			super.visitClassContext(classContext);
 		} finally {
 			 = null;
 			 = null;
 		}
 	}

looks for methods that contain a IINC and GOTO or GOTO_W opcodes

Parameters:
method the context object of the current method
Returns:
if the class uses synchronization
 
 	public boolean prescreen(Method method) {
 		BitSet bytecodeSet = getClassContext().getBytecodeSet(method);
 		return (bytecodeSet != null) && (bytecodeSet.get(Constants.IINC)) && (bytecodeSet.get(Constants.GOTO) || bytecodeSet.get(Constants.GOTO_W));
 	}

overrides the visitor to reset the opcode stack

Parameters:
obj the code object for the currently parsed Code
 
 	public void visitCode(final Code obj) {
 		Method m = getMethod();
		if (prescreen(m)) {
			 = false;
			.resetForMethodEntry(this);
			super.visitCode(obj);
			if () {
				.resetForMethodEntry(this);
				super.visitCode(obj);
			}
		}
	}

overrides the visitor to find list indexed iterating

Parameters:
seen the currently parsed opcode
	public void sawOpcode(final int seen) {
		else
	}

the first pass of the method opcode to collet for loops information

Parameters:
seen the currently parsed opcode
	private void sawOpcodeLoop(final int seen) {
		try {
			.mergeJumps(this);
			switch () {
					if ((seen == IINC) && (getIntConstant() == 1)) {
					}
				break;
				case :
					if ((seen == GOTO) || (seen == GOTO_W)) {
						int branchTarget = getBranchTarget();
						int pc = getPC();
						if (branchTarget < pc) {
							.add(new ForLoopbranchTargetpc));
						}
					}
				break;
			}
			if ((seen == INVOKEINTERFACE) 
			 &&  "java/util/List".equals(getClassConstantOperand())
			 &&  "()I".equals(getSigConstantOperand())) {
				 = true;
			}						
finally {
			.sawOpcode(thisseen);
		}
	}

the second pass to look for get methods on the for loop reg

Parameters:
seen the currently parsed opcode
	private void sawOpcodeBug(final int seen) {
		try {		
			.mergeJumps(this);
			while (it.hasNext()) {
				ForLoop fl = it.next();
				switch (fl.getLoopState()) {
						if (getPC() == fl.getLoopStart()) {
							if ((seen == ILOAD) || ((seen >= ILOAD_0) && (seen <= ILOAD_3))) {
								if (getReg(seen, ILOAD, ILOAD_0) == fl.getLoopReg()) {
									continue;
								}
							}
							it.remove();
						}			
					break;
						if (getPC() >= fl.getLoopEnd()) {
							it.remove();
							continue;
						}
						if (seen == IF_ICMPGE) {
							if (.getStackDepth() > 1) {
								OpcodeStack.Item itm = .getStackItem(0);
								if (itm.getConstant() != null) {
									it.remove();
									continue;
								}
							}
							int branchTarget = getBranchTarget();
							if ((branchTarget >= (fl.getLoopEnd() + 3)) && (branchTarget <= (fl.getLoopEnd() + 5))) {
								continue;
							}
						}
					break;
						if ((getPC() == fl.getLoopEnd()) && (fl.getLoopState() == .)) {
							.reportBug(new BugInstance( this"LII_LIST_INDEXED_ITERATING", NORMAL_PRIORITY )
									.addClass(this)
									.addMethod(this)
									.addSourceLineRange(thisfl.getLoopStart(), fl.getLoopEnd()));
							it.remove();
						}
						if (getPC() > fl.getLoopEnd()) {
							it.remove();
						}
						if ((seen == ILOAD) || ((seen >= ILOAD_0) && (seen <= ILOAD_3))) {
							 = getReg(seen, ILOAD, ILOAD_0);
							if ( == fl.getLoopReg())
else if (fl.getLoopRegLoaded()) {
							boolean sawGet = ((seen == INVOKEINTERFACE) 
									 		&&  "java/util/List".equals(getClassConstantOperand())
									 		&&  "(I)Ljava/lang/Object;".equals(getSigConstantOperand()));
							if (!sawGet) {
								it.remove();
else {
								if (.getStackDepth() > 1) {
									OpcodeStack.Item itm = .getStackItem(0);
									if (!itm.couldBeZero())
										it.remove();
									else {
										itm = .getStackItem(1);
										if (fl.isSecondItem(itm))
											it.remove();
									}
								}
							}
						}
					break;
				}
			}
finally {
			.sawOpcode(thisseen);
		}
	}

get the register operand from the passed in opcode

Parameters:
seen the currently parsed opcode
generalOp the standard non numbered operand
zeroOp the base opcode from which to calculate the register
Returns:
the register operand for the instruction
	private int getReg(final int seenfinal int generalOpfinal int zeroOp) {
		if (seen == generalOp)
		return seen - zeroOp;
	}

represents a for loop
	static class ForLoop
	{
		private int loopStart;
		private int loopEnd;
		private int loopReg;
		private boolean loopRegLoaded;
		private OpcodeStack.Item loopCollectionItem;

constructs a for loop information block

Parameters:
start the start of the for loop
end the end of the for loop
reg the loop register
		public ForLoopfinal int startfinal int endfinal int reg) {
			 = start;
			 = end;
			 = reg;
			 = false;
			loopCollectionItem = null;
		}

get the start pc of the loop

Returns:
the start pc of the loop
		public int getLoopStart() {
			return ;
		}

get the end pc of the loop

Returns:
the end pc of the loop
		public int getLoopEnd() {
			return ;
		}

get the loop register

Returns:
the loop register
		public int getLoopReg() {
			return ;
		}

sets the current state of the for loop

Parameters:
state the new state
		public void setLoopState(final LoopState state) {
			 = state;
		}

get the current phase of the for loop

Returns:
the current state
		public LoopState getLoopState() {
			return ;
		}

mark that the loop register has been loaded with an iload instruction

Parameters:
loaded the flag of whether the loop register is loaded
		public void setLoopRegLoaded(final boolean loaded) {
			 = loaded;
		}

returns whether the loop register is on the top of the stack

Returns:
whether the loop register is on the top of the stack
		public boolean getLoopRegLoaded() {
		}

returns whether this is the second time the loop register is found

Parameters:
itm the item on the stack
Returns:
whether this is the second time the loop register is found
		public boolean isSecondItem(OpcodeStack.Item itm) {
			if (loopCollectionItem == null) {
				loopCollectionItem = itm;
				return false;
			}
			int seenReg = loopCollectionItem.getRegisterNumber();
			if (seenReg >= 0) {
				if (itm.getXField() != null)
					return true;
				int newReg = itm.getRegisterNumber();
				if ((newReg >= 0) && (seenReg != newReg))
					return true;
else {
				XField seenField = loopCollectionItem.getXField();
				if (seenField != null) {
					if (itm.getRegisterNumber() >= 0)
						return true;
					XField newField = itm.getXField();
					if ((newField != null) && (!newField.getName().equals(seenField.getName())))
						return true;
				}
			}
			loopCollectionItem = itm;
			return false;
		}
	}
New to GrepCode? Check out our FAQ X