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  }