edu.umd.cs.findbugs.detect.FindFieldSelfAssignment Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spotbugs Show documentation
Show all versions of spotbugs Show documentation
SpotBugs: Because it's easy!
The newest version!
/*
* 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.Const;
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.CustomUserValue;
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;
@CustomUserValue
public class FindFieldSelfAssignment extends OpcodeStackDetector implements StatelessDetector {
private final BugReporter bugReporter;
private static final boolean DEBUG = SystemProperties.getBoolean("fsa.debug");
private static final int NO_REGISTER = -1;
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 initializedFields = new HashSet<>();
XField possibleOverwrite;
private int parentInstanceLoadFromRegister = NO_REGISTER;
@Override
public void sawOpcode(int seen) {
if (DEBUG) {
System.out.printf("%5d %12s %s%n", getPC(), Const.getOpcodeName(seen), stack);
}
if (seen == Const.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() == Const.PUTFIELD) {
OpcodeStack.Item third = stack.getStackItem(2);
OpcodeStack.Item fourth = stack.getStackItem(3);
XField f2 = third.getXField();
int registerNumber2 = fourth.getRegisterNumber();
int loadedFromRegister2 = fourth.getFieldLoadedFromRegister();
if (f2 != null && f2.equals(getXFieldOperand())
&& ((registerNumber2 >= 0 && registerNumber2 == third.getFieldLoadedFromRegister())
|| (loadedFromRegister2 >= 0 && third.getUserValue() instanceof Integer
&& loadedFromRegister2 == ((Integer) third.getUserValue()).intValue()))
&& !third.sameValue(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 == Const.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;
default:
break;
}
if (seen == Const.GETFIELD) {
XField f = getXFieldOperand();
OpcodeStack.Item top = stack.getStackItem(0);
XField topF = top.getXField();
if (f == null || topF == null) {
return;
}
if ("this$0".equals(topF.getName())) {
parentInstanceLoadFromRegister = top.getFieldLoadedFromRegister();
}
}
}
@Override
public void afterOpcode(int seen) {
super.afterOpcode(seen);
if (seen == Const.GETFIELD && parentInstanceLoadFromRegister > NO_REGISTER) {
OpcodeStack.Item top = stack.getStackItem(0);
top.setUserValue(parentInstanceLoadFromRegister);
parentInstanceLoadFromRegister = NO_REGISTER;
}
}
}