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