1
2
3
4 package net.sourceforge.pmd.lang.java.rule.strings;
5
6 import java.util.HashSet;
7 import java.util.List;
8 import java.util.Set;
9
10 import net.sourceforge.pmd.lang.ast.Node;
11 import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
12 import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
13 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
14 import net.sourceforge.pmd.lang.java.ast.ASTName;
15 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
16 import net.sourceforge.pmd.lang.java.symboltable.TypedNameDeclaration;
17 import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
18 import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 public class UseStringBufferLengthRule extends AbstractJavaRule {
39
40
41
42
43
44
45
46
47
48
49
50 private Set<NameDeclaration> alreadySeen = new HashSet<NameDeclaration>();
51
52 @Override
53 public Object visit(ASTMethodDeclaration acu, Object data) {
54 alreadySeen.clear();
55 return super.visit(acu, data);
56 }
57
58 @Override
59 public Object visit(ASTName decl, Object data) {
60 if (!decl.getImage().endsWith("toString")) {
61 return data;
62 }
63 NameDeclaration nd = decl.getNameDeclaration();
64 if (nd == null) {
65 return data;
66 }
67 if (alreadySeen.contains(nd) ||
68 !(nd instanceof TypedNameDeclaration) ||
69 (nd instanceof TypedNameDeclaration && TypeHelper.isNeither((TypedNameDeclaration)nd, StringBuffer.class, StringBuilder.class))) {
70 return data;
71 }
72 alreadySeen.add(nd);
73
74 if (isViolation(decl)) {
75 addViolation(data, decl);
76 }
77
78 return data;
79 }
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97 private boolean isViolation(ASTName decl) {
98
99 Node parent = decl.jjtGetParent().jjtGetParent();
100 if (parent.jjtGetNumChildren() == 4) {
101
102 if (parent.jjtGetChild(0).getFirstChildOfType(ASTName.class).getImage().endsWith(".toString")) {
103
104
105
106 return isEqualsViolation(parent) || isLengthViolation(parent);
107 }
108 }
109 return false;
110 }
111
112 private boolean isEqualsViolation(Node parent) {
113
114 if (parent.jjtGetChild(2).hasImageEqualTo("equals")) {
115
116 List<ASTArgumentList> argList = parent.jjtGetChild(3).findDescendantsOfType(ASTArgumentList.class);
117 if (argList.size() == 1) {
118 List<ASTLiteral> literals = argList.get(0).findDescendantsOfType(ASTLiteral.class);
119 return literals.size() == 1 && literals.get(0).hasImageEqualTo("\"\"");
120 }
121 }
122 return false;
123 }
124
125 private boolean isLengthViolation(Node parent) {
126
127 return parent.jjtGetChild(2).hasImageEqualTo("length");
128
129
130 }
131
132 }