package quickfix; import static edu.umd.cs.findbugs.plugin.eclipse.quickfix.util.ASTUtil.addStaticImports; import static edu.umd.cs.findbugs.plugin.eclipse.quickfix.util.ASTUtil.getASTNode; 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.CustomLabelVisitor; import edu.umd.cs.findbugs.plugin.eclipse.quickfix.exception.BugResolutionException; import org.eclipse.jdt.core.dom.AST; 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.rewrite.ASTRewrite; public class UseAssertEqualsResolution extends BugResolution { @Override protected boolean resolveBindings() { return true; } @Override protected ASTVisitor getCustomLabelVisitor() { return new UAEVisitor(); } @Override protected void repairBug(ASTRewrite rewrite, CompilationUnit workingUnit, BugInstance bug) throws BugResolutionException { ASTNode node = getASTNode(workingUnit, bug.getPrimarySourceLineAnnotation()); UAEVisitor visitor = new UAEVisitor(); node.accept(visitor); MethodInvocation badMethodInvocation = visitor.badMethodInvocation; MethodInvocation fixedMethodInvocation = createFixedMethodInvocation(rewrite, visitor); rewrite.replace(badMethodInvocation, fixedMethodInvocation, null); if (visitor.usedStaticAssert) { //this static import may not exist. However, if it wasn't done statically, addStaticImports(rewrite, workingUnit, "org.junit.Assert.assertEquals"); // we know the Assert import will have to exist } } private MethodInvocation createFixedMethodInvocation(ASTRewrite rewrite, UAEVisitor visitor) { AST ast = rewrite.getAST(); MethodInvocation retVal = ast.newMethodInvocation(); retVal.setName(ast.newSimpleName("assertEquals")); if (!visitor.usedStaticAssert) { retVal.setExpression(ast.newSimpleName("Assert")); } @SuppressWarnings("unchecked") List<Expression> arguments = retVal.arguments(); //known to be of type Expression arguments.add((Expression) rewrite.createCopyTarget(visitor.expectedExpression)); arguments.add((Expression) rewrite.createCopyTarget(visitor.actualExpression)); return retVal; } private static class UAEVisitor extends ASTVisitor implements CustomLabelVisitor { public boolean usedStaticAssert; public MethodInvocation badMethodInvocation; public Expression actualExpression; public Expression expectedExpression; @Override public boolean visit(MethodInvocation node) { if (badMethodInvocation != null) { return false; } if ("assertTrue".equals(node.getName().getIdentifier())) { if (this.findExpectedAndActual(node.arguments().get(0))) { // if expression is not null, it was called Assert.assertTrue (most likely) this.usedStaticAssert = node.getExpression() == null; this.badMethodInvocation = node; } } return true; } //returns true if it was successful private boolean findExpectedAndActual(Object comparisonWithEquals) { if (comparisonWithEquals instanceof InfixExpression) { // == return handleInfixEquals((InfixExpression) comparisonWithEquals); } else if (comparisonWithEquals instanceof MethodInvocation) { // .equals return handleDotEquals((MethodInvocation) comparisonWithEquals); } //not sure what this could be return false; } private boolean handleDotEquals(MethodInvocation comparisonWithEquals) { if (!"equals".equals(comparisonWithEquals.getName().getIdentifier())) { return false; } bucketIntoExpectedActual(comparisonWithEquals.getExpression(), (Expression) comparisonWithEquals.arguments().get(0)); return true; } private boolean handleInfixEquals(InfixExpression comparisonWithEquals) { if (comparisonWithEquals.getOperator() != InfixExpression.Operator.EQUALS) { return false; } bucketIntoExpectedActual(comparisonWithEquals.getLeftOperand(), comparisonWithEquals.getRightOperand()); return true; } private void bucketIntoExpectedActual(Expression left, Expression right) { //put the right argument in the expected category if it is a constant if (right.resolveConstantExpressionValue() != null && left.resolveConstantExpressionValue() == null) { actualExpression = left; expectedExpression = right; } else { expectedExpression = left; actualExpression = right; } } @Override public String getLabelReplacement() { return String.format("assertEquals(%s, %s)", expectedExpression.toString(), actualExpression.toString()); } } }