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 }