View Javadoc

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  //    public NonThreadSafeSingleton() {
46  //        checkNonStaticMethods = super.getBooleanProperty("checkNonStaticMethods");
47  //        checkNonStaticFields = super.getBooleanProperty("checkNonStaticFields");
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 }