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  }