Clover coverage report - PMD - 3.9
Coverage timestamp: Tue Dec 19 2006 09:38:44 EST
file stats: LOC: 128   Methods: 4
NCLOC: 93   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
InefficientStringBuffering.java 88.2% 94% 100% 92%
coverage coverage
 1    /**
 2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
 3    */
 4    package net.sourceforge.pmd.rules.strings;
 5   
 6    import net.sourceforge.pmd.AbstractRule;
 7    import net.sourceforge.pmd.ast.ASTAdditiveExpression;
 8    import net.sourceforge.pmd.ast.ASTAllocationExpression;
 9    import net.sourceforge.pmd.ast.ASTArgumentList;
 10    import net.sourceforge.pmd.ast.ASTBlockStatement;
 11    import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
 12    import net.sourceforge.pmd.ast.ASTLiteral;
 13    import net.sourceforge.pmd.ast.ASTName;
 14    import net.sourceforge.pmd.ast.ASTStatementExpression;
 15    import net.sourceforge.pmd.ast.Node;
 16    import net.sourceforge.pmd.ast.SimpleNode;
 17    import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
 18   
 19    import java.util.Iterator;
 20    import java.util.List;
 21   
 22    /*
 23    * How this rule works:
 24    * find additive expressions: +
 25    * check that the addition is between anything other than two literals
 26    * if true and also the parent is StringBuffer constructor or append,
 27    * report a violation.
 28    *
 29    * @author mgriffa
 30    */
 31    public class InefficientStringBuffering extends AbstractRule {
 32   
 33  20 public Object visit(ASTAdditiveExpression node, Object data) {
 34  20 ASTBlockStatement bs = (ASTBlockStatement) node.getFirstParentOfType(ASTBlockStatement.class);
 35  20 if (bs == null) {
 36  1 return data;
 37    }
 38   
 39  19 int immediateLiterals = 0;
 40  19 List nodes = node.findChildrenOfType(ASTLiteral.class);
 41  19 for (Iterator i = nodes.iterator();i.hasNext();) {
 42  22 ASTLiteral literal = (ASTLiteral)i.next();
 43  22 if (literal.jjtGetParent().jjtGetParent().jjtGetParent() instanceof ASTAdditiveExpression) {
 44  21 immediateLiterals++;
 45    }
 46  22 try {
 47  22 Integer.parseInt(literal.getImage());
 48  3 return data;
 49    } catch (NumberFormatException nfe) {
 50    // NFE means new StringBuffer("a" + "b"), want to flag those
 51    }
 52    }
 53   
 54  16 if (immediateLiterals > 1) {
 55  4 return data;
 56    }
 57   
 58    // if literal + public static final, return
 59  12 List nameNodes = node.findChildrenOfType(ASTName.class);
 60  12 for (Iterator i = nameNodes.iterator(); i.hasNext();) {
 61  15 ASTName name = (ASTName)i.next();
 62  15 if (name.getNameDeclaration() instanceof VariableNameDeclaration) {
 63  7 VariableNameDeclaration vnd = (VariableNameDeclaration)name.getNameDeclaration();
 64  7 if (vnd.getAccessNodeParent().isFinal() && vnd.getAccessNodeParent().isStatic()) {
 65  1 return data;
 66    }
 67    }
 68    }
 69   
 70   
 71  11 if (bs.isAllocation()) {
 72  2 if (isAllocatedStringBuffer(node)) {
 73  2 addViolation(data, node);
 74    }
 75  9 } else if (isInStringBufferOperation(node, 6, "append")) {
 76  4 addViolation(data, node);
 77    }
 78  11 return data;
 79    }
 80   
 81  245 protected static boolean isInStringBufferOperation(SimpleNode node, int length, String methodName) {
 82  245 if (!xParentIsStatementExpression(node, length)) {
 83  29 return false;
 84    }
 85  216 ASTStatementExpression s = (ASTStatementExpression) node.getFirstParentOfType(ASTStatementExpression.class);
 86  216 if (s == null) {
 87  0 return false;
 88    }
 89  216 ASTName n = (ASTName)s.getFirstChildOfType(ASTName.class);
 90  216 if (n == null || n.getImage().indexOf(methodName) == -1 || !(n.getNameDeclaration() instanceof VariableNameDeclaration)) {
 91  9 return false;
 92    }
 93   
 94    // TODO having to hand-code this kind of dredging around is ridiculous
 95    // we need something to support this in the framework
 96    // but, "for now" (tm):
 97    // if more than one arg to append(), skip it
 98  207 ASTArgumentList argList = (ASTArgumentList)s.getFirstChildOfType(ASTArgumentList.class);
 99  207 if (argList == null || argList.jjtGetNumChildren() > 1) {
 100  3 return false;
 101    }
 102   
 103  204 return ((VariableNameDeclaration)n.getNameDeclaration()).getTypeImage().equals("StringBuffer");
 104    }
 105   
 106    // TODO move this method to SimpleNode
 107  245 private static boolean xParentIsStatementExpression(SimpleNode node, int length) {
 108  245 Node curr = node;
 109  245 for (int i=0; i<length; i++) {
 110  802 if (node.jjtGetParent() == null) {
 111  0 return false;
 112    }
 113  802 curr = curr.jjtGetParent();
 114    }
 115  245 return curr instanceof ASTStatementExpression;
 116    }
 117   
 118  2 private boolean isAllocatedStringBuffer(ASTAdditiveExpression node) {
 119  2 ASTAllocationExpression ao = (ASTAllocationExpression) node.getFirstParentOfType(ASTAllocationExpression.class);
 120  2 if (ao == null) {
 121  0 return false;
 122    }
 123    // note that the child can be an ArrayDimsAndInits, for example, from java.lang.FloatingDecimal: t = new int[ nWords+wordcount+1 ];
 124  2 ASTClassOrInterfaceType an = (ASTClassOrInterfaceType) ao.getFirstChildOfType(ASTClassOrInterfaceType.class);
 125  2 return an != null && (an.getImage().endsWith("StringBuffer") || an.getImage().endsWith("StringBuilder"));
 126    }
 127    }
 128