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 }