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