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.Iterator;
    20  import java.util.List;
    21  import java.util.Map;
    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() + 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.hasImageEqualTo("readObject") && !node.hasImageEqualTo("writeObject") && !node.hasImageEqualTo("readResolve") && !node.hasImageEqualTo("writeReplace");
    95      }
    96  }