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