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 private Set<NameDeclaration> alreadySeen = new HashSet<NameDeclaration>();
50
51 @Override
52 public Object visit(ASTMethodDeclaration acu, Object data) {
53 alreadySeen.clear();
54 return super.visit(acu, data);
55 }
56
57 @Override
58 public Object visit(ASTName decl, Object data) {
59 if (!decl.getImage().endsWith("toString")) {
60 return data;
61 }
62 NameDeclaration nd = decl.getNameDeclaration();
63 if (nd == null) {
64 return data;
65 }
66 if (alreadySeen.contains(nd) || !(nd instanceof TypedNameDeclaration) || nd instanceof TypedNameDeclaration
67 && TypeHelper.isNeither((TypedNameDeclaration) nd, StringBuffer.class, StringBuilder.class)) {
68 return data;
69 }
70 alreadySeen.add(nd);
71
72 if (isViolation(decl)) {
73 addViolation(data, decl);
74 }
75
76 return data;
77 }
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 private boolean isViolation(ASTName decl) {
96
97 Node parent = decl.jjtGetParent().jjtGetParent();
98 if (parent.jjtGetNumChildren() == 4) {
99
100
101 if (parent.jjtGetChild(0).getFirstChildOfType(ASTName.class).getImage().endsWith(".toString")) {
102
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
117 List<ASTArgumentList> argList = parent.jjtGetChild(3).findDescendantsOfType(ASTArgumentList.class);
118 if (argList.size() == 1) {
119 List<ASTLiteral> literals = argList.get(0).findDescendantsOfType(ASTLiteral.class);
120 return literals.size() == 1 && literals.get(0).hasImageEqualTo("\"\"");
121 }
122 }
123 return false;
124 }
125
126 private boolean isLengthViolation(Node parent) {
127
128 return parent.jjtGetChild(2).hasImageEqualTo("length");
129
130
131 }
132
133 }