/* * FindBugs - Find bugs in Java programs * Copyright (C) 2005, University of Maryland * * 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 edu.umd.cs.findbugs.detect; import org.apache.bcel.classfile.Code; import org.apache.bcel.classfile.LineNumberTable; import edu.umd.cs.findbugs.BugInstance; import edu.umd.cs.findbugs.BugReporter; import edu.umd.cs.findbugs.OpcodeStack; import edu.umd.cs.findbugs.StatelessDetector; import edu.umd.cs.findbugs.bcel.OpcodeStackDetector; public class FindBadForLoop extends OpcodeStackDetector implements StatelessDetector { BugReporter bugReporter; public FindBadForLoop(BugReporter bugReporter) { this.bugReporter = bugReporter; } LineNumberTable lineNumbers; @Override public void visit(Code obj) { lastRegStore = -1; lineNumbers = obj.getLineNumberTable(); super.visit(obj); } int lastRegStore; @Override public void sawOpcode(int seen) { if (seen == ISTORE || seen == ISTORE_0 || seen == ISTORE_1 || seen == ISTORE_2 || seen == ISTORE_3) lastRegStore = getRegisterOperand(); if (lineNumbers != null && stack.getStackDepth() >= 2 && (seen == IF_ICMPGE || seen == IF_ICMPGT || seen == IF_ICMPLT || seen == IF_ICMPLE || seen == IF_ICMPNE || seen == IF_ICMPEQ)) { OpcodeStack.Item item0 = stack.getStackItem(0); OpcodeStack.Item item1 = stack.getStackItem(1); int r0 = item0.getRegisterNumber(); int r1 = item1.getRegisterNumber(); int rMin = Math.min(r0, r1); int rMax = Math.max(r0, r1); int branchTarget = getBranchTarget(); if (rMin == -1 && rMax > 0 && rMax == lastRegStore && branchTarget - 6 > getPC()) { int beforeTarget = getCodeByte(branchTarget - 3); int beforeGoto = getCodeByte(branchTarget - 6); if (beforeTarget == GOTO && beforeGoto == IINC) { int offset1 = (byte) getCodeByte(branchTarget - 2); int offset2 = getCodeByte(branchTarget - 1); int offset = offset1 << 8 | offset2; int backTarget = branchTarget - 3 + offset; int reg = getCodeByte(branchTarget - 5); int testLineNumber = lineNumbers.getSourceLine(getPC()); int incLineNumber = lineNumbers.getSourceLine(branchTarget - 6); int beforeIncLineNumber = lineNumbers.getSourceLine(branchTarget - 7); if (backTarget < getPC() && getPC() - 8 < backTarget && reg != rMax && incLineNumber < testLineNumber + 3 && beforeIncLineNumber > incLineNumber) { bugReporter.reportBug(new BugInstance(this, "QF_QUESTIONABLE_FOR_LOOP", NORMAL_PRIORITY) .addClassAndMethod(this).addSourceLine(this)); } } } } } }