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 = (ASTStatementExpression) oper.jjtGetParent();
088 if ((expr.jjtGetChild(0) instanceof ASTPrimaryExpression)
089 && (((ASTPrimaryExpression) expr.jjtGetChild(0)).jjtGetChild(0) instanceof ASTPrimaryPrefix)) {
090 ASTPrimaryPrefix pp = (ASTPrimaryPrefix) ((ASTPrimaryExpression) expr.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 = (ASTName) pp.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 }
|