/* * FindBugs - Find bugs in Java programs * Copyright (C) 2003-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 java.util.HashSet; import java.util.Set; import org.apache.bcel.classfile.Code; import edu.umd.cs.findbugs.BugInstance; import edu.umd.cs.findbugs.BugReporter; import edu.umd.cs.findbugs.LocalVariableAnnotation; import edu.umd.cs.findbugs.OpcodeStack; import edu.umd.cs.findbugs.OpcodeStack.Item; import edu.umd.cs.findbugs.Priorities; import edu.umd.cs.findbugs.StatelessDetector; import edu.umd.cs.findbugs.SystemProperties; import edu.umd.cs.findbugs.ba.XField; import edu.umd.cs.findbugs.bcel.OpcodeStackDetector; public class FindFieldSelfAssignment extends OpcodeStackDetector implements StatelessDetector { private final BugReporter bugReporter; private static final boolean DEBUG = SystemProperties.getBoolean("fsa.debug"); int state; public FindFieldSelfAssignment(BugReporter bugReporter) { this.bugReporter = bugReporter; } @Override public void visit(Code obj) { state = 0; lastMethodCall = -1; if (DEBUG) System.out.println(getXMethod()); super.visit(obj); possibleOverwrite = null; if (DEBUG) System.out.println(); initializedFields.clear(); } int register; int lastMethodCall; Set<String> initializedFields = new HashSet<String>(); XField possibleOverwrite; @Override public void sawOpcode(int seen) { if (DEBUG) System.out.printf("%5d %12s %s%n", getPC(), OPCODE_NAMES[seen],stack); if (seen == PUTFIELD) { OpcodeStack.Item top = stack.getStackItem(0); OpcodeStack.Item next = stack.getStackItem(1); if (possibleOverwrite != null && possibleOverwrite.equals(getXFieldOperand())) { bugReporter.reportBug(new BugInstance(this, "SA_FIELD_SELF_ASSIGNMENT", Priorities.HIGH_PRIORITY).addClassAndMethod(this) .addReferencedField(this).addSourceLine(this)); } possibleOverwrite = null; if (stack.getStackDepth() >= 4 && getNextOpcode() == PUTFIELD) { OpcodeStack.Item third = stack.getStackItem(2); OpcodeStack.Item fourth = stack.getStackItem(3); XField f2 = third.getXField(); int registerNumber2 = fourth.getRegisterNumber(); if (f2 != null && f2.equals(getXFieldOperand()) && registerNumber2 >= 0 && registerNumber2 == third.getFieldLoadedFromRegister() && !third.equals(top) && (third.getPC() == -1 || third.getPC() > lastMethodCall)) { possibleOverwrite = f2; } } XField f = top.getXField(); int registerNumber = next.getRegisterNumber(); if (f != null && f.equals(getXFieldOperand()) && registerNumber >= 0 && registerNumber == top.getFieldLoadedFromRegister() && (top.getPC() == -1 || top.getPC() > lastMethodCall)) { int priority = NORMAL_PRIORITY; LocalVariableAnnotation possibleMatch = LocalVariableAnnotation.findMatchingIgnoredParameter(getClassContext(), getMethod(), getNameConstantOperand(), getSigConstantOperand()); if (possibleMatch != null) priority--; else possibleMatch = LocalVariableAnnotation.findUniqueBestMatchingParameter(getClassContext(), getMethod(), getNameConstantOperand(), getSigConstantOperand()); if (possibleMatch == null) { String signature = stack.getLVValue(registerNumber).getSignature(); for (int i = 0; i < stack.getNumLocalValues(); i++) if (i != register) { Item lvValue = stack.getLVValue(i); if (lvValue != null && lvValue.getSignature().equals(signature)) { priority--; break; } } } bugReporter.reportBug(new BugInstance(this, "SA_FIELD_SELF_ASSIGNMENT", priority).addClassAndMethod(this) .addReferencedField(this).addOptionalAnnotation(possibleMatch).addSourceLine(this)); } } else possibleOverwrite = null; if (isMethodCall()) lastMethodCall = getPC(); switch (state) { case 0: if (seen == DUP) state = 6; break; case 6: if (isRegisterStore()) { state = 7; register = getRegisterOperand(); } else state = 0; break; case 7: if (isRegisterStore() && register == getRegisterOperand()) { bugReporter.reportBug(new BugInstance(this, "SA_LOCAL_DOUBLE_ASSIGNMENT", NORMAL_PRIORITY) .addClassAndMethod(this) .add(LocalVariableAnnotation.getLocalVariableAnnotation(getMethod(), register, getPC(), getPC() - 1)) .addSourceLine(this)); } state = 0; break; } } }