1
2
3
4 package net.sourceforge.pmd.lang.java.rule.unusedcode;
5
6 import java.util.HashSet;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
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.ASTInitializer;
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.AccessNode;
18 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
19 import net.sourceforge.pmd.lang.java.symboltable.ClassScope;
20 import net.sourceforge.pmd.lang.java.symboltable.MethodNameDeclaration;
21 import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
22 import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
23
24 public class UnusedPrivateMethodRule extends AbstractJavaRule {
25
26
27 public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
28 if (node.isInterface()) {
29 return data;
30 }
31
32 Map<MethodNameDeclaration, List<NameOccurrence>> methods = node.getScope().getEnclosingScope(ClassScope.class).getMethodDeclarations();
33 for (MethodNameDeclaration mnd: findUnique(methods)) {
34 List<NameOccurrence> occs = methods.get(mnd);
35 if (!privateAndNotExcluded(mnd)) {
36 continue;
37 }
38 if (occs.isEmpty()) {
39 addViolation(data, mnd.getNode(), mnd.getImage() + mnd.getParameterDisplaySignature());
40 } else {
41 if (calledFromOutsideItself(occs, mnd)) {
42 addViolation(data, mnd.getNode(), mnd.getImage() + mnd.getParameterDisplaySignature());
43 }
44
45 }
46 }
47 return data;
48 }
49
50 private Set<MethodNameDeclaration> findUnique(Map<MethodNameDeclaration, List<NameOccurrence>> methods) {
51
52
53
54 Set<MethodNameDeclaration> unique = new HashSet<MethodNameDeclaration>();
55 Set<String> sigs = new HashSet<String>();
56 for (MethodNameDeclaration mnd: methods.keySet()) {
57 String sig = mnd.getImage() + mnd.getParameterCount() + mnd.isVarargs();
58 if (!sigs.contains(sig)) {
59 unique.add(mnd);
60 }
61 sigs.add(sig);
62 }
63 return unique;
64 }
65
66 private boolean calledFromOutsideItself(List<NameOccurrence> occs, NameDeclaration mnd) {
67 int callsFromOutsideMethod = 0;
68 for (NameOccurrence occ: occs) {
69 Node occNode = occ.getLocation();
70 ASTConstructorDeclaration enclosingConstructor = occNode.getFirstParentOfType(ASTConstructorDeclaration.class);
71 if (enclosingConstructor != null) {
72 callsFromOutsideMethod++;
73 break;
74 }
75 ASTInitializer enclosingInitializer = occNode.getFirstParentOfType(ASTInitializer.class);
76 if (enclosingInitializer != null) {
77 callsFromOutsideMethod++;
78 break;
79 }
80
81 ASTMethodDeclaration enclosingMethod = occNode.getFirstParentOfType(ASTMethodDeclaration.class);
82 if (enclosingMethod == null || !mnd.getNode().jjtGetParent().equals(enclosingMethod)) {
83 callsFromOutsideMethod++;
84 }
85 }
86 return callsFromOutsideMethod == 0;
87 }
88
89 private boolean privateAndNotExcluded(NameDeclaration mnd) {
90 ASTMethodDeclarator node = (ASTMethodDeclarator) mnd.getNode();
91 return ((AccessNode) node.jjtGetParent()).isPrivate() && !node.hasImageEqualTo("readObject") && !node.hasImageEqualTo("writeObject") && !node.hasImageEqualTo("readResolve") && !node.hasImageEqualTo("writeReplace");
92 }
93 }