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