/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.java.rule.design; import java.util.List; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; public class SingletonClassReturningNewInstanceRule extends AbstractJavaRule { @Override public Object visit(ASTMethodDeclaration node, Object data) { boolean violation = false; String localVarName = null; String returnVariableName = null; if (node.getResultType().isVoid()) { return super.visit(node, data); } if ("getInstance".equals(node.getMethodName())) { List<ASTReturnStatement> rsl = node.findDescendantsOfType(ASTReturnStatement.class); if (rsl.isEmpty()) { return super.visit(node, data); } else { for (ASTReturnStatement rs : rsl) { List<ASTPrimaryExpression> pel = rs.findDescendantsOfType(ASTPrimaryExpression.class); ASTPrimaryExpression ape = pel.get(0); if (ape.getFirstDescendantOfType(ASTAllocationExpression.class) != null) { violation = true; break; } } } /* * public class Singleton { * * private static Singleton m_instance=null; * * public static Singleton getInstance() { * * Singleton m_instance=null; * * if ( m_instance == null ) { synchronized(Singleton.class) { * if(m_instance == null) { m_instance = new Singleton(); } } } * return m_instance; } } */ List<ASTBlockStatement> astBlockStatements = node.findDescendantsOfType(ASTBlockStatement.class); returnVariableName = getReturnVariableName(node); if (astBlockStatements.size() != 0) { for (ASTBlockStatement blockStatement : astBlockStatements) { if (blockStatement.hasDescendantOfType(ASTLocalVariableDeclaration.class)) { List<ASTLocalVariableDeclaration> lVarList = blockStatement .findDescendantsOfType(ASTLocalVariableDeclaration.class); if (!lVarList.isEmpty()) { for (ASTLocalVariableDeclaration localVar : lVarList) { localVarName = localVar.getVariableName(); if (returnVariableName != null && returnVariableName.equals(localVarName)) { violation = true; break; } } } } } } } if (violation) { addViolation(data, node); } return super.visit(node, data); } private String getReturnVariableName(ASTMethodDeclaration node) { List<ASTReturnStatement> rsl = node.findDescendantsOfType(ASTReturnStatement.class); ASTReturnStatement rs = rsl.get(0); List<ASTPrimaryExpression> pel = rs.findDescendantsOfType(ASTPrimaryExpression.class); ASTPrimaryExpression ape = pel.get(0); Node lastChild = ape.jjtGetChild(0); String returnVariableName = null; if (lastChild instanceof ASTPrimaryPrefix) { returnVariableName = getNameFromPrimaryPrefix((ASTPrimaryPrefix) lastChild); } /* * if(lastChild instanceof ASTPrimarySuffix){ returnVariableName = * getNameFromPrimarySuffix((ASTPrimarySuffix) lastChild); } */ return returnVariableName; } private String getNameFromPrimaryPrefix(ASTPrimaryPrefix pp) { if ((pp.jjtGetNumChildren() == 1) && (pp.jjtGetChild(0) instanceof ASTName)) { return ((ASTName) pp.jjtGetChild(0)).getImage(); } return null; } }