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.unusedcode;
5   
6   import java.util.HashSet;
7   import java.util.List;
8   import java.util.Map;
9   import java.util.Set;
10  
11  import net.sourceforge.pmd.lang.ast.Node;
12  import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
13  import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
14  import net.sourceforge.pmd.lang.java.ast.ASTInitializer;
15  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
16  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;
17  import net.sourceforge.pmd.lang.java.ast.AccessNode;
18  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
19  import net.sourceforge.pmd.lang.java.symboltable.ClassScope;
20  import net.sourceforge.pmd.lang.java.symboltable.MethodNameDeclaration;
21  import net.sourceforge.pmd.lang.java.symboltable.NameOccurrence;
22  
23  public class UnusedPrivateMethodRule extends AbstractJavaRule {
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              Node 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  }