package quickfix; 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.ArrayCreation; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; public class InefficientToArrayResolution extends BugResolution { @Override protected boolean resolveBindings() { return true; } @Override protected ASTVisitor getCustomLabelVisitor() { return new ITAVisitor(); } @Override protected void repairBug(ASTRewrite rewrite, CompilationUnit workingUnit, BugInstance bug) throws BugResolutionException { ASTNode node = getASTNode(workingUnit, bug.getPrimarySourceLineAnnotation()); ITAVisitor visitor = new ITAVisitor(); node.accept(visitor); if (visitor.collectionTurnedToArray != null) { ASTNode sizeBasedInitialization = createSizedBasedInitialization(rewrite, visitor); rewrite.replace(visitor.dimensionInitializerToReplace, sizeBasedInitialization, null); } } private MethodInvocation createSizedBasedInitialization(ASTRewrite rewrite, ITAVisitor visitor) { AST ast = rewrite.getAST(); MethodInvocation sizeBasedInitialization = ast.newMethodInvocation(); sizeBasedInitialization.setExpression((Expression) rewrite.createCopyTarget(visitor.collectionTurnedToArray)); sizeBasedInitialization.setName(ast.newSimpleName("size")); return sizeBasedInitialization; } private static class ITAVisitor extends ASTVisitor implements CustomLabelVisitor { public Expression collectionTurnedToArray = null; public Expression dimensionInitializerToReplace = null; public String arrayTypeName = null; // for label purposes @Override public boolean visit(ArrayCreation node) { if (dimensionInitializerToReplace != null) { return false; } @SuppressWarnings("unchecked") List<Expression> dimensions = node.dimensions(); if (dimensions.size() != 1) { return true; } Expression initializer = dimensions.get(0); if (Integer.valueOf(0).equals(initializer.resolveConstantExpressionValue())) { try { collectionTurnedToArray = findCollection(node); } catch (NotPartOfToArrayMethodInvocationException e) { // bail out, we haven't found a toArray call return true; } dimensionInitializerToReplace = initializer; arrayTypeName = findArrayTypeName(node); return false; } return true; } private String findArrayTypeName(ArrayCreation node) { return node.getType().getElementType().toString(); } private Expression findCollection(ArrayCreation node) throws NotPartOfToArrayMethodInvocationException { ASTNode parent = node.getParent(); if (parent instanceof MethodInvocation) { MethodInvocation parentMethodInvocation = (MethodInvocation) parent; if ("toArray".equals(parentMethodInvocation.getName().getIdentifier())) { return parentMethodInvocation.getExpression(); } } throw new NotPartOfToArrayMethodInvocationException(); } @Override public String getLabelReplacement() { return String.format("new %s[%s.size()]", arrayTypeName, collectionTurnedToArray.toString()); } } private static class NotPartOfToArrayMethodInvocationException extends Exception { private static final long serialVersionUID = -5779852902622201169L; } }