001: /**
002: * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003: */package net.sourceforge.pmd.rules.design;
004:
005: import java.util.HashMap;
006: import java.util.List;
007: import java.util.Map;
008:
009: import net.sourceforge.pmd.AbstractRule;
010: import net.sourceforge.pmd.PropertyDescriptor;
011: import net.sourceforge.pmd.ast.ASTAssignmentOperator;
012: import net.sourceforge.pmd.ast.ASTCompilationUnit;
013: import net.sourceforge.pmd.ast.ASTFieldDeclaration;
014: import net.sourceforge.pmd.ast.ASTIfStatement;
015: import net.sourceforge.pmd.ast.ASTMethodDeclaration;
016: import net.sourceforge.pmd.ast.ASTName;
017: import net.sourceforge.pmd.ast.ASTNullLiteral;
018: import net.sourceforge.pmd.ast.ASTPrimaryExpression;
019: import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
020: import net.sourceforge.pmd.ast.ASTPrimarySuffix;
021: import net.sourceforge.pmd.ast.ASTStatementExpression;
022: import net.sourceforge.pmd.ast.ASTSynchronizedStatement;
023: import net.sourceforge.pmd.properties.BooleanProperty;
024:
025: public class NonThreadSafeSingleton extends AbstractRule {
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 PropertyDescriptor checkNonStaticMethodsDescriptor = new BooleanProperty(
033: "checkNonStaticMethods", "Check for non-static methods.",
034: true, 1.0f);
035: private static final PropertyDescriptor checkNonStaticFieldsDescriptor = new BooleanProperty(
036: "checkNonStaticFields", "Check for non-static fields.",
037: true, 2.0f);
038:
039: private static final Map<String, PropertyDescriptor> propertyDescriptorsByName = asFixedMap(new PropertyDescriptor[] {
040: checkNonStaticMethodsDescriptor,
041: checkNonStaticFieldsDescriptor });
042:
043: // public NonThreadSafeSingleton() {
044: // checkNonStaticMethods = super.getBooleanProperty("checkNonStaticMethods");
045: // checkNonStaticFields = super.getBooleanProperty("checkNonStaticFields");
046: // }
047:
048: public Object visit(ASTCompilationUnit node, Object data) {
049: fieldDecls.clear();
050: checkNonStaticMethods = getBooleanProperty(checkNonStaticMethodsDescriptor);
051: checkNonStaticFields = getBooleanProperty(checkNonStaticFieldsDescriptor);
052: return super .visit(node, data);
053: }
054:
055: public Object visit(ASTFieldDeclaration node, Object data) {
056: if (checkNonStaticFields || node.isStatic()) {
057: fieldDecls.put(node.getVariableName(), node);
058: }
059: return super .visit(node, data);
060: }
061:
062: public Object visit(ASTMethodDeclaration node, Object data) {
063:
064: if ((checkNonStaticMethods && !node.isStatic())
065: || node.isSynchronized()) {
066: return super .visit(node, data);
067: }
068:
069: List<ASTIfStatement> ifStatements = node
070: .findChildrenOfType(ASTIfStatement.class);
071: for (ASTIfStatement ifStatement : ifStatements) {
072: if (ifStatement
073: .getFirstParentOfType(ASTSynchronizedStatement.class) == null) {
074: ASTNullLiteral NullLiteral = ifStatement
075: .getFirstChildOfType(ASTNullLiteral.class);
076:
077: if (NullLiteral == null) {
078: continue;
079: }
080: ASTName Name = ifStatement
081: .getFirstChildOfType(ASTName.class);
082: if (Name == null
083: || !fieldDecls.containsKey(Name.getImage())) {
084: continue;
085: }
086: List assigmnents = ifStatement
087: .findChildrenOfType(ASTAssignmentOperator.class);
088: boolean violation = false;
089: for (int ix = 0; ix < assigmnents.size(); ix++) {
090: ASTAssignmentOperator oper = (ASTAssignmentOperator) assigmnents
091: .get(ix);
092: if (!oper.jjtGetParent().getClass().equals(
093: ASTStatementExpression.class)) {
094: continue;
095: }
096: ASTStatementExpression expr = (ASTStatementExpression) oper
097: .jjtGetParent();
098: if (expr.jjtGetChild(0).getClass().equals(
099: ASTPrimaryExpression.class)
100: && ((ASTPrimaryExpression) expr
101: .jjtGetChild(0)).jjtGetChild(0)
102: .getClass().equals(
103: ASTPrimaryPrefix.class)) {
104: ASTPrimaryPrefix pp = (ASTPrimaryPrefix) ((ASTPrimaryExpression) expr
105: .jjtGetChild(0)).jjtGetChild(0);
106: String name = null;
107: if (pp.usesThisModifier()) {
108: ASTPrimarySuffix priSuf = expr
109: .getFirstChildOfType(ASTPrimarySuffix.class);
110: name = priSuf.getImage();
111: } else {
112: ASTName astName = (ASTName) pp
113: .jjtGetChild(0);
114: name = astName.getImage();
115: }
116: if (fieldDecls.containsKey(name)) {
117: violation = true;
118: }
119: }
120: }
121: if (violation) {
122: addViolation(data, ifStatement);
123: }
124: }
125: }
126: return super .visit(node, data);
127: }
128:
129: /**
130: * @return Map
131: */
132: protected Map<String, PropertyDescriptor> propertiesByName() {
133: return propertyDescriptorsByName;
134: }
135: }
|