View Javadoc

1   /***
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.rules;
5   
6   import net.sourceforge.pmd.AbstractRule;
7   import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
8   import net.sourceforge.pmd.ast.ASTConstructorDeclaration;
9   import net.sourceforge.pmd.ast.ASTInitializer;
10  import net.sourceforge.pmd.ast.ASTMethodDeclaration;
11  import net.sourceforge.pmd.ast.ASTMethodDeclarator;
12  import net.sourceforge.pmd.ast.AccessNode;
13  import net.sourceforge.pmd.ast.SimpleNode;
14  import net.sourceforge.pmd.symboltable.ClassScope;
15  import net.sourceforge.pmd.symboltable.MethodNameDeclaration;
16  import net.sourceforge.pmd.symboltable.NameOccurrence;
17  
18  import java.util.Iterator;
19  import java.util.List;
20  import java.util.Map;
21  import java.util.HashSet;
22  import java.util.Set;
23  
24  public class UnusedPrivateMethodRule extends AbstractRule {
25  
26  
27      public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
28          if (node.isInterface()) {
29              return data;
30          }
31  
32          Map methods = ((ClassScope) node.getScope()).getMethodDeclarations();
33          for (Iterator i = findUnique(methods).iterator(); i.hasNext();) {
34              MethodNameDeclaration mnd = (MethodNameDeclaration) i.next();
35              List occs = (List) methods.get(mnd);
36              if (!privateAndNotExcluded(mnd)) {
37                  continue;
38              }
39              if (occs.isEmpty()) {
40                  addViolation(data, mnd.getNode(), mnd.getImage() + mnd.getParameterDisplaySignature());
41              } else {
42                  if (calledFromOutsideItself(occs, mnd)) {
43                      addViolation(data, mnd.getNode(), mnd.getImage() + mnd.getParameterDisplaySignature());
44                  }
45  
46              }
47          }
48          return data;
49      }
50  
51      private Set findUnique(Map methods) {
52          // some rather hideous hackery here
53          // to work around the fact that PMD does not yet do full type analysis
54          // when it does, delete this
55          Set unique = new HashSet();
56          Set sigs = new HashSet();
57          for (Iterator i = methods.keySet().iterator(); i.hasNext();) {
58              MethodNameDeclaration mnd = (MethodNameDeclaration) i.next();
59              String sig = mnd.getImage() + String.valueOf(mnd.getParameterCount());
60              if (!sigs.contains(sig)) {
61                  unique.add(mnd);
62              }
63              sigs.add(sig);
64          }
65          return unique;
66      }
67  
68      private boolean calledFromOutsideItself(List occs, MethodNameDeclaration mnd) {
69          int callsFromOutsideMethod = 0;
70          for (Iterator i = occs.iterator(); i.hasNext();) {
71              NameOccurrence occ = (NameOccurrence) i.next();
72              SimpleNode occNode = occ.getLocation();
73              ASTConstructorDeclaration enclosingConstructor = (ASTConstructorDeclaration) occNode.getFirstParentOfType(ASTConstructorDeclaration.class);
74              if (enclosingConstructor != null) {
75                  callsFromOutsideMethod++;
76                  break; // Do we miss unused private constructors here?
77              }
78              ASTInitializer enclosingInitializer = (ASTInitializer) occNode.getFirstParentOfType(ASTInitializer.class);
79              if (enclosingInitializer != null) {
80                  callsFromOutsideMethod++;
81                  break;
82              }
83  
84              ASTMethodDeclaration enclosingMethod = (ASTMethodDeclaration) occNode.getFirstParentOfType(ASTMethodDeclaration.class);
85              if ((enclosingMethod == null) || (enclosingMethod != null && !mnd.getNode().jjtGetParent().equals(enclosingMethod))) {
86                  callsFromOutsideMethod++;
87              }
88          }
89          return callsFromOutsideMethod == 0;
90      }
91  
92      private boolean privateAndNotExcluded(MethodNameDeclaration mnd) {
93          ASTMethodDeclarator node = (ASTMethodDeclarator) mnd.getNode();
94          return ((AccessNode) node.jjtGetParent()).isPrivate() && !node.getImage().equals("readObject") && !node.getImage().equals("writeObject") && !node.getImage().equals("readResolve") && !node.getImage().equals("writeReplace");
95      }
96  }