View Javadoc

1   package net.sourceforge.pmd.rules;
2   
3   import java.util.Iterator;
4   import java.util.Set;
5   
6   import net.sourceforge.pmd.AbstractRule;
7   import net.sourceforge.pmd.ast.ASTExpression;
8   import net.sourceforge.pmd.ast.ASTLocalVariableDeclaration;
9   import net.sourceforge.pmd.ast.ASTName;
10  import net.sourceforge.pmd.ast.ASTType;
11  import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
12  import net.sourceforge.pmd.symboltable.NameOccurrence;
13  import net.sourceforge.pmd.util.CollectionUtil;
14  
15  /***
16   * An operation on an Immutable object (BigDecimal or BigInteger) won't change
17   * the object itself. The result of the operation is a new object. Therefore,
18   * ignoring the operation result is an error.
19   */
20  public class UselessOperationOnImmutable extends AbstractRule {
21  
22      /***
23       * These are the methods which are immutable
24       */
25      private static final Set targetMethods = CollectionUtil.asSet(new String[] { ".add", ".multiply", ".divide", ".subtract", ".setScale", ".negate", ".movePointLeft", ".movePointRight", ".pow", ".shiftLeft", ".shiftRight" });
26  
27      /***
28       * These are the classes that the rule can apply to
29       */
30      private static final Set targetClasses = CollectionUtil.asSet(new String[] { "java.math.BigDecimal", "BigDecimal", "java.math.BigInteger", "BigInteger" });
31  
32      public Object visit(ASTLocalVariableDeclaration node, Object data) {
33  
34          ASTVariableDeclaratorId var = getDeclaration(node);
35          if (var == null) {
36              return super.visit(node, data);
37          }
38          String variableName = var.getImage();
39          for (Iterator it = var.getUsages().iterator(); it.hasNext();) {
40              NameOccurrence no = (NameOccurrence) it.next();
41              ASTName sn = (ASTName) no.getLocation();
42              if (!sn.jjtGetParent().jjtGetParent().jjtGetParent().getClass().equals(ASTExpression.class)) {
43                  String methodCall = sn.getImage().substring(variableName.length());
44                  if (targetMethods.contains(methodCall)) {
45                      addViolation(data, sn);
46                  }
47              }
48          }
49          return super.visit(node, data);
50      }
51  
52      /***
53       * This method checks the variable declaration if it is on a class we care
54       * about. If it is, it returns the DeclaratorId
55       * 
56       * @param node
57       *            The ASTLocalVariableDeclaration which is a problem
58       * @return ASTVariableDeclaratorId
59       */
60      private ASTVariableDeclaratorId getDeclaration(ASTLocalVariableDeclaration node) {
61          ASTType type = node.getTypeNode();
62          if (targetClasses.contains(type.getTypeImage())) {
63              return (ASTVariableDeclaratorId) node.jjtGetChild(1).jjtGetChild(0);
64          }
65          return null;
66      }
67  }