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 NonThreadSafeSingletonRule() {
    38  	definePropertyDescriptor(CHECK_NON_STATIC_METHODS_DESCRIPTOR);
    39  	definePropertyDescriptor(CHECK_NON_STATIC_FIELDS_DESCRIPTOR);
    40      }
    41
    42      @Override
    43      public Object visit(ASTCompilationUnit node, Object data) {
    44  	fieldDecls.clear();
    45  	checkNonStaticMethods = getProperty(CHECK_NON_STATIC_METHODS_DESCRIPTOR);
    46  	checkNonStaticFields = getProperty(CHECK_NON_STATIC_FIELDS_DESCRIPTOR);
    47  	return super.visit(node, data);
    48      }
    49
    50      @Override
    51      public Object visit(ASTFieldDeclaration node, Object data) {
    52  	if (checkNonStaticFields || node.isStatic()) {
    53  	    fieldDecls.put(node.getVariableName(), node);
    54  	}
    55  	return super.visit(node, data);
    56      }
    57
    58      @Override
    59      public Object visit(ASTMethodDeclaration node, Object data) {
    60
    61  	if (checkNonStaticMethods && !node.isStatic() || node.isSynchronized()) {
    62  	    return super.visit(node, data);
    63  	}
    64
    65  	List<ASTIfStatement> ifStatements = node.findDescendantsOfType(ASTIfStatement.class);
    66  	for (ASTIfStatement ifStatement : ifStatements) {
    67  	    if (ifStatement.getFirstParentOfType(ASTSynchronizedStatement.class) == null) {
    68  		if (!ifStatement.hasDescendantOfType(ASTNullLiteral.class)) {
    69  		    continue;
    70  		}
    71  		ASTName n = ifStatement.getFirstDescendantOfType(ASTName.class);
    72  		if (n == null || !fieldDecls.containsKey(n.getImage())) {
    73  		    continue;
    74  		}
    75  		List<ASTAssignmentOperator> assigmnents = ifStatement.findDescendantsOfType(ASTAssignmentOperator.class);
    76  		boolean violation = false;
    77  		for (int ix = 0; ix < assigmnents.size(); ix++) {
    78  		    ASTAssignmentOperator oper = assigmnents.get(ix);
    79  		    if (!(oper.jjtGetParent() instanceof ASTStatementExpression)) {
    80  			continue;
    81  		    }
    82  		    ASTStatementExpression expr = (ASTStatementExpression) oper.jjtGetParent();
    83  		    if ((expr.jjtGetChild(0) instanceof ASTPrimaryExpression)
    84  	            && ((ASTPrimaryExpression) expr.jjtGetChild(0)).jjtGetNumChildren() == 1
    85  			    && (((ASTPrimaryExpression) expr.jjtGetChild(0)).jjtGetChild(0) instanceof ASTPrimaryPrefix)) {
    86  			ASTPrimaryPrefix pp = (ASTPrimaryPrefix) ((ASTPrimaryExpression) expr.jjtGetChild(0))
    87  				.jjtGetChild(0);
    88  			String name = null;
    89  			if (pp.usesThisModifier()) {
    90  			    ASTPrimarySuffix priSuf = expr.getFirstDescendantOfType(ASTPrimarySuffix.class);
    91  			    name = priSuf.getImage();
    92  			} else {
    93  			    ASTName astName = (ASTName) pp.jjtGetChild(0);
    94  			    name = astName.getImage();
    95  			}
    96  			if (fieldDecls.containsKey(name)) {
    97  			    violation = true;
    98  			}
    99  		    }
    100 		}
    101 		if (violation) {
    102 		    addViolation(data, ifStatement);
    103 		}
    104 	    }
    105 	}
    106 	return super.visit(node, data);
    107     }
    108 }