1
2
3
4 package net.sourceforge.pmd.lang.java.rule.unnecessary;
5
6 import java.util.HashMap;
7 import java.util.Map;
8 import java.util.Set;
9
10 import net.sourceforge.pmd.lang.ast.Node;
11 import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
12 import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
13 import net.sourceforge.pmd.lang.java.ast.ASTType;
14 import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
15 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
16 import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
17 import net.sourceforge.pmd.util.CollectionUtil;
18
19
20
21
22
23
24 public class UselessOperationOnImmutableRule extends AbstractJavaRule {
25
26
27
28
29 private static final Set<String> BIG_DECIMAL_METHODS = CollectionUtil.asSet(new String[] { ".abs", ".add", ".divide", ".divideToIntegralValue", ".max", ".min", ".movePointLeft", ".movePointRight", ".multiply", ".negate", ".plus", ".pow", ".remainder", ".round", ".scaleByPowerOfTen", ".setScale", ".stripTrailingZeros", ".subtract", ".ulp" });
30
31
32
33
34 private static final Set<String> BIG_INTEGER_METHODS = CollectionUtil.asSet(new String[] { ".abs", ".add", ".and", ".andNot", ".clearBit", ".divide", ".flipBit", ".gcd", ".max", ".min", ".mod", ".modInverse", ".modPow", ".multiply", ".negate", ".nextProbablePrine", ".not", ".or", ".pow", ".remainder", ".setBit", ".shiftLeft", ".shiftRight", ".subtract", ".xor" });
35
36
37
38
39 private static final Set<String> STRING_METHODS = CollectionUtil.asSet(new String[] { ".concat", ".intern", ".replace", ".replaceAll", ".replaceFirst", ".substring", ".toLowerCase", ".toString", ".toUpperCase", ".trim" });
40
41
42
43
44 private static final Map<String, Set<String>> MAP_CLASSES = new HashMap<String, Set<String>>();
45 static {
46 MAP_CLASSES.put("java.math.BigDecimal", BIG_DECIMAL_METHODS);
47 MAP_CLASSES.put("BigDecimal", BIG_DECIMAL_METHODS);
48 MAP_CLASSES.put("java.math.BigInteger", BIG_INTEGER_METHODS);
49 MAP_CLASSES.put("BigInteger", BIG_INTEGER_METHODS);
50 MAP_CLASSES.put("java.lang.String", STRING_METHODS);
51 MAP_CLASSES.put("String", STRING_METHODS);
52 }
53
54 @Override
55 public Object visit(ASTLocalVariableDeclaration node, Object data) {
56
57 ASTVariableDeclaratorId var = getDeclaration(node);
58 if (var == null) {
59 return super.visit(node, data);
60 }
61 String variableName = var.getImage();
62 for (NameOccurrence no: var.getUsages()) {
63
64
65 Node sn = no.getLocation();
66 Node primaryExpression = sn.jjtGetParent().jjtGetParent();
67 Class<? extends Node> parentClass = primaryExpression.jjtGetParent().getClass();
68 if (parentClass.equals(ASTStatementExpression.class)) {
69 String methodCall = sn.getImage().substring(variableName.length());
70 ASTType nodeType = node.getTypeNode();
71 if ( nodeType != null ) {
72 if ( MAP_CLASSES.get(nodeType.getTypeImage()).contains(methodCall)) {
73 addViolation(data, sn);
74 }
75 }
76 }
77 }
78 return super.visit(node, data);
79 }
80
81
82
83
84
85
86
87
88
89 private ASTVariableDeclaratorId getDeclaration(ASTLocalVariableDeclaration node) {
90 ASTType type = node.getTypeNode();
91 if (MAP_CLASSES.keySet().contains(type.getTypeImage())) {
92 return node.getFirstDescendantOfType(ASTVariableDeclaratorId.class);
93 }
94 return null;
95 }
96 }