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  }