View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.rule.design;
5   
6   import java.util.List;
7   
8   import net.sourceforge.pmd.lang.ast.Node;
9   import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
10  import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
11  import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
12  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
13  import net.sourceforge.pmd.lang.java.ast.ASTName;
14  import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
15  import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
16  import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
17  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
18  
19  public class SingletonClassReturningNewInstanceRule extends AbstractJavaRule {
20  
21      @Override
22      public Object visit(ASTMethodDeclaration node, Object data) {
23  
24          boolean violation = false;
25          String localVarName = null;
26          String returnVariableName = null;
27  
28          if (node.getResultType().isVoid()) {
29              return super.visit(node, data);
30          }
31  
32          if ("getInstance".equals(node.getMethodName())) {
33              List<ASTReturnStatement> rsl = node.findDescendantsOfType(ASTReturnStatement.class);
34              if (rsl.isEmpty()) {
35                  return super.visit(node, data);
36              } else {
37                  for (ASTReturnStatement rs : rsl) {
38  
39                      List<ASTPrimaryExpression> pel = rs.findDescendantsOfType(ASTPrimaryExpression.class);
40                      ASTPrimaryExpression ape = pel.get(0);
41                      if (ape.getFirstDescendantOfType(ASTAllocationExpression.class) != null) {
42                          violation = true;
43                          break;
44                      }
45                  }
46              }
47  
48              /*
49               * public class Singleton {
50               * 
51               * private static Singleton m_instance=null;
52               * 
53               * public static Singleton getInstance() {
54               * 
55               * Singleton m_instance=null;
56               * 
57               * if ( m_instance == null ) { synchronized(Singleton.class) {
58               * if(m_instance == null) { m_instance = new Singleton(); } } }
59               * return m_instance; } }
60               */
61  
62              List<ASTBlockStatement> ASTBlockStatements = node.findDescendantsOfType(ASTBlockStatement.class);
63              returnVariableName = getReturnVariableName(node);
64              if (ASTBlockStatements.size() != 0) {
65                  for (ASTBlockStatement blockStatement : ASTBlockStatements) {
66                      if (blockStatement.hasDescendantOfType(ASTLocalVariableDeclaration.class)) {
67                          List<ASTLocalVariableDeclaration> lVarList = blockStatement
68                                  .findDescendantsOfType(ASTLocalVariableDeclaration.class);
69                          if (!lVarList.isEmpty()) {
70                              for (ASTLocalVariableDeclaration localVar : lVarList) {
71                                  localVarName = localVar.getVariableName();
72                                  if (returnVariableName != null && returnVariableName.equals(localVarName)) {
73                                      violation = true;
74                                      break;
75                                  }
76                              }
77                          }
78                      }
79                  }
80              }
81          }
82          if (violation) {
83              addViolation(data, node);
84          }
85          return super.visit(node, data);
86      }
87  
88      private String getReturnVariableName(ASTMethodDeclaration node) {
89  
90          List<ASTReturnStatement> rsl = node.findDescendantsOfType(ASTReturnStatement.class);
91          ASTReturnStatement rs = rsl.get(0);
92          List<ASTPrimaryExpression> pel = rs.findDescendantsOfType(ASTPrimaryExpression.class);
93          ASTPrimaryExpression ape = pel.get(0);
94          Node lastChild = ape.jjtGetChild(0);
95          String returnVariableName = null;
96          if (lastChild instanceof ASTPrimaryPrefix) {
97              returnVariableName = getNameFromPrimaryPrefix((ASTPrimaryPrefix) lastChild);
98          }
99          /*
100          * if(lastChild instanceof ASTPrimarySuffix){ returnVariableName =
101          * getNameFromPrimarySuffix((ASTPrimarySuffix) lastChild); }
102          */
103         return returnVariableName;
104 
105     }
106 
107     private String getNameFromPrimaryPrefix(ASTPrimaryPrefix pp) {
108         if ((pp.jjtGetNumChildren() == 1) && (pp.jjtGetChild(0) instanceof ASTName)) {
109             return ((ASTName) pp.jjtGetChild(0)).getImage();
110         }
111         return null;
112     }
113 }