Clover coverage report - PMD - 3.7
Coverage timestamp: Wed May 31 2006 09:25:59 EDT
file stats: LOC: 129   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 (isInStringBufferAppend(node, 6)) {
 76  4 addViolation(data, node);
 77    }
 78  11 return data;
 79    }
 80   
 81  235 protected static boolean isInStringBufferAppend(SimpleNode node, int length) {
 82  235 if (!xParentIsStatementExpression(node, length)) {
 83  29 return false;
 84    }
 85  206 ASTStatementExpression s = (ASTStatementExpression) node.getFirstParentOfType(ASTStatementExpression.class);
 86  206 if (s == null) {
 87  0 return false;
 88    }
 89  206 ASTName n = (ASTName)s.getFirstChildOfType(ASTName.class);
 90   
 91  206 if (n == null || n.getImage().indexOf("append") == -1 || !(n.getNameDeclaration() instanceof VariableNameDeclaration)) {
 92  5 return false;
 93    }
 94   
 95    // TODO having to hand-code this kind of dredging around is ridiculous
 96    // we need something to support this in the framework
 97    // but, "for now" (tm):
 98    // if more than one arg to append(), skip it
 99  201 ASTArgumentList argList = (ASTArgumentList)s.getFirstChildOfType(ASTArgumentList.class);
 100  201 if (argList == null || argList.jjtGetNumChildren() > 1) {
 101  1 return false;
 102    }
 103   
 104  200 return ((VariableNameDeclaration)n.getNameDeclaration()).getTypeImage().equals("StringBuffer");
 105    }
 106   
 107    // TODO move this method to SimpleNode
 108  235 private static boolean xParentIsStatementExpression(SimpleNode node, int length) {
 109  235 Node curr = node;
 110  235 for (int i=0; i<length; i++) {
 111  772 if (node.jjtGetParent() == null) {
 112  0 return false;
 113    }
 114  772 curr = curr.jjtGetParent();
 115    }
 116  235 return curr instanceof ASTStatementExpression;
 117    }
 118   
 119  2 private boolean isAllocatedStringBuffer(ASTAdditiveExpression node) {
 120  2 ASTAllocationExpression ao = (ASTAllocationExpression) node.getFirstParentOfType(ASTAllocationExpression.class);
 121  2 if (ao == null) {
 122  0 return false;
 123    }
 124    // note that the child can be an ArrayDimsAndInits, for example, from java.lang.FloatingDecimal: t = new int[ nWords+wordcount+1 ];
 125  2 ASTClassOrInterfaceType an = (ASTClassOrInterfaceType) ao.getFirstChildOfType(ASTClassOrInterfaceType.class);
 126  2 return an != null && (an.getImage().endsWith("StringBuffer") || an.getImage().endsWith("StringBuilder"));
 127    }
 128    }
 129