001: /**
002: * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003: */package net.sourceforge.pmd.rules;
004:
005: import java.util.ArrayList;
006: import java.util.List;
007: import java.util.Map;
008:
009: import net.sourceforge.pmd.AbstractRule;
010: import net.sourceforge.pmd.ast.ASTClassOrInterfaceBody;
011: import net.sourceforge.pmd.ast.ASTClassOrInterfaceBodyDeclaration;
012: import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
013: import net.sourceforge.pmd.ast.ASTName;
014: import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
015: import net.sourceforge.pmd.ast.ASTPrimarySuffix;
016: import net.sourceforge.pmd.symboltable.NameOccurrence;
017: import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
018:
019: public class UnusedPrivateFieldRule extends AbstractRule {
020:
021: public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
022: Map<VariableNameDeclaration, List<NameOccurrence>> vars = node
023: .getScope().getVariableDeclarations();
024: for (Map.Entry<VariableNameDeclaration, List<NameOccurrence>> entry : vars
025: .entrySet()) {
026: VariableNameDeclaration decl = entry.getKey();
027: if (!decl.getAccessNodeParent().isPrivate()
028: || isOK(decl.getImage())) {
029: continue;
030: }
031: if (!actuallyUsed(entry.getValue())) {
032: if (!usedInOuterClass(node, decl)) {
033: addViolation(data, decl.getNode(), decl.getImage());
034: }
035: }
036: }
037: return super .visit(node, data);
038: }
039:
040: /**
041: * Find out whether the variable is used in an outer class
042: */
043: private boolean usedInOuterClass(
044: ASTClassOrInterfaceDeclaration node,
045: VariableNameDeclaration decl) {
046: List<ASTClassOrInterfaceDeclaration> outerClasses = node
047: .getParentsOfType(ASTClassOrInterfaceDeclaration.class);
048: for (ASTClassOrInterfaceDeclaration outerClass : outerClasses) {
049: ASTClassOrInterfaceBody classOrInterfaceBody = outerClass
050: .getFirstChildOfType(ASTClassOrInterfaceBody.class);
051:
052: List<ASTClassOrInterfaceBodyDeclaration> classOrInterfaceBodyDeclarations = new ArrayList<ASTClassOrInterfaceBodyDeclaration>();
053: classOrInterfaceBody.findChildrenOfType(
054: ASTClassOrInterfaceBodyDeclaration.class,
055: classOrInterfaceBodyDeclarations, false);
056:
057: for (ASTClassOrInterfaceBodyDeclaration classOrInterfaceBodyDeclaration : classOrInterfaceBodyDeclarations) {
058: for (int i = 0; i < classOrInterfaceBodyDeclaration
059: .jjtGetNumChildren(); i++) {
060: if (classOrInterfaceBodyDeclaration.jjtGetChild(i) instanceof ASTClassOrInterfaceDeclaration) {
061: continue; //Skip other inner classes
062: }
063:
064: List<ASTPrimarySuffix> primarySuffixes = classOrInterfaceBodyDeclaration
065: .findChildrenOfType(ASTPrimarySuffix.class);
066: for (ASTPrimarySuffix primarySuffix : primarySuffixes) {
067: if (decl.getImage().equals(
068: primarySuffix.getImage())) {
069: return true; //No violation
070: }
071: }
072:
073: List<ASTPrimaryPrefix> primaryPrefixes = classOrInterfaceBodyDeclaration
074: .findChildrenOfType(ASTPrimaryPrefix.class);
075: for (ASTPrimaryPrefix primaryPrefix : primaryPrefixes) {
076: ASTName name = primaryPrefix
077: .getFirstChildOfType(ASTName.class);
078:
079: if (name != null
080: && name.getImage().endsWith(
081: decl.getImage())) {
082: return true; //No violation
083: }
084: }
085: }
086: }
087:
088: }
089:
090: return false;
091: }
092:
093: private boolean actuallyUsed(List<NameOccurrence> usages) {
094: for (NameOccurrence nameOccurrence : usages) {
095: if (!nameOccurrence.isOnLeftHandSide()) {
096: return true;
097: }
098: }
099:
100: return false;
101: }
102:
103: private boolean isOK(String image) {
104: return image.equals("serialVersionUID")
105: || image.equals("serialPersistentFields")
106: || image.equals("IDENT");
107: }
108: }
|