Clover coverage report - PMD - 3.9 Coverage timestamp: Tue Dec 19 2006 09:38:44 EST FRAMES NO FRAMES |
file stats: | LOC: | 90 |  | Methods: | 3
| NCLOC: | 49 |  | Classes: | 1
Source file | Conditionals | Statements | Methods | TOTAL
UseStringBufferLength.java | 85.7% | 91.3% | 100% | 90% |

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 |  | }