NonThreadSafeSingletonRule.java
001 /**
002  * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003  */
004 package net.sourceforge.pmd.lang.java.rule.design;
005 
006 import java.util.HashMap;
007 import java.util.List;
008 import java.util.Map;
009 
010 import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
011 import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
012 import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
013 import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
014 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
015 import net.sourceforge.pmd.lang.java.ast.ASTName;
016 import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral;
017 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
018 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
019 import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
020 import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
021 import net.sourceforge.pmd.lang.java.ast.ASTSynchronizedStatement;
022 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
023 import net.sourceforge.pmd.lang.rule.properties.BooleanProperty;
024 
025 public class NonThreadSafeSingletonRule extends AbstractJavaRule {
026 
027     private Map<String, ASTFieldDeclaration> fieldDecls = new HashMap<String, ASTFieldDeclaration>();
028 
029     private boolean checkNonStaticMethods = true;
030     private boolean checkNonStaticFields = true;
031 
032     private static final BooleanProperty CHECK_NON_STATIC_METHODS_DESCRIPTOR = new BooleanProperty(
033       "checkNonStaticMethods""Check for non-static methods.  Do not set this to false and checkNonStaticFields to true.", true, 1.0f);
034     private static final BooleanProperty CHECK_NON_STATIC_FIELDS_DESCRIPTOR = new BooleanProperty(
035       "checkNonStaticFields""Check for non-static fields.  Do not set this to true and checkNonStaticMethods to false.", false, 2.0f);
036 
037     //    public NonThreadSafeSingleton() {
038     //        checkNonStaticMethods = super.getBooleanProperty("checkNonStaticMethods");
039     //        checkNonStaticFields = super.getBooleanProperty("checkNonStaticFields");
040     //    }
041     
042     public NonThreadSafeSingletonRule() {
043   definePropertyDescriptor(CHECK_NON_STATIC_METHODS_DESCRIPTOR);
044   definePropertyDescriptor(CHECK_NON_STATIC_FIELDS_DESCRIPTOR);
045     }
046 
047     @Override
048     public Object visit(ASTCompilationUnit node, Object data) {
049   fieldDecls.clear();
050   checkNonStaticMethods = getProperty(CHECK_NON_STATIC_METHODS_DESCRIPTOR);
051   checkNonStaticFields = getProperty(CHECK_NON_STATIC_FIELDS_DESCRIPTOR);
052   return super.visit(node, data);
053     }
054 
055     @Override
056     public Object visit(ASTFieldDeclaration node, Object data) {
057   if (checkNonStaticFields || node.isStatic()) {
058       fieldDecls.put(node.getVariableName(), node);
059   }
060   return super.visit(node, data);
061     }
062 
063     @Override
064     public Object visit(ASTMethodDeclaration node, Object data) {
065 
066   if (checkNonStaticMethods && !node.isStatic() || node.isSynchronized()) {
067       return super.visit(node, data);
068   }
069 
070   List<ASTIfStatement> ifStatements = node.findDescendantsOfType(ASTIfStatement.class);
071   for (ASTIfStatement ifStatement : ifStatements) {
072       if (ifStatement.getFirstParentOfType(ASTSynchronizedStatement.class== null) {
073     if (!ifStatement.hasDescendantOfType(ASTNullLiteral.class)) {
074         continue;
075     }
076     ASTName n = ifStatement.getFirstDescendantOfType(ASTName.class);
077     if (n == null || !fieldDecls.containsKey(n.getImage())) {
078         continue;
079     }
080     List<ASTAssignmentOperator> assigmnents = ifStatement.findDescendantsOfType(ASTAssignmentOperator.class);
081     boolean violation = false;
082     for (int ix = 0; ix < assigmnents.size(); ix++) {
083         ASTAssignmentOperator oper = assigmnents.get(ix);
084         if (!(oper.jjtGetParent() instanceof ASTStatementExpression)) {
085       continue;
086         }
087         ASTStatementExpression expr = (ASTStatementExpressionoper.jjtGetParent();
088         if ((expr.jjtGetChild(0instanceof ASTPrimaryExpression)
089           && (((ASTPrimaryExpressionexpr.jjtGetChild(0)).jjtGetChild(0instanceof ASTPrimaryPrefix)) {
090       ASTPrimaryPrefix pp = (ASTPrimaryPrefix) ((ASTPrimaryExpressionexpr.jjtGetChild(0))
091         .jjtGetChild(0);
092       String name = null;
093       if (pp.usesThisModifier()) {
094           ASTPrimarySuffix priSuf = expr.getFirstDescendantOfType(ASTPrimarySuffix.class);
095           name = priSuf.getImage();
096       else {
097           ASTName astName = (ASTNamepp.jjtGetChild(0);
098           name = astName.getImage();
099       }
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 }