/*
* 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.StatelessDetector;
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;
int state;
public FindFieldSelfAssignment(BugReporter bugReporter) {
this.bugReporter = bugReporter;
}
@Override
public void visit(Code obj) {
// System.out.println(getFullyQualifiedMethodName());
state = 0;
super.visit(obj);
initializedFields.clear();
}
int register;
Set<String> initializedFields = new HashSet<String>();
@Override
public void sawOpcode(int seen) {
// 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);
XField f = top.getXField();
int registerNumber = next.getRegisterNumber();
if (f != null && f.equals(getXFieldOperand()) && registerNumber >= 0
&& registerNumber == top.getFieldLoadedFromRegister()) {
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));
}
}
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;
}
}
}