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 java.util.HashMap;
7 import java.util.Iterator;
8 import java.util.List;
9 import java.util.Map;
10
11 import net.sourceforge.pmd.AbstractRule;
12 import net.sourceforge.pmd.PropertyDescriptor;
13 import net.sourceforge.pmd.ast.ASTAssignmentOperator;
14 import net.sourceforge.pmd.ast.ASTCompilationUnit;
15 import net.sourceforge.pmd.ast.ASTFieldDeclaration;
16 import net.sourceforge.pmd.ast.ASTIfStatement;
17 import net.sourceforge.pmd.ast.ASTMethodDeclaration;
18 import net.sourceforge.pmd.ast.ASTName;
19 import net.sourceforge.pmd.ast.ASTNullLiteral;
20 import net.sourceforge.pmd.ast.ASTPrimaryExpression;
21 import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
22 import net.sourceforge.pmd.ast.ASTPrimarySuffix;
23 import net.sourceforge.pmd.ast.ASTStatementExpression;
24 import net.sourceforge.pmd.ast.ASTSynchronizedStatement;
25 import net.sourceforge.pmd.properties.BooleanProperty;
26
27 public class NonThreadSafeSingleton extends AbstractRule {
28
29 private Map fieldDecls = new HashMap();
30
31 private boolean checkNonStaticMethods = true;
32 private boolean checkNonStaticFields = true;
33
34 private static final PropertyDescriptor checkNonStaticMethodsDescriptor = new BooleanProperty(
35 "checkNonStaticMethods", "Check for non-static methods.", true, 1.0f
36 );
37 private static final PropertyDescriptor checkNonStaticFieldsDescriptor = new BooleanProperty(
38 "checkNonStaticFields", "Check for non-static fields.", true, 2.0f
39 );
40
41 private static final Map propertyDescriptorsByName = asFixedMap(new PropertyDescriptor[] {
42 checkNonStaticMethodsDescriptor, checkNonStaticFieldsDescriptor
43 });
44
45
46
47
48
49
50 public Object visit(ASTCompilationUnit node, Object data) {
51 fieldDecls.clear();
52 checkNonStaticMethods = getBooleanProperty(checkNonStaticMethodsDescriptor);
53 checkNonStaticFields = getBooleanProperty(checkNonStaticFieldsDescriptor);
54 return super.visit(node, data);
55 }
56
57 public Object visit(ASTFieldDeclaration node, Object data) {
58 if (checkNonStaticFields || node.isStatic()) {
59 fieldDecls.put(node.getVariableName(), node);
60 }
61 return super.visit(node, data);
62 }
63
64 public Object visit(ASTMethodDeclaration node, Object data) {
65
66 if ((checkNonStaticMethods && !node.isStatic()) || node.isSynchronized()) {
67 return super.visit(node, data);
68 }
69
70 List ifStatements = node.findChildrenOfType(ASTIfStatement.class);
71 for (Iterator iter = ifStatements.iterator(); iter.hasNext();) {
72 ASTIfStatement ifStatement = (ASTIfStatement) iter.next();
73 if (ifStatement.getFirstParentOfType(ASTSynchronizedStatement.class) == null) {
74 ASTNullLiteral NullLiteral = (ASTNullLiteral) ifStatement.getFirstChildOfType(ASTNullLiteral.class);
75
76 if (NullLiteral == null) {
77 continue;
78 }
79 ASTName Name = (ASTName) ifStatement.getFirstChildOfType(ASTName.class);
80 if (Name == null || !fieldDecls.containsKey(Name.getImage())) {
81 continue;
82 }
83 List assigmnents = ifStatement.findChildrenOfType(ASTAssignmentOperator.class);
84 boolean violation = false;
85 for (int ix = 0; ix < assigmnents.size(); ix++) {
86 ASTAssignmentOperator oper = (ASTAssignmentOperator) assigmnents.get(ix);
87 if (!oper.jjtGetParent().getClass().equals(ASTStatementExpression.class)) {
88 continue;
89 }
90 ASTStatementExpression expr = (ASTStatementExpression) oper.jjtGetParent();
91 if (expr.jjtGetChild(0).getClass().equals(ASTPrimaryExpression.class) && ((ASTPrimaryExpression) expr.jjtGetChild(0)).jjtGetChild(0).getClass().equals(ASTPrimaryPrefix.class)) {
92 ASTPrimaryPrefix pp = (ASTPrimaryPrefix) ((ASTPrimaryExpression) expr.jjtGetChild(0)).jjtGetChild(0);
93 String name = null;
94 if (pp.usesThisModifier()) {
95 ASTPrimarySuffix priSuf = (ASTPrimarySuffix)expr.getFirstChildOfType(ASTPrimarySuffix.class);
96 name = priSuf.getImage();
97 } else {
98 ASTName astName = (ASTName) pp.jjtGetChild(0);
99 name = astName.getImage();
100 }
101 if (fieldDecls.containsKey(name)) {
102 violation = true;
103 }
104 }
105 }
106 if (violation) {
107 addViolation(data, ifStatement);
108 }
109 }
110 }
111 return super.visit(node, data);
112 }
113
114 /***
115 * @return Map
116 */
117 protected Map propertiesByName() {
118 return propertyDescriptorsByName;
119 }
120 }