View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.rules;
5   
6   import java.util.ArrayList;
7   import java.util.List;
8   import java.util.Map;
9   
10  import net.sourceforge.pmd.AbstractRule;
11  import net.sourceforge.pmd.ast.ASTClassOrInterfaceBody;
12  import net.sourceforge.pmd.ast.ASTClassOrInterfaceBodyDeclaration;
13  import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
14  import net.sourceforge.pmd.ast.ASTName;
15  import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
16  import net.sourceforge.pmd.ast.ASTPrimarySuffix;
17  import net.sourceforge.pmd.symboltable.NameOccurrence;
18  import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
19  
20  public class UnusedPrivateFieldRule extends AbstractRule {
21  
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 = new ArrayList<ASTClassOrInterfaceBodyDeclaration>();
48  			classOrInterfaceBody.findChildrenOfType(ASTClassOrInterfaceBodyDeclaration.class, classOrInterfaceBodyDeclarations, false);
49  			
50  			for (ASTClassOrInterfaceBodyDeclaration classOrInterfaceBodyDeclaration : classOrInterfaceBodyDeclarations) {
51  				for (int i = 0; i < classOrInterfaceBodyDeclaration.jjtGetNumChildren(); i++) {
52  					if (classOrInterfaceBodyDeclaration.jjtGetChild(i) instanceof ASTClassOrInterfaceDeclaration) {
53  						continue;	//Skip other inner classes
54  					}
55  					
56  					List<ASTPrimarySuffix> primarySuffixes = classOrInterfaceBodyDeclaration.findChildrenOfType(ASTPrimarySuffix.class);
57  					for (ASTPrimarySuffix primarySuffix : primarySuffixes) {
58  						if (decl.getImage().equals(primarySuffix.getImage())) {
59  							return true; //No violation
60  						}
61  					}
62  					
63  					List<ASTPrimaryPrefix> primaryPrefixes = classOrInterfaceBodyDeclaration.findChildrenOfType(ASTPrimaryPrefix.class);
64  					for (ASTPrimaryPrefix primaryPrefix : primaryPrefixes) {
65  						ASTName name = primaryPrefix.getFirstChildOfType(ASTName.class);
66  						
67  						if (name != null && name.getImage().endsWith(decl.getImage())) {
68  							return true; //No violation
69  						}
70  					}
71  				}
72  			}
73  			
74  		}
75  		
76  		return false;
77  	}
78  
79      private boolean actuallyUsed(List<NameOccurrence> usages) {
80          for (NameOccurrence nameOccurrence: usages) {
81              if (!nameOccurrence.isOnLeftHandSide()) {
82                  return true;
83              }
84          }
85          
86          return false;
87      }
88  
89      private boolean isOK(String image) {
90          return image.equals("serialVersionUID") || image.equals("serialPersistentFields") || image.equals("IDENT");
91      }
92  }