1
2
3
4 package net.sourceforge.pmd.lang.java.rule.strings;
5
6 import java.util.List;
7 import java.util.Map;
8
9 import net.sourceforge.pmd.lang.ast.Node;
10 import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
11 import net.sourceforge.pmd.lang.java.ast.ASTName;
12 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
13 import net.sourceforge.pmd.lang.java.ast.ASTStatement;
14 import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
15 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
16 import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
17 import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
18 import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public class ConsecutiveAppendsShouldReuseRule extends AbstractJavaRule {
49
50 @Override
51 public Object visit(ASTBlockStatement node, Object data) {
52 String variable = getVariableAppended(node);
53 if (variable != null) {
54 ASTBlockStatement nextSibling = getNextBlockStatementSibling(node);
55 if (nextSibling != null) {
56 String nextVariable = getVariableAppended(nextSibling);
57 if (nextVariable != null && nextVariable.equals(variable)) {
58 addViolation(data, node);
59 }
60 }
61 }
62 return super.visit(node, data);
63 }
64 private ASTBlockStatement getNextBlockStatementSibling(Node node) {
65 Node parent = node.jjtGetParent();
66 int childIndex = -1;
67 for (int i = 0; i < parent.jjtGetNumChildren(); i++) {
68 if (parent.jjtGetChild(i) == node) {
69 childIndex = i;
70 break;
71 }
72 }
73 if (childIndex + 1 < parent.jjtGetNumChildren()) {
74 Node nextSibling = parent.jjtGetChild(childIndex + 1);
75 if (nextSibling instanceof ASTBlockStatement) {
76 return (ASTBlockStatement)nextSibling;
77 }
78 }
79 return null;
80 }
81 private String getVariableAppended(ASTBlockStatement node) {
82 if (isFirstChild(node, ASTStatement.class)) {
83 ASTStatement statement = (ASTStatement) node.jjtGetChild(0);
84 if (isFirstChild(statement, ASTStatementExpression.class)) {
85 ASTStatementExpression stmtExp = (ASTStatementExpression) statement.jjtGetChild(0);
86 ASTPrimaryPrefix primaryPrefix = stmtExp.getFirstDescendantOfType(ASTPrimaryPrefix.class);
87 if (primaryPrefix != null) {
88 ASTName name = primaryPrefix.getFirstChildOfType(ASTName.class);
89 if (name != null) {
90 String image = name.getImage();
91 if (image.endsWith(".append")) {
92 String variable = image.substring(0, image.indexOf('.'));
93 if (isAStringBuilderBuffer(primaryPrefix, variable)) {
94 return variable;
95 }
96 }
97 }
98 }
99 }
100 }
101 return null;
102 }
103 private boolean isAStringBuilderBuffer(ASTPrimaryPrefix prefix, String name) {
104 Map<VariableNameDeclaration, List<NameOccurrence>> declarations = prefix.getScope().getDeclarations(VariableNameDeclaration.class);
105 for (VariableNameDeclaration decl : declarations.keySet()) {
106 if (decl.getName().equals(name) && TypeHelper.isEither(decl, StringBuilder.class, StringBuffer.class)) {
107 return true;
108 }
109 }
110 return false;
111 }
112
113 private boolean isFirstChild(Node node, Class<?> clazz) {
114 if (node.jjtGetNumChildren() == 1 && clazz.isAssignableFrom(node.jjtGetChild(0).getClass())) {
115 return true;
116 }
117 return false;
118 }
119 }