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() || node.isSynchronized()) {
    42              return super.visit(node, data);
    43          }
    44
    45          ASTBlock block = node.getBlock();
    46          if (block == null) {
    47              return super.visit(node, data);
    48          }
    49          //Only process functions with one BlockStatement
    50          if (block.jjtGetNumChildren() != 1 || block.findChildrenOfType(ASTStatement.class).size() != 1)
    51              return super.visit(node, data);
    52
    53          ASTStatement statement = (ASTStatement) block.jjtGetChild(0).jjtGetChild(0);
    54          if (statement.jjtGetChild(0).jjtGetNumChildren() == 0) {
    55              return data;     // skips empty return statements
    56          }
    57          SimpleNode statementGrandChild = (SimpleNode) statement.jjtGetChild(0).jjtGetChild(0);
    58          ASTPrimaryExpression primaryExpression;
    59
    60          if (statementGrandChild instanceof ASTPrimaryExpression)
    61              primaryExpression = (ASTPrimaryExpression) statementGrandChild;
    62          else {
    63              List primaryExpressions = findFirstDegreeChildrenOfType(statementGrandChild, ASTPrimaryExpression.class);
    64              if (primaryExpressions.size() != 1)
    65                  return super.visit(node, data);
    66              primaryExpression = (ASTPrimaryExpression) primaryExpressions.get(0);
    67          }
    68
    69          ASTPrimaryPrefix primaryPrefix = (ASTPrimaryPrefix) findFirstDegreeChildrenOfType(primaryExpression, ASTPrimaryPrefix.class).get(0);
    70          if (!primaryPrefix.usesSuperModifier())
    71              return super.visit(node, data);
    72
    73          ASTMethodDeclarator methodDeclarator = (ASTMethodDeclarator) findFirstDegreeChildrenOfType(node, ASTMethodDeclarator.class).get(0);
    74          if (!primaryPrefix.hasImageEqualTo(methodDeclarator.getImage()))
    75              return super.visit(node, data);
    76
    77          //Process arguments
    78          ASTPrimarySuffix primarySuffix = (ASTPrimarySuffix) findFirstDegreeChildrenOfType(primaryExpression, ASTPrimarySuffix.class).get(0);
    79          ASTArguments arguments = (ASTArguments) primarySuffix.jjtGetChild(0);
    80          ASTFormalParameters formalParameters = (ASTFormalParameters) methodDeclarator.jjtGetChild(0);
    81          if (formalParameters.jjtGetNumChildren() != arguments.jjtGetNumChildren())
    82              return super.visit(node, data);
    83
    84          if (arguments.jjtGetNumChildren() == 0) //No arguments to check
    85              addViolation(data, node, getMessage());
    86          else {
    87              ASTArgumentList argumentList = (ASTArgumentList) arguments.jjtGetChild(0);
    88              for (int i = 0; i < argumentList.jjtGetNumChildren(); i++) {
    89                  Node ExpressionChild = argumentList.jjtGetChild(i).jjtGetChild(0);
    90                  if (!(ExpressionChild instanceof ASTPrimaryExpression) || ExpressionChild.jjtGetNumChildren() != 1)
    91                      return super.visit(node, data); //The arguments are not simply passed through
    92
    93                  ASTPrimaryExpression argumentPrimaryExpression = (ASTPrimaryExpression) ExpressionChild;
    94                  ASTPrimaryPrefix argumentPrimaryPrefix = (ASTPrimaryPrefix) argumentPrimaryExpression.jjtGetChild(0);
    95                  if (argumentPrimaryPrefix.jjtGetNumChildren() == 0) {
    96                      return super.visit(node, data); //The arguments are not simply passed through (using "this" for instance)
    97                  }
    98                  Node argumentPrimaryPrefixChild = argumentPrimaryPrefix.jjtGetChild(0);
    99                  if (!(argumentPrimaryPrefixChild instanceof ASTName))
    100                     return super.visit(node, data); //The arguments are not simply passed through
    101
    102                 if (formalParameters.jjtGetNumChildren() < i + 1) {
    103                     return super.visit(node, data); // different number of args
    104                 }
    105
    106                 ASTName argumentName = (ASTName) argumentPrimaryPrefixChild;
    107                 ASTFormalParameter formalParameter = (ASTFormalParameter) formalParameters.jjtGetChild(i);
    108                 ASTVariableDeclaratorId variableId = (ASTVariableDeclaratorId) findFirstDegreeChildrenOfType(formalParameter, ASTVariableDeclaratorId.class).get(0);
    109                 if (!argumentName.hasImageEqualTo(variableId.getImage())) {
    110                     return super.visit(node, data); //The arguments are not simply passed through
    111                 }
    112
    113             }
    114             addViolation(data, node, getMessage()); //All arguments are passed through directly
    115         }
    116         return super.visit(node, data);
    117     }
    118
    119     public List findFirstDegreeChildrenOfType(SimpleNode n, Class targetType) {
    120         List l = new ArrayList();
    121         lclFindChildrenOfType(n, targetType, l);
    122         return l;
    123     }
    124
    125     private void lclFindChildrenOfType(Node node, Class targetType, List results) {
    126         if (node.getClass().equals(targetType)) {
    127             results.add(node);
    128         }
    129
    130         if (node instanceof ASTClassOrInterfaceDeclaration && ((ASTClassOrInterfaceDeclaration) node).isNested()) {
    131             return;
    132         }
    133
    134         if (node instanceof ASTClassOrInterfaceBodyDeclaration && ((ASTClassOrInterfaceBodyDeclaration) node).isAnonymousInnerClass()) {
    135             return;
    136         }
    137
    138         for (int i = 0; i < node.jjtGetNumChildren(); i++) {
    139             Node child = node.jjtGetChild(i);
    140             if (child.getClass().equals(targetType)) {
    141                 results.add(child);
    142             }
    143         }
    144     }
    145 }