View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.rule.unusedcode;
5   
6   import java.util.List;
7   import java.util.Map;
8   
9   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(i) instanceof 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  }