1 /***
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd.rules.design;
5
6 import net.sourceforge.pmd.AbstractRule;
7 import net.sourceforge.pmd.ast.ASTAssignmentOperator;
8 import net.sourceforge.pmd.ast.ASTConditionalExpression;
9 import net.sourceforge.pmd.ast.ASTEqualityExpression;
10 import net.sourceforge.pmd.ast.ASTName;
11 import net.sourceforge.pmd.ast.ASTNullLiteral;
12 import net.sourceforge.pmd.ast.ASTStatementExpression;
13 import net.sourceforge.pmd.ast.Node;
14 import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
15
16 import java.util.Iterator;
17 import java.util.Map;
18
19
20 public class NullAssignmentRule extends AbstractRule {
21
22 public Object visit(ASTNullLiteral node, Object data) {
23 if (get5thParent(node) instanceof ASTStatementExpression) {
24 ASTStatementExpression n = (ASTStatementExpression)get5thParent(node);
25
26 if (isAssignmentToFinalField(n)) {
27 return data;
28 }
29
30 if (n.jjtGetNumChildren() > 2 && n.jjtGetChild(1) instanceof ASTAssignmentOperator) {
31 addViolation(data, node);
32 }
33 } else if (get4thParent(node) instanceof ASTConditionalExpression) {
34 checkTernary((ASTConditionalExpression)get4thParent(node), data, node);
35 } else if (get5thParent(node) instanceof ASTConditionalExpression) {
36 checkTernary((ASTConditionalExpression)get5thParent(node), data, node);
37 }
38
39 return data;
40 }
41
42 private boolean isAssignmentToFinalField(ASTStatementExpression n) {
43 ASTName name = (ASTName)n.getFirstChildOfType(ASTName.class);
44 if (name != null) {
45 Map vars = name.getScope().getEnclosingClassScope().getVariableDeclarations();
46 for (Iterator i = vars.keySet().iterator(); i.hasNext();) {
47 VariableNameDeclaration vnd = (VariableNameDeclaration)i.next();
48 if (vnd.getImage().equals(name.getImage()) && vnd.getAccessNodeParent().isFinal()) {
49 return true;
50 }
51 }
52 }
53 return false;
54 }
55
56 private Node get4thParent(ASTNullLiteral node) {
57 return node.jjtGetParent().jjtGetParent().jjtGetParent().jjtGetParent();
58 }
59
60 private Node get5thParent(ASTNullLiteral node) {
61 return get4thParent(node).jjtGetParent();
62 }
63
64 private void checkTernary(ASTConditionalExpression n, Object data, ASTNullLiteral node) {
65 if (n.isTernary() && !(n.jjtGetChild(0) instanceof ASTEqualityExpression)) {
66 addViolation(data, node);
67 }
68 }
69 }