View Javadoc

    1   package net.sourceforge.pmd.lang.java.rule.basic;
    2
    3   import java.util.List;
    4
    5   import net.sourceforge.pmd.lang.ast.Node;
    6   import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
    7   import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
    8   import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
    9   import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;
    10  import net.sourceforge.pmd.lang.java.ast.ASTImplementsList;
    11  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;
    12  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
    13
    14  public class OverrideBothEqualsAndHashcodeRule extends AbstractJavaRule {
    15
    16      private boolean implementsComparable = false;
    17
    18      private boolean containsEquals = false;
    19
    20      private boolean containsHashCode = false;
    21
    22      private Node nodeFound = null;
    23
    24      @Override
    25      public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
    26  	if (node.isInterface()) {
    27  	    return data;
    28  	}
    29  	super.visit(node, data);
    30  	if (!implementsComparable && containsEquals ^ containsHashCode) {
    31  	    if (nodeFound == null) {
    32  		nodeFound = node;
    33  	    }
    34  	    addViolation(data, nodeFound);
    35  	}
    36  	implementsComparable = containsEquals = containsHashCode = false;
    37  	nodeFound = null;
    38  	return data;
    39      }
    40
    41      @Override
    42      public Object visit(ASTImplementsList node, Object data) {
    43  	for (int ix = 0; ix < node.jjtGetNumChildren(); ix++) {
    44  	    if (node.jjtGetChild(ix) instanceof ASTClassOrInterfaceType) {
    45  		ASTClassOrInterfaceType cit = (ASTClassOrInterfaceType) node.jjtGetChild(ix);
    46  		Class<?> clazz = cit.getType();
    47  		if (clazz != null || node.jjtGetChild(ix).hasImageEqualTo("Comparable")) {
    48  		    implementsComparable = true;
    49  		    return data;
    50  		}
    51  	    }
    52  	}
    53  	return super.visit(node, data);
    54      }
    55
    56      @Override
    57      public Object visit(ASTMethodDeclarator node, Object data) {
    58  	if (implementsComparable) {
    59  	    return data;
    60  	}
    61
    62  	int iFormalParams = 0;
    63  	String paramName = null;
    64  	for (int ix = 0; ix < node.jjtGetNumChildren(); ix++) {
    65  	    Node sn = node.jjtGetChild(ix);
    66  	    if (sn instanceof ASTFormalParameters) {
    67  		List<ASTFormalParameter> allParams = ((ASTFormalParameters) sn)
    68  			.findChildrenOfType(ASTFormalParameter.class);
    69  		for (ASTFormalParameter formalParam : allParams) {
    70  		    iFormalParams++;
    71  		    ASTClassOrInterfaceType param = formalParam.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
    72  		    if (param != null) {
    73  			paramName = param.getImage();
    74  		    }
    75  		}
    76  	    }
    77  	}
    78
    79  	if (iFormalParams == 0 && node.hasImageEqualTo("hashCode")) {
    80  	    containsHashCode = true;
    81  	    nodeFound = node;
    82  	} else if (iFormalParams == 1 && node.hasImageEqualTo("equals")
    83  		&& ("Object".equals(paramName) || "java.lang.Object".equals(paramName))) {
    84  	    containsEquals = true;
    85  	    nodeFound = node;
    86  	}
    87  	return super.visit(node, data);
    88      }
    89
    90  }