UnusedPrivateFieldRule.java
01 /**
02  * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
03  */
04 package net.sourceforge.pmd.lang.java.rule.unusedcode;
05 
06 import java.util.List;
07 import java.util.Map;
08 
09 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody;
10 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
11 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
12 import net.sourceforge.pmd.lang.java.ast.ASTName;
13 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
14 import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
15 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
16 import net.sourceforge.pmd.lang.java.symboltable.NameOccurrence;
17 import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
18 
19 public class UnusedPrivateFieldRule extends AbstractJavaRule {
20 
21     @Override
22     public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
23         Map<VariableNameDeclaration, List<NameOccurrence>> vars = node.getScope().getVariableDeclarations();
24         for (Map.Entry<VariableNameDeclaration, List<NameOccurrence>> entry: vars.entrySet()) {
25             VariableNameDeclaration decl = entry.getKey();
26             if (!decl.getAccessNodeParent().isPrivate() || isOK(decl.getImage())) {
27                 continue;
28             }
29             if (!actuallyUsed(entry.getValue())) {
30               if (!usedInOuterClass(node, decl)) {
31                 addViolation(data, decl.getNode(), decl.getImage());
32               }
33             }
34         }
35         return super.visit(node, data);
36     }
37 
38     /**
39      * Find out whether the variable is used in an outer class
40      */
41   private boolean usedInOuterClass(ASTClassOrInterfaceDeclaration node,
42       VariableNameDeclaration decl) {
43     List<ASTClassOrInterfaceDeclaration> outerClasses = node.getParentsOfType(ASTClassOrInterfaceDeclaration.class);
44     for (ASTClassOrInterfaceDeclaration outerClass : outerClasses) {
45       ASTClassOrInterfaceBody classOrInterfaceBody = outerClass.getFirstChildOfType(ASTClassOrInterfaceBody.class);
46 
47       List<ASTClassOrInterfaceBodyDeclaration> classOrInterfaceBodyDeclarations = classOrInterfaceBody.findChildrenOfType(ASTClassOrInterfaceBodyDeclaration.class);
48 
49       for (ASTClassOrInterfaceBodyDeclaration classOrInterfaceBodyDeclaration : classOrInterfaceBodyDeclarations) {
50         for (int i = 0; i < classOrInterfaceBodyDeclaration.jjtGetNumChildren(); i++) {
51           if (classOrInterfaceBodyDeclaration.jjtGetChild(iinstanceof ASTClassOrInterfaceDeclaration) {
52             continue;  //Skip other inner classes
53           }
54 
55           List<ASTPrimarySuffix> primarySuffixes = classOrInterfaceBodyDeclaration.findDescendantsOfType(ASTPrimarySuffix.class);
56           for (ASTPrimarySuffix primarySuffix : primarySuffixes) {
57             if (decl.getImage().equals(primarySuffix.getImage())) {
58               return true//No violation
59             }
60           }
61 
62           List<ASTPrimaryPrefix> primaryPrefixes = classOrInterfaceBodyDeclaration.findDescendantsOfType(ASTPrimaryPrefix.class);
63           for (ASTPrimaryPrefix primaryPrefix : primaryPrefixes) {
64             ASTName name = primaryPrefix.getFirstDescendantOfType(ASTName.class);
65 
66             if (name != null && name.getImage().endsWith(decl.getImage())) {
67               return true//No violation
68             }
69           }
70         }
71       }
72 
73     }
74 
75     return false;
76   }
77 
78     private boolean actuallyUsed(List<NameOccurrence> usages) {
79         for (NameOccurrence nameOccurrence: usages) {
80             if (!nameOccurrence.isOnLeftHandSide()) {
81                 return true;
82             }
83         }
84 
85         return false;
86     }
87 
88     private boolean isOK(String image) {
89         return image.equals("serialVersionUID"|| image.equals("serialPersistentFields"|| image.equals("IDENT");
90     }
91 }