KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > pmd > rules > strings > InefficientStringBuffering


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 JavaDoc;
20 import java.util.List JavaDoc;
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     public Object JavaDoc visit(ASTAdditiveExpression node, Object JavaDoc data) {
34         ASTBlockStatement bs = (ASTBlockStatement) node.getFirstParentOfType(ASTBlockStatement.class);
35         if (bs == null) {
36             return data;
37         }
38
39         int immediateLiterals = 0;
40         List nodes = node.findChildrenOfType(ASTLiteral.class);
41         for (Iterator JavaDoc i = nodes.iterator();i.hasNext();) {
42             ASTLiteral literal = (ASTLiteral)i.next();
43             if (literal.jjtGetParent().jjtGetParent().jjtGetParent() instanceof ASTAdditiveExpression) {
44                 immediateLiterals++;
45             }
46             try {
47                 Integer.parseInt(literal.getImage());
48                 return data;
49             } catch (NumberFormatException JavaDoc nfe) {
50                 // NFE means new StringBuffer("a" + "b"), want to flag those
51
}
52         }
53
54         if (immediateLiterals > 1) {
55             return data;
56         }
57
58         // if literal + public static final, return
59
List nameNodes = node.findChildrenOfType(ASTName.class);
60         for (Iterator JavaDoc i = nameNodes.iterator(); i.hasNext();) {
61             ASTName name = (ASTName)i.next();
62             if (name.getNameDeclaration() instanceof VariableNameDeclaration) {
63                 VariableNameDeclaration vnd = (VariableNameDeclaration)name.getNameDeclaration();
64                 if (vnd.getAccessNodeParent().isFinal() && vnd.getAccessNodeParent().isStatic()) {
65                     return data;
66                 }
67             }
68         }
69
70
71         if (bs.isAllocation()) {
72             if (isAllocatedStringBuffer(node)) {
73                 addViolation(data, node);
74             }
75         } else if (isInStringBufferOperation(node, 6, "append")) {
76             addViolation(data, node);
77         }
78         return data;
79     }
80
81     protected static boolean isInStringBufferOperation(SimpleNode node, int length, String JavaDoc methodName) {
82         if (!xParentIsStatementExpression(node, length)) {
83             return false;
84         }
85         ASTStatementExpression s = (ASTStatementExpression) node.getFirstParentOfType(ASTStatementExpression.class);
86         if (s == null) {
87             return false;
88         }
89         ASTName n = (ASTName)s.getFirstChildOfType(ASTName.class);
90         if (n == null || n.getImage().indexOf(methodName) == -1 || !(n.getNameDeclaration() instanceof VariableNameDeclaration)) {
91             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
ASTArgumentList argList = (ASTArgumentList)s.getFirstChildOfType(ASTArgumentList.class);
99         if (argList == null || argList.jjtGetNumChildren() > 1) {
100             return false;
101         }
102
103         return ((VariableNameDeclaration)n.getNameDeclaration()).getTypeImage().equals("StringBuffer");
104     }
105
106     // TODO move this method to SimpleNode
107
private static boolean xParentIsStatementExpression(SimpleNode node, int length) {
108         Node curr = node;
109         for (int i=0; i<length; i++) {
110             if (node.jjtGetParent() == null) {
111                 return false;
112             }
113             curr = curr.jjtGetParent();
114         }
115         return curr instanceof ASTStatementExpression;
116     }
117
118     private boolean isAllocatedStringBuffer(ASTAdditiveExpression node) {
119         ASTAllocationExpression ao = (ASTAllocationExpression) node.getFirstParentOfType(ASTAllocationExpression.class);
120         if (ao == null) {
121             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
ASTClassOrInterfaceType an = (ASTClassOrInterfaceType) ao.getFirstChildOfType(ASTClassOrInterfaceType.class);
125         return an != null && (an.getImage().endsWith("StringBuffer") || an.getImage().endsWith("StringBuilder"));
126     }
127 }
128
129
Popular Tags