package quickfix;
import static edu.umd.cs.findbugs.plugin.eclipse.quickfix.util.ASTUtil.getASTNode;
import java.util.ArrayList;
import java.util.List;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.plugin.eclipse.quickfix.BugResolution;
import edu.umd.cs.findbugs.plugin.eclipse.quickfix.exception.BugResolutionException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.PrefixExpression;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import util.TraversalUtil;
public class ChangeEnumEqualsResolution extends BugResolution {
@Override
protected boolean resolveBindings() {
return true; // we need this to detect
}
@Override
protected void repairBug(ASTRewrite rewrite, CompilationUnit workingUnit, BugInstance bug) throws BugResolutionException {
ASTNode node = getASTNode(workingUnit, bug.getPrimarySourceLineAnnotation());
node = TraversalUtil.backtrackToBlock(node);
EnumEqualsVisitor visitor = new EnumEqualsVisitor();
node.accept(visitor);
for (ResolutionBundle bundle : visitor.resolutionBundles) {
InfixExpression newEquals = rewrite.getAST().newInfixExpression();
if (bundle.wasNegated) {
newEquals.setOperator(InfixExpression.Operator.NOT_EQUALS);
} else {
newEquals.setOperator(InfixExpression.Operator.EQUALS);
}
newEquals.setLeftOperand((Expression) rewrite.createCopyTarget(bundle.thisEnum));
newEquals.setRightOperand((Expression) rewrite.createCopyTarget(bundle.thatEnum));
rewrite.replace(bundle.badEqualsInvocation, newEquals, null);
}
}
private static class ResolutionBundle {
public boolean wasNegated;
public Expression badEqualsInvocation;
public Expression thisEnum;
public Expression thatEnum;
public ResolutionBundle(MethodInvocation badEqualsInvocation, Expression thisEnum, Expression thatEnum) {
this.badEqualsInvocation = badEqualsInvocation;
this.thisEnum = thisEnum;
this.thatEnum = thatEnum;
}
}
private static class EnumEqualsVisitor extends ASTVisitor {
public List<ResolutionBundle> resolutionBundles = new ArrayList<>();
@SuppressWarnings("unchecked")
@Override
public boolean visit(MethodInvocation node) {
List<Expression> arguments = node.arguments();
if ("equals".equals(node.getName().getIdentifier()) && arguments.size() == 1) {
Expression messageReciever = node.getExpression();
if (messageReciever.resolveTypeBinding().isEnum()) {
ResolutionBundle resolutionBundle = new ResolutionBundle(node, messageReciever, arguments.get(0));
checkNegated(node, resolutionBundle);
resolutionBundles.add(resolutionBundle);
}
}
return true;
}
private void checkNegated(MethodInvocation node, ResolutionBundle resolutionBundle) {
PrefixExpression negatedExpression = TraversalUtil.findClosestAncestor(node, PrefixExpression.class);
if (negatedExpression == null) {
return;
}
if (negatedExpression.getOperator().equals(PrefixExpression.Operator.NOT)) {
resolutionBundle.wasNegated = true;
resolutionBundle.badEqualsInvocation = negatedExpression;
}
}
}
}