View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
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", "Check for non-static methods.  Do not set this to false and checkNonStaticFields to true.", true, 1.0f);
34      private static final BooleanProperty CHECK_NON_STATIC_FIELDS_DESCRIPTOR = new BooleanProperty(
35  	    "checkNonStaticFields", "Check for non-static fields.  Do not set this to true and checkNonStaticMethods to false.", false, 2.0f);
36  
37      //    public NonThreadSafeSingleton() {
38      //        checkNonStaticMethods = super.getBooleanProperty("checkNonStaticMethods");
39      //        checkNonStaticFields = super.getBooleanProperty("checkNonStaticFields");
40      //    }
41      
42      public NonThreadSafeSingletonRule() {
43  	definePropertyDescriptor(CHECK_NON_STATIC_METHODS_DESCRIPTOR);
44  	definePropertyDescriptor(CHECK_NON_STATIC_FIELDS_DESCRIPTOR);
45      }
46  
47      @Override
48      public Object visit(ASTCompilationUnit node, Object data) {
49  	fieldDecls.clear();
50  	checkNonStaticMethods = getProperty(CHECK_NON_STATIC_METHODS_DESCRIPTOR);
51  	checkNonStaticFields = getProperty(CHECK_NON_STATIC_FIELDS_DESCRIPTOR);
52  	return super.visit(node, data);
53      }
54  
55      @Override
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      @Override
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<ASTIfStatement> ifStatements = node.findDescendantsOfType(ASTIfStatement.class);
71  	for (ASTIfStatement ifStatement : ifStatements) {
72  	    if (ifStatement.getFirstParentOfType(ASTSynchronizedStatement.class) == null) {
73  		if (!ifStatement.hasDescendantOfType(ASTNullLiteral.class)) {
74  		    continue;
75  		}
76  		ASTName n = ifStatement.getFirstDescendantOfType(ASTName.class);
77  		if (n == null || !fieldDecls.containsKey(n.getImage())) {
78  		    continue;
79  		}
80  		List<ASTAssignmentOperator> assigmnents = ifStatement.findDescendantsOfType(ASTAssignmentOperator.class);
81  		boolean violation = false;
82  		for (int ix = 0; ix < assigmnents.size(); ix++) {
83  		    ASTAssignmentOperator oper = assigmnents.get(ix);
84  		    if (!(oper.jjtGetParent() instanceof ASTStatementExpression)) {
85  			continue;
86  		    }
87  		    ASTStatementExpression expr = (ASTStatementExpression) oper.jjtGetParent();
88  		    if ((expr.jjtGetChild(0) instanceof ASTPrimaryExpression)
89  			    && (((ASTPrimaryExpression) expr.jjtGetChild(0)).jjtGetChild(0) instanceof ASTPrimaryPrefix)) {
90  			ASTPrimaryPrefix pp = (ASTPrimaryPrefix) ((ASTPrimaryExpression) expr.jjtGetChild(0))
91  				.jjtGetChild(0);
92  			String name = null;
93  			if (pp.usesThisModifier()) {
94  			    ASTPrimarySuffix priSuf = expr.getFirstDescendantOfType(ASTPrimarySuffix.class);
95  			    name = priSuf.getImage();
96  			} else {
97  			    ASTName astName = (ASTName) pp.jjtGetChild(0);
98  			    name = astName.getImage();
99  			}
100 			if (fieldDecls.containsKey(name)) {
101 			    violation = true;
102 			}
103 		    }
104 		}
105 		if (violation) {
106 		    addViolation(data, ifStatement);
107 		}
108 	    }
109 	}
110 	return super.visit(node, data);
111     }
112 }