Clover coverage report - PMD - 3.7
Coverage timestamp: Wed May 31 2006 09:25:59 EDT
file stats: LOC: 90   Methods: 3
NCLOC: 49   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
UseStringBufferLength.java 85.7% 91.3% 100% 90%
coverage coverage
 1    package net.sourceforge.pmd.rules.strings;
 2   
 3    import net.sourceforge.pmd.AbstractRule;
 4    import net.sourceforge.pmd.ast.ASTCompilationUnit;
 5    import net.sourceforge.pmd.ast.ASTLiteral;
 6    import net.sourceforge.pmd.ast.ASTName;
 7    import net.sourceforge.pmd.ast.SimpleNode;
 8    import net.sourceforge.pmd.symboltable.NameDeclaration;
 9    import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
 10   
 11    import java.util.HashSet;
 12    import java.util.List;
 13    import java.util.Set;
 14   
 15   
 16    /**
 17    * This rule finds places where StringBuffer.toString() is called just to see if
 18    * the string is 0 length by either using .equals("") or toString().size()
 19    * <p/>
 20    * <pre>
 21    * StringBuffer sb = new StringBuffer(&quot;some string&quot;);
 22    * if (sb.toString().equals(&quot;&quot;)) {
 23    * // this is wrong
 24    * }
 25    * if (sb.length() == 0) {
 26    * // this is right
 27    * }
 28    * </pre>
 29    *
 30    * @author acaplan
 31    */
 32    public class UseStringBufferLength extends AbstractRule {
 33   
 34    // FIXME Need to remove this somehow.
 35    /*
 36    Specifically, we need a symbol tree that can be traversed downwards, so that instead
 37    of visiting each name and then visiting the declaration for that name, we should visit all
 38    the declarations and check their usages.
 39    With that in place, this rule would be reduced to:
 40    - find all StringBuffer declarations
 41    - check each usage
 42    - flag those that involve variable.toString()
 43    */
 44    private Set alreadySeen = new HashSet();
 45   
 46  5 public Object visit(ASTCompilationUnit acu, Object data) {
 47  5 alreadySeen.clear();
 48  5 return super.visit(acu, data);
 49    }
 50   
 51  14 public Object visit(ASTName decl, Object data) {
 52  14 if (!decl.getImage().endsWith("toString")) {
 53  10 return data;
 54    }
 55  4 NameDeclaration nd = decl.getNameDeclaration();
 56  4 if (!(nd instanceof VariableNameDeclaration)) {
 57  0 return data;
 58    }
 59  4 VariableNameDeclaration vnd = (VariableNameDeclaration) nd;
 60  4 if (!vnd.getTypeImage().equals("StringBuffer") || alreadySeen.contains(vnd)) {
 61  0 return data;
 62    }
 63  4 alreadySeen.add(vnd);
 64   
 65  4 SimpleNode parent = (SimpleNode) decl.jjtGetParent().jjtGetParent();
 66  4 for (int jx = 0; jx < parent.jjtGetNumChildren(); jx++) {
 67  16 SimpleNode achild = (SimpleNode) parent.jjtGetChild(jx);
 68  16 if (isViolation(parent, achild)) {
 69  2 addViolation(data, decl);
 70    }
 71    }
 72   
 73  4 return data;
 74    }
 75   
 76    /**
 77    * Check the given node if it calls either .equals or .size we need to check the target
 78    */
 79  16 private boolean isViolation(SimpleNode parent, SimpleNode achild) {
 80  16 if ("equals".equals(achild.getImage())) {
 81  3 List literals = parent.findChildrenOfType(ASTLiteral.class);
 82  3 return (!literals.isEmpty() && "\"\"".equals(((SimpleNode) literals.get(0)).getImage()));
 83  13 } else if ("length".equals(achild.getImage())) {
 84  1 return true;
 85    }
 86  12 return false;
 87    }
 88   
 89   
 90    }