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.HashSet;
19  import java.util.List;
20  import java.util.Map;
21  import java.util.Set;
22  
23  public class UnusedPrivateMethodRule extends AbstractRule {
24  
25  
26      public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
27          if (node.isInterface()) {
28              return data;
29          }
30  
31          Map<MethodNameDeclaration, List<NameOccurrence>> methods = ((ClassScope) node.getScope()).getMethodDeclarations();
32          for (MethodNameDeclaration mnd: findUnique(methods)) {
33              List<NameOccurrence> occs = methods.get(mnd);
34              if (!privateAndNotExcluded(mnd)) {
35                  continue;
36              }
37              if (occs.isEmpty()) {
38                  addViolation(data, mnd.getNode(), mnd.getImage() + mnd.getParameterDisplaySignature());
39              } else {
40                  if (calledFromOutsideItself(occs, mnd)) {
41                      addViolation(data, mnd.getNode(), mnd.getImage() + mnd.getParameterDisplaySignature());
42                  }
43  
44              }
45          }
46          return data;
47      }
48  
49      private Set<MethodNameDeclaration> findUnique(Map<MethodNameDeclaration, List<NameOccurrence>> methods) {
50          // some rather hideous hackery here
51          // to work around the fact that PMD does not yet do full type analysis
52          // when it does, delete this
53          Set<MethodNameDeclaration> unique = new HashSet<MethodNameDeclaration>();
54          Set<String> sigs = new HashSet<String>();
55          for (MethodNameDeclaration mnd: methods.keySet()) {
56              String sig = mnd.getImage() + mnd.getParameterCount() + mnd.isVarargs();
57              if (!sigs.contains(sig)) {
58                  unique.add(mnd);
59              }
60              sigs.add(sig);
61          }
62          return unique;
63      }
64  
65      private boolean calledFromOutsideItself(List<NameOccurrence> occs, MethodNameDeclaration mnd) {
66          int callsFromOutsideMethod = 0;
67          for (NameOccurrence occ: occs) {
68              SimpleNode occNode = occ.getLocation();
69              ASTConstructorDeclaration enclosingConstructor = occNode.getFirstParentOfType(ASTConstructorDeclaration.class);
70              if (enclosingConstructor != null) {
71                  callsFromOutsideMethod++;
72                  break; // Do we miss unused private constructors here?
73              }
74              ASTInitializer enclosingInitializer = occNode.getFirstParentOfType(ASTInitializer.class);
75              if (enclosingInitializer != null) {
76                  callsFromOutsideMethod++;
77                  break;
78              }
79  
80              ASTMethodDeclaration enclosingMethod = occNode.getFirstParentOfType(ASTMethodDeclaration.class);
81              if (enclosingMethod == null || !mnd.getNode().jjtGetParent().equals(enclosingMethod)) {
82                  callsFromOutsideMethod++;
83              }
84          }
85          return callsFromOutsideMethod == 0;
86      }
87  
88      private boolean privateAndNotExcluded(MethodNameDeclaration mnd) {
89          ASTMethodDeclarator node = (ASTMethodDeclarator) mnd.getNode();
90          return ((AccessNode) node.jjtGetParent()).isPrivate() && !node.hasImageEqualTo("readObject") && !node.hasImageEqualTo("writeObject") && !node.hasImageEqualTo("readResolve") && !node.hasImageEqualTo("writeReplace");
91      }
92  }