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 java.util.List;
7   import java.util.ArrayList;
8   
9   import net.sourceforge.pmd.AbstractRule;
10  import net.sourceforge.pmd.ast.ASTArgumentList;
11  import net.sourceforge.pmd.ast.ASTArguments;
12  import net.sourceforge.pmd.ast.ASTBlock;
13  import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
14  import net.sourceforge.pmd.ast.ASTFormalParameter;
15  import net.sourceforge.pmd.ast.ASTFormalParameters;
16  import net.sourceforge.pmd.ast.ASTMethodDeclaration;
17  import net.sourceforge.pmd.ast.ASTMethodDeclarator;
18  import net.sourceforge.pmd.ast.ASTName;
19  import net.sourceforge.pmd.ast.ASTPrimaryExpression;
20  import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
21  import net.sourceforge.pmd.ast.ASTPrimarySuffix;
22  import net.sourceforge.pmd.ast.ASTStatement;
23  import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
24  import net.sourceforge.pmd.ast.Node;
25  import net.sourceforge.pmd.ast.SimpleNode;
26  import net.sourceforge.pmd.ast.ASTClassOrInterfaceBodyDeclaration;
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                  ASTName argumentName = (ASTName)argumentPrimaryPrefixChild;
97                  ASTFormalParameter formalParameter = (ASTFormalParameter)formalParameters.jjtGetChild(i);
98                  ASTVariableDeclaratorId variableId = (ASTVariableDeclaratorId)findFirstDegreeChildrenOfType(formalParameter, ASTVariableDeclaratorId.class).get(0);
99                  if (!argumentName.getImage().equals(variableId.getImage()))
100                     return super.visit(node, data); //The arguments are not simply passed through
101 
102             }
103             addViolation(data, node, getMessage()); //All arguments are passed through directly
104         }
105         return super.visit(node, data);
106     }
107 
108     public List findFirstDegreeChildrenOfType(SimpleNode n, Class targetType) {
109         List l = new ArrayList();
110         lclFindChildrenOfType(n, targetType, l, 0);
111         return l;
112     }
113 
114     private void lclFindChildrenOfType(Node node, Class targetType, List results, int depth) {
115          if (node.getClass().equals(targetType)) {
116              results.add(node);
117          }
118 
119          if (node instanceof ASTClassOrInterfaceDeclaration && ((ASTClassOrInterfaceDeclaration) node).isNested()) {
120              return;
121          }
122 
123          if (node instanceof ASTClassOrInterfaceBodyDeclaration && ((ASTClassOrInterfaceBodyDeclaration) node).isAnonymousInnerClass()) {
124              return;
125          }
126 
127          for (int i = 0; i < node.jjtGetNumChildren(); i++) {
128              Node child = node.jjtGetChild(i);
129              if (child.getClass().equals(targetType)) {
130                  results.add(child);
131              }
132          }
133      }
134 }