1
2
3
4 package net.sourceforge.pmd.lang.java.rule.unusedcode;
5
6 import java.util.ArrayList;
7 import java.util.List;
8 import java.util.Map;
9
10 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody;
11 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
12 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
13 import net.sourceforge.pmd.lang.java.ast.ASTEnumBody;
14 import net.sourceforge.pmd.lang.java.ast.ASTEnumConstant;
15 import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;
16 import net.sourceforge.pmd.lang.java.ast.ASTName;
17 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
18 import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
19 import net.sourceforge.pmd.lang.java.ast.AccessNode;
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.symboltable.NameDeclaration;
25 import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
26
27 public class UnusedPrivateFieldRule extends AbstractJavaRule {
28
29 @Override
30 public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
31 Map<VariableNameDeclaration, List<NameOccurrence>> vars = node.getScope().getDeclarations(
32 VariableNameDeclaration.class);
33 for (Map.Entry<VariableNameDeclaration, List<NameOccurrence>> entry : vars.entrySet()) {
34 VariableNameDeclaration decl = entry.getKey();
35 AccessNode accessNodeParent = decl.getAccessNodeParent();
36 if (!accessNodeParent.isPrivate() || isOK(decl.getImage())) {
37 continue;
38 }
39 if (!actuallyUsed(entry.getValue())) {
40 if (!usedInOuterClass(node, decl) && !usedInOuterEnum(node, decl)) {
41 addViolation(data, decl.getNode(), decl.getImage());
42 }
43 }
44 }
45 return super.visit(node, data);
46 }
47
48 private boolean usedInOuterEnum(ASTClassOrInterfaceDeclaration node, NameDeclaration decl) {
49 List<ASTEnumDeclaration> outerEnums = node.getParentsOfType(ASTEnumDeclaration.class);
50 for (ASTEnumDeclaration outerEnum : outerEnums) {
51 ASTEnumBody enumBody = outerEnum.getFirstChildOfType(ASTEnumBody.class);
52 if (usedInOuter(decl, enumBody)) {
53 return true;
54 }
55 }
56 return false;
57 }
58
59
60
61
62 private boolean usedInOuterClass(ASTClassOrInterfaceDeclaration node, NameDeclaration decl) {
63 List<ASTClassOrInterfaceDeclaration> outerClasses = node.getParentsOfType(ASTClassOrInterfaceDeclaration.class);
64 for (ASTClassOrInterfaceDeclaration outerClass : outerClasses) {
65 ASTClassOrInterfaceBody classOrInterfaceBody = outerClass.getFirstChildOfType(ASTClassOrInterfaceBody.class);
66 if (usedInOuter(decl, classOrInterfaceBody)) {
67 return true;
68 }
69 }
70 return false;
71 }
72
73 private boolean usedInOuter(NameDeclaration decl, JavaNode body) {
74 List<ASTClassOrInterfaceBodyDeclaration> classOrInterfaceBodyDeclarations = body
75 .findChildrenOfType(ASTClassOrInterfaceBodyDeclaration.class);
76 List<ASTEnumConstant> enumConstants = body
77 .findChildrenOfType(ASTEnumConstant.class);
78 List<JavaNode> nodes = new ArrayList<JavaNode>();
79 nodes.addAll(classOrInterfaceBodyDeclarations);
80 nodes.addAll(enumConstants);
81
82 for (JavaNode node : nodes) {
83 List<ASTPrimarySuffix> primarySuffixes = node.findDescendantsOfType(ASTPrimarySuffix.class);
84 for (ASTPrimarySuffix primarySuffix : primarySuffixes) {
85 if (decl.getImage().equals(primarySuffix.getImage())) {
86 return true;
87 }
88 }
89
90 List<ASTPrimaryPrefix> primaryPrefixes = node.findDescendantsOfType(ASTPrimaryPrefix.class);
91 for (ASTPrimaryPrefix primaryPrefix : primaryPrefixes) {
92 ASTName name = primaryPrefix.getFirstDescendantOfType(ASTName.class);
93
94 if (name != null) {
95 for (String id : name.getImage().split("\\.")) {
96 if (id.equals(decl.getImage())) {
97 return true;
98 }
99 }
100 }
101 }
102 }
103 return false;
104 }
105
106 private boolean actuallyUsed(List<NameOccurrence> usages) {
107 for (NameOccurrence nameOccurrence : usages) {
108 JavaNameOccurrence jNameOccurrence = (JavaNameOccurrence) nameOccurrence;
109 if (!jNameOccurrence.isOnLeftHandSide()) {
110 return true;
111 }
112 }
113
114 return false;
115 }
116
117 private boolean isOK(String image) {
118 return image.equals("serialVersionUID") || image.equals("serialPersistentFields") || image.equals("IDENT");
119 }
120 }