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 }