1
2
3
4 package net.sourceforge.pmd.lang.java.rule.design;
5
6 import java.util.List;
7
8 import net.sourceforge.pmd.lang.ast.Node;
9 import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
10 import net.sourceforge.pmd.lang.java.ast.ASTExpression;
11 import net.sourceforge.pmd.lang.java.ast.ASTName;
12 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
13 import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
14 import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
15 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
16
17 public class IdempotentOperationsRule extends AbstractJavaRule {
18
19 @Override
20 public Object visit(ASTStatementExpression node, Object data) {
21 if (node.jjtGetNumChildren() != 3
22 || !(node.jjtGetChild(0) instanceof ASTPrimaryExpression)
23 || !(node.jjtGetChild(1) instanceof ASTAssignmentOperator)
24 || ((ASTAssignmentOperator) node.jjtGetChild(1)).isCompound()
25 || !(node.jjtGetChild(2) instanceof ASTExpression)
26 || node.jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() == 0
27 || node.jjtGetChild(2).jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() == 0
28 ) {
29 return super.visit(node, data);
30 }
31
32 Node lhs = node.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0);
33 if (!(lhs instanceof ASTName)) {
34 return super.visit(node, data);
35 }
36
37 Node rhs = node.jjtGetChild(2).jjtGetChild(0).jjtGetChild(0).jjtGetChild(0);
38 if (!(rhs instanceof ASTName)) {
39 return super.visit(node, data);
40 }
41
42 if (!lhs.hasImageEqualTo(rhs.getImage())) {
43 return super.visit(node, data);
44 }
45
46 if (lhs.jjtGetParent().jjtGetParent().jjtGetNumChildren() > 1) {
47 Node n = lhs.jjtGetParent().jjtGetParent().jjtGetChild(1);
48 if (n instanceof ASTPrimarySuffix && ((ASTPrimarySuffix) n).isArrayDereference()) {
49 return super.visit(node, data);
50 }
51 }
52
53 if (rhs.jjtGetParent().jjtGetParent().jjtGetNumChildren() > 1) {
54 Node n = rhs.jjtGetParent().jjtGetParent().jjtGetChild(1);
55 if (n instanceof ASTPrimarySuffix && ((ASTPrimarySuffix) n).isArguments() || ((ASTPrimarySuffix) n).isArrayDereference()) {
56 return super.visit(node, data);
57 }
58 }
59
60 if (lhs.findDescendantsOfType(ASTPrimarySuffix.class).size() != rhs.findDescendantsOfType(ASTPrimarySuffix.class).size()) {
61 return super.visit(node, data);
62 }
63
64 List<ASTPrimarySuffix> lhsSuffixes = lhs.jjtGetParent().jjtGetParent().findDescendantsOfType(ASTPrimarySuffix.class);
65 List<ASTPrimarySuffix> rhsSuffixes = rhs.jjtGetParent().jjtGetParent().findDescendantsOfType(ASTPrimarySuffix.class);
66 if (lhsSuffixes.size() != rhsSuffixes.size()) {
67 return super.visit(node, data);
68 }
69
70 for (int i = 0; i < lhsSuffixes.size(); i++) {
71 ASTPrimarySuffix l = lhsSuffixes.get(i);
72 ASTPrimarySuffix r = rhsSuffixes.get(i);
73
74 if (!l.hasImageEqualTo(r.getImage())) {
75 return super.visit(node, data);
76 }
77 }
78
79 addViolation(data, node);
80 return super.visit(node, data);
81 }
82 }