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 net.sourceforge.pmd.AbstractRule;
    7   import net.sourceforge.pmd.ast.ASTArgumentList;
    8   import net.sourceforge.pmd.ast.ASTArguments;
    9   import net.sourceforge.pmd.ast.ASTBlock;
    10  import net.sourceforge.pmd.ast.ASTClassOrInterfaceBodyDeclaration;
    11  import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
    12  import net.sourceforge.pmd.ast.ASTFormalParameter;
    13  import net.sourceforge.pmd.ast.ASTFormalParameters;
    14  import net.sourceforge.pmd.ast.ASTMethodDeclaration;
    15  import net.sourceforge.pmd.ast.ASTMethodDeclarator;
    16  import net.sourceforge.pmd.ast.ASTName;
    17  import net.sourceforge.pmd.ast.ASTPrimaryExpression;
    18  import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
    19  import net.sourceforge.pmd.ast.ASTPrimarySuffix;
    20  import net.sourceforge.pmd.ast.ASTStatement;
    21  import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
    22  import net.sourceforge.pmd.ast.Node;
    23  import net.sourceforge.pmd.ast.SimpleNode;
    24
    25  import java.util.ArrayList;
    26  import java.util.List;
    27
    28  public class UselessOverridingMethod extends AbstractRule {
    29
    30      public Object visit(ASTClassOrInterfaceDeclaration clz, Object data) {
    31          if (clz.isInterface()) {
    32              return data;
    33          }
    34          return super.visit(clz, data);
    35      }
    36
    37      public Object visit(ASTMethodDeclaration node, Object data) {
    38          // Can skip abstract methods and methods whose only purpose is to
    39          // guarantee that the inherited method is not changed by finalizing
    40          // them.
    41          if (node.isAbstract() || node.isFinal() || node.isNative()) {
    42              return super.visit(node, data);
    43          }
    44
    45          ASTBlock block = node.getBlock();
    46          //Only process functions with one BlockStatement
    47          if (block.jjtGetNumChildren() != 1 || block.findChildrenOfType(ASTStatement.class).size() != 1)
    48              return super.visit(node, data);
    49
    50          ASTStatement statement = (ASTStatement) block.jjtGetChild(0).jjtGetChild(0);
    51          if (statement.jjtGetChild(0).jjtGetNumChildren() == 0) {
    52              return data;     // skips empty return statements
    53          }
    54          SimpleNode statementGrandChild = (SimpleNode) statement.jjtGetChild(0).jjtGetChild(0);
    55          ASTPrimaryExpression primaryExpression;
    56
    57          if (statementGrandChild instanceof ASTPrimaryExpression)
    58              primaryExpression = (ASTPrimaryExpression) statementGrandChild;
    59          else {
    60              List primaryExpressions = findFirstDegreeChildrenOfType(statementGrandChild, ASTPrimaryExpression.class);
    61              if (primaryExpressions.size() != 1)
    62                  return super.visit(node, data);
    63              primaryExpression = (ASTPrimaryExpression) primaryExpressions.get(0);
    64          }
    65
    66          ASTPrimaryPrefix primaryPrefix = (ASTPrimaryPrefix) findFirstDegreeChildrenOfType(primaryExpression, ASTPrimaryPrefix.class).get(0);
    67          if (!primaryPrefix.usesSuperModifier())
    68              return super.visit(node, data);
    69
    70          ASTMethodDeclarator methodDeclarator = (ASTMethodDeclarator) findFirstDegreeChildrenOfType(node, ASTMethodDeclarator.class).get(0);
    71          if (!primaryPrefix.getImage().equals(methodDeclarator.getImage()))
    72              return super.visit(node, data);
    73
    74          //Process arguments
    75          ASTPrimarySuffix primarySuffix = (ASTPrimarySuffix) findFirstDegreeChildrenOfType(primaryExpression, ASTPrimarySuffix.class).get(0);
    76          ASTArguments arguments = (ASTArguments) primarySuffix.jjtGetChild(0);
    77          ASTFormalParameters formalParameters = (ASTFormalParameters) methodDeclarator.jjtGetChild(0);
    78          if (formalParameters.jjtGetNumChildren() != arguments.jjtGetNumChildren())
    79              return super.visit(node, data);
    80
    81          if (arguments.jjtGetNumChildren() == 0) //No arguments to check
    82              addViolation(data, node, getMessage());
    83          else {
    84              ASTArgumentList argumentList = (ASTArgumentList) arguments.jjtGetChild(0);
    85              for (int i = 0; i < argumentList.jjtGetNumChildren(); i++) {
    86                  Node ExpressionChild = argumentList.jjtGetChild(i).jjtGetChild(0);
    87                  if (!(ExpressionChild instanceof ASTPrimaryExpression) || ExpressionChild.jjtGetNumChildren() != 1)
    88                      return super.visit(node, data); //The arguments are not simply passed through
    89
    90                  ASTPrimaryExpression argumentPrimaryExpression = (ASTPrimaryExpression) ExpressionChild;
    91                  ASTPrimaryPrefix argumentPrimaryPrefix = (ASTPrimaryPrefix) argumentPrimaryExpression.jjtGetChild(0);
    92                  Node argumentPrimaryPrefixChild = argumentPrimaryPrefix.jjtGetChild(0);
    93                  if (!(argumentPrimaryPrefixChild instanceof ASTName))
    94                      return super.visit(node, data); //The arguments are not simply passed through
    95
    96                  if (formalParameters.jjtGetNumChildren() < i + 1) {
    97                      return super.visit(node, data); // different number of args
    98                  }
    99
    100                 ASTName argumentName = (ASTName) argumentPrimaryPrefixChild;
    101                 ASTFormalParameter formalParameter = (ASTFormalParameter) formalParameters.jjtGetChild(i);
    102                 ASTVariableDeclaratorId variableId = (ASTVariableDeclaratorId) findFirstDegreeChildrenOfType(formalParameter, ASTVariableDeclaratorId.class).get(0);
    103                 if (!argumentName.getImage().equals(variableId.getImage())) {
    104                     return super.visit(node, data); //The arguments are not simply passed through
    105                 }
    106
    107             }
    108             addViolation(data, node, getMessage()); //All arguments are passed through directly
    109         }
    110         return super.visit(node, data);
    111     }
    112
    113     public List findFirstDegreeChildrenOfType(SimpleNode n, Class targetType) {
    114         List l = new ArrayList();
    115         lclFindChildrenOfType(n, targetType, l);
    116         return l;
    117     }
    118
    119     private void lclFindChildrenOfType(Node node, Class targetType, List results) {
    120         if (node.getClass().equals(targetType)) {
    121             results.add(node);
    122         }
    123
    124         if (node instanceof ASTClassOrInterfaceDeclaration && ((ASTClassOrInterfaceDeclaration) node).isNested()) {
    125             return;
    126         }
    127
    128         if (node instanceof ASTClassOrInterfaceBodyDeclaration && ((ASTClassOrInterfaceBodyDeclaration) node).isAnonymousInnerClass()) {
    129             return;
    130         }
    131
    132         for (int i = 0; i < node.jjtGetNumChildren(); i++) {
    133             Node child = node.jjtGetChild(i);
    134             if (child.getClass().equals(targetType)) {
    135                 results.add(child);
    136             }
    137         }
    138     }
    139 }