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.io.InvalidObjectException;
7   import java.io.ObjectInputStream;
8   import java.util.List;
9   import java.util.Map;
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.ASTFormalParameter;
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.ASTName;
18  import net.sourceforge.pmd.lang.java.ast.ASTNameList;
19  import net.sourceforge.pmd.lang.java.ast.ASTType;
20  import net.sourceforge.pmd.lang.java.ast.JavaNode;
21  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
22  import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence;
23  import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
24  import net.sourceforge.pmd.lang.rule.properties.BooleanProperty;
25  import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
26  
27  public class UnusedFormalParameterRule extends AbstractJavaRule {
28  
29      private static final BooleanProperty CHECKALL_DESCRIPTOR = new BooleanProperty("checkAll",
30              "Check all methods, including non-private ones", false, 1.0f);
31  
32      public UnusedFormalParameterRule() {
33          definePropertyDescriptor(CHECKALL_DESCRIPTOR);
34      }
35  
36      public Object visit(ASTConstructorDeclaration node, Object data) {
37          check(node, data);
38          return data;
39      }
40  
41      public Object visit(ASTMethodDeclaration node, Object data) {
42          if (!node.isPrivate() && !getProperty(CHECKALL_DESCRIPTOR)) {
43              return data;
44          }
45          if (!node.isNative() && !node.isAbstract() && !isSerializationMethod(node)) {
46              check(node, data);
47          }
48          return data;
49      }
50  
51      private boolean isSerializationMethod(ASTMethodDeclaration node) {
52          ASTMethodDeclarator declarator = node.getFirstDescendantOfType(ASTMethodDeclarator.class);
53          List<ASTFormalParameter> parameters = declarator.findDescendantsOfType(ASTFormalParameter.class);
54          if (node.isPrivate()
55              && "readObject".equals(node.getMethodName())
56              && parameters.size() == 1
57              && throwsOneException(node, InvalidObjectException.class)) {
58              ASTType type = parameters.get(0).getTypeNode();
59              if (type.getType() == ObjectInputStream.class
60                      || ObjectInputStream.class.getSimpleName().equals(type.getTypeImage())
61                      || ObjectInputStream.class.getName().equals(type.getTypeImage())) {
62                  return true;
63              }
64          }
65          return false;
66      }
67  
68      private boolean throwsOneException(ASTMethodDeclaration node, Class<? extends Throwable> exception) {
69          ASTNameList throwsList = node.getThrows();
70          if (throwsList != null && throwsList.jjtGetNumChildren() == 1) {
71              ASTName n = (ASTName)throwsList.jjtGetChild(0);
72              if (n.getType() == exception
73                  || exception.getSimpleName().equals(n.getImage())
74                  || exception.getName().equals(n.getImage())) {
75                  return true;
76              }
77          }
78          return false;
79      }
80  
81      private void check(Node node, Object data) {
82          Node parent = node.jjtGetParent().jjtGetParent().jjtGetParent();
83          if (parent instanceof ASTClassOrInterfaceDeclaration
84                  && !((ASTClassOrInterfaceDeclaration) parent).isInterface()) {
85              Map<VariableNameDeclaration, List<NameOccurrence>> vars = ((JavaNode) node).getScope().getDeclarations(
86                      VariableNameDeclaration.class);
87              for (Map.Entry<VariableNameDeclaration, List<NameOccurrence>> entry : vars.entrySet()) {
88                  VariableNameDeclaration nameDecl = entry.getKey();
89                  if (actuallyUsed(nameDecl, entry.getValue())) {
90                      continue;
91                  }
92                  addViolation(data, nameDecl.getNode(), new Object[] {
93                          node instanceof ASTMethodDeclaration ? "method" : "constructor", nameDecl.getImage() });
94              }
95          }
96      }
97  
98      private boolean actuallyUsed(VariableNameDeclaration nameDecl, List<NameOccurrence> usages) {
99          for (NameOccurrence occ : usages) {
100             JavaNameOccurrence jocc = (JavaNameOccurrence) occ;
101             if (jocc.isOnLeftHandSide()) {
102                 if (nameDecl.isArray() && jocc.getLocation().jjtGetParent().jjtGetParent().jjtGetNumChildren() > 1) {
103                     // array element access
104                     return true;
105                 }
106                 continue;
107             } else {
108                 return true;
109             }
110         }
111         return false;
112     }
113 }