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