View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.rule.optimizations;
5   
6   import net.sourceforge.pmd.lang.ast.Node;
7   import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
8   import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
9   import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression;
10  import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression;
11  import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
12  import net.sourceforge.pmd.lang.java.ast.ASTName;
13  import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
14  import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
15  import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
16  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
17  import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
18  import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
19  
20  public class UseStringBufferForStringAppendsRule extends AbstractJavaRule {
21  
22      @Override
23      public Object visit(ASTVariableDeclaratorId node, Object data) {
24          if (!TypeHelper.isA(node, String.class) || node.isArray()) {
25              return data;
26          }
27          Node parent = node.jjtGetParent().jjtGetParent();
28          if (!(parent instanceof ASTLocalVariableDeclaration)) {
29              return data;
30          }
31          for (NameOccurrence no: node.getUsages()) {
32              Node name = no.getLocation();
33              ASTStatementExpression statement = name.getFirstParentOfType(ASTStatementExpression.class);
34              if (statement == null) {
35                  continue;
36              }
37              ASTArgumentList argList = name.getFirstParentOfType(ASTArgumentList.class);
38              if (argList != null && argList.getFirstParentOfType(ASTStatementExpression.class) == statement) {
39                  // used in method call
40                  continue;
41              }
42              ASTEqualityExpression equality = name.getFirstParentOfType(ASTEqualityExpression.class);
43              if (equality != null && equality.getFirstParentOfType(ASTStatementExpression.class) == statement) {
44                  // used in condition
45                  continue;
46              }
47              ASTConditionalExpression conditional = name.getFirstParentOfType(ASTConditionalExpression.class);
48              if (conditional != null && name.jjtGetParent().jjtGetParent().jjtGetParent() == conditional && conditional.getFirstParentOfType(ASTStatementExpression.class) == statement) {
49                  // is used in ternary as only option (not appendend to other string)
50                  continue;
51              }
52              if (statement.jjtGetNumChildren() > 0 && statement.jjtGetChild(0) instanceof ASTPrimaryExpression) {
53                  ASTName astName = statement.jjtGetChild(0).getFirstDescendantOfType(ASTName.class);
54                  if(astName != null){
55                      if (astName.equals(name)) {
56                          ASTAssignmentOperator assignmentOperator = statement.getFirstDescendantOfType(ASTAssignmentOperator.class);
57                          if (assignmentOperator != null && assignmentOperator.isCompound()) {
58                              addViolation(data, assignmentOperator);
59                          }
60                      } else if(astName.getImage().equals(name.getImage())){
61                          ASTAssignmentOperator assignmentOperator = statement.getFirstDescendantOfType(ASTAssignmentOperator.class);
62                          if (assignmentOperator != null && !assignmentOperator.isCompound()) {
63                              addViolation(data, astName);
64                          }
65                      }
66                  }
67              }
68          }
69          return data;
70      }
71  }