1
2
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
104 return true;
105 }
106 continue;
107 } else {
108 return true;
109 }
110 }
111 return false;
112 }
113 }