package quickfix;
import static edu.umd.cs.findbugs.plugin.eclipse.quickfix.util.ASTUtil.getASTNode;
import static util.TraversalUtil.backtrackToBlock;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
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 edu.umd.cs.findbugs.plugin.eclipse.quickfix.util.ASTUtil;
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.InfixExpression.Operator;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
public class ArrayToStringResolution extends BugResolution {
@Override
protected boolean resolveBindings() {
return true;
}
@SuppressWarnings("unchecked")
@Override
protected void repairBug(ASTRewrite rewrite, CompilationUnit workingUnit, BugInstance bug) throws BugResolutionException {
ASTNode node = getASTNode(workingUnit, bug.getPrimarySourceLineAnnotation());
node = backtrackToBlock(node);
ArrayToStringVisitor atsFinder = new ArrayToStringVisitor();
node.accept(atsFinder);
AST ast = node.getAST();
for (Expression arr : atsFinder.arrayExpressionsToWrap) {
MethodInvocation wrappedExpression = ast.newMethodInvocation();
wrappedExpression.setExpression(ast.newSimpleName("Arrays"));
wrappedExpression.setName(ast.newSimpleName("toString"));
wrappedExpression.arguments().add(rewrite.createMoveTarget(arr));
rewrite.replace(arr, wrappedExpression, null);
}
ASTUtil.addImports(rewrite, workingUnit, "java.util.Arrays");
}
private static class ArrayToStringVisitor extends ASTVisitor {
public List<Expression> arrayExpressionsToWrap = new ArrayList<>();
private static Set<String> methodsToCheck = new HashSet<>();
static {
methodsToCheck.add("java.io.PrintStream.println");
methodsToCheck.add("java.io.PrintStream.print");
methodsToCheck.add("java.io.PrintStream.printf");
methodsToCheck.add("java.lang.StringBuilder.append");
methodsToCheck.add("java.lang.StringBuffer.append");
methodsToCheck.add("java.lang.String.format");
methodsToCheck.add("java.util.Formatter.format");
}
@SuppressWarnings("unchecked")
@Override
public boolean visit(MethodInvocation node) {
// for stringBuilder.append(array); and System.out.println(one);
if (methodsToCheck.contains(asQualifiedString(node)))
{
List<Expression> arguments = node.arguments();
for (Expression argument : arguments) {
checkOperand(argument);
}
}
return true;
}
private static String asQualifiedString(MethodInvocation node) {
return String.format("%s.%s",
node.getExpression().resolveTypeBinding().getQualifiedName(),
node.getName().getIdentifier());
}
@SuppressWarnings("unchecked")
@Override
public boolean visit(InfixExpression node) {
// for "Hello" + array + ':' + otherArray
if (node.getOperator() == Operator.PLUS &&
"java.lang.String".equals(node.resolveTypeBinding().getQualifiedName())) {
checkOperand(node.getLeftOperand());
checkOperand(node.getRightOperand());
List<Expression> extendedOps = node.extendedOperands();
for (Expression operand : extendedOps) {
checkOperand(operand);
}
}
return true;
}
private void checkOperand(Expression operand) {
if (operand.resolveTypeBinding().isArray()) {
arrayExpressionsToWrap.add(operand);
}
}
}
}