View Javadoc

1   /***
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.rules;
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.ASTBlockStatement;
10  import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
11  import net.sourceforge.pmd.ast.ASTLiteral;
12  import net.sourceforge.pmd.ast.ASTName;
13  
14  /*
15   * How this rule works:
16   * find additive expressions: +
17   * check that the addition is between literal and nonliteral
18   * if true and also the parent is StringBuffer constructor or append,
19   * report a violation.
20   * 
21   * @author mgriffa
22   */
23  public final class AvoidConcatenatingNonLiteralsInStringBuffer extends AbstractRule {
24  
25      public Object visit(ASTAdditiveExpression node, Object data) {
26          ASTBlockStatement bs = (ASTBlockStatement) node.getFirstParentOfType(ASTBlockStatement.class);
27          if (bs == null) {
28              return data;
29          }
30  
31          if (!concatsLiteralStringAndNonLiteral(node)) {
32              return data;
33          }
34          
35          if (bs.isAllocation()) {
36              if (isAllocatedStringBuffer(node)) {
37                  addViolation(data, node);
38              }
39          } else if (isInStringBufferAppend(node)) {
40              addViolation(data, node);
41          }
42          return data;
43      }
44  
45      private boolean concatsLiteralStringAndNonLiteral(ASTAdditiveExpression node) {
46          if (!node.containsChildOfType(ASTName.class)) {
47              return false;
48          }
49          ASTLiteral n = (ASTLiteral)node.getFirstChildOfType(ASTLiteral.class);
50          if (n == null) {
51              return false;
52          }
53          try {
54              Integer.parseInt(n.getImage());
55          } catch (NumberFormatException nfe) {
56              return true;
57          }
58          return false;
59      }
60  
61      private boolean isInStringBufferAppend(ASTAdditiveExpression node) {
62          ASTBlockStatement s = (ASTBlockStatement) node.getFirstParentOfType(ASTBlockStatement.class);
63          if (s == null) {
64              return false;
65          }
66          ASTName n = (ASTName) s.getFirstChildOfType(ASTName.class);
67          return n.getImage()!=null && n.getImage().endsWith("append");
68      }
69      
70      private boolean isAllocatedStringBuffer(ASTAdditiveExpression node) {
71          ASTAllocationExpression ao = (ASTAllocationExpression) node.getFirstParentOfType(ASTAllocationExpression.class);
72          if (ao == null) {
73              return false;
74          }
75          // note that the child can be an ArrayDimsAndInits, for example, from java.lang.FloatingDecimal:  t = new int[ nWords+wordcount+1 ];
76          ASTClassOrInterfaceType an = (ASTClassOrInterfaceType) ao.getFirstChildOfType(ASTClassOrInterfaceType.class);
77          return an != null && (an.getImage().endsWith("StringBuffer") || an.getImage().endsWith("StringBuilder"));
78      }
79  }
80