1
2
3
4 package net.sourceforge.pmd.lang.java.rule.design;
5
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Map;
9
10 import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
11 import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
12 import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
13 import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
14 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
15 import net.sourceforge.pmd.lang.java.ast.ASTName;
16 import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral;
17 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
18 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
19 import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
20 import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
21 import net.sourceforge.pmd.lang.java.ast.ASTSynchronizedStatement;
22 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
23 import net.sourceforge.pmd.lang.rule.properties.BooleanProperty;
24
25 public class NonThreadSafeSingletonRule extends AbstractJavaRule {
26
27 private Map<String, ASTFieldDeclaration> fieldDecls = new HashMap<String, ASTFieldDeclaration>();
28
29 private boolean checkNonStaticMethods = true;
30 private boolean checkNonStaticFields = true;
31
32 private static final BooleanProperty CHECK_NON_STATIC_METHODS_DESCRIPTOR = new BooleanProperty(
33 "checkNonStaticMethods",
34 "Check for non-static methods. Do not set this to false and checkNonStaticFields to true.", true, 1.0f);
35 private static final BooleanProperty CHECK_NON_STATIC_FIELDS_DESCRIPTOR = new BooleanProperty(
36 "checkNonStaticFields",
37 "Check for non-static fields. Do not set this to true and checkNonStaticMethods to false.", false, 2.0f);
38
39 public NonThreadSafeSingletonRule() {
40 definePropertyDescriptor(CHECK_NON_STATIC_METHODS_DESCRIPTOR);
41 definePropertyDescriptor(CHECK_NON_STATIC_FIELDS_DESCRIPTOR);
42 }
43
44 @Override
45 public Object visit(ASTCompilationUnit node, Object data) {
46 fieldDecls.clear();
47 checkNonStaticMethods = getProperty(CHECK_NON_STATIC_METHODS_DESCRIPTOR);
48 checkNonStaticFields = getProperty(CHECK_NON_STATIC_FIELDS_DESCRIPTOR);
49 return super.visit(node, data);
50 }
51
52 @Override
53 public Object visit(ASTFieldDeclaration node, Object data) {
54 if (checkNonStaticFields || node.isStatic()) {
55 fieldDecls.put(node.getVariableName(), node);
56 }
57 return super.visit(node, data);
58 }
59
60 @Override
61 public Object visit(ASTMethodDeclaration node, Object data) {
62
63 if (checkNonStaticMethods && !node.isStatic() || node.isSynchronized()) {
64 return super.visit(node, data);
65 }
66
67 List<ASTIfStatement> ifStatements = node.findDescendantsOfType(ASTIfStatement.class);
68 for (ASTIfStatement ifStatement : ifStatements) {
69 if (ifStatement.getFirstParentOfType(ASTSynchronizedStatement.class) == null) {
70 if (!ifStatement.hasDescendantOfType(ASTNullLiteral.class)) {
71 continue;
72 }
73 ASTName n = ifStatement.getFirstDescendantOfType(ASTName.class);
74 if (n == null || !fieldDecls.containsKey(n.getImage())) {
75 continue;
76 }
77 List<ASTAssignmentOperator> assigmnents = ifStatement
78 .findDescendantsOfType(ASTAssignmentOperator.class);
79 boolean violation = false;
80 for (int ix = 0; ix < assigmnents.size(); ix++) {
81 ASTAssignmentOperator oper = assigmnents.get(ix);
82 if (!(oper.jjtGetParent() instanceof ASTStatementExpression)) {
83 continue;
84 }
85 ASTStatementExpression expr = (ASTStatementExpression) oper.jjtGetParent();
86 if (expr.jjtGetChild(0) instanceof ASTPrimaryExpression
87 && ((ASTPrimaryExpression) expr.jjtGetChild(0)).jjtGetNumChildren() == 1
88 && ((ASTPrimaryExpression) expr.jjtGetChild(0)).jjtGetChild(0) instanceof ASTPrimaryPrefix) {
89 ASTPrimaryPrefix pp = (ASTPrimaryPrefix) ((ASTPrimaryExpression) expr.jjtGetChild(0))
90 .jjtGetChild(0);
91 String name = null;
92 if (pp.usesThisModifier()) {
93 ASTPrimarySuffix priSuf = expr.getFirstDescendantOfType(ASTPrimarySuffix.class);
94 name = priSuf.getImage();
95 } else {
96 ASTName astName = (ASTName) pp.jjtGetChild(0);
97 name = astName.getImage();
98 }
99 if (fieldDecls.containsKey(name)) {
100 violation = true;
101 }
102 }
103 }
104 if (violation) {
105 addViolation(data, ifStatement);
106 }
107 }
108 }
109 return super.visit(node, data);
110 }
111 }