View Javadoc

1   package net.sourceforge.pmd.rules.design;
2   
3   import java.util.Iterator;
4   import java.util.List;
5   import java.util.Map;
6   
7   import net.sourceforge.pmd.AbstractRule;
8   import net.sourceforge.pmd.ast.ASTExpression;
9   import net.sourceforge.pmd.ast.ASTMethodDeclaration;
10  import net.sourceforge.pmd.ast.ASTName;
11  import net.sourceforge.pmd.ast.ASTPrimaryExpression;
12  import net.sourceforge.pmd.ast.ASTPrimarySuffix;
13  import net.sourceforge.pmd.ast.ASTReturnStatement;
14  import net.sourceforge.pmd.symboltable.NameOccurrence;
15  import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
16  
17  public class UnnecessaryLocalBeforeReturn extends AbstractRule {
18  
19      public Object visit(ASTMethodDeclaration meth, Object data) {
20          // skip void/abstract/native method
21          if (meth.isVoid() || meth.isAbstract() || meth.isNative()) {
22              return data;
23          }
24          return super.visit(meth, data);
25      }
26  
27      public Object visit(ASTReturnStatement rtn, Object data) {
28          // skip returns of literals
29          ASTName name = (ASTName) rtn.getFirstChildOfType(ASTName.class);
30          if (name == null) {
31              return data;
32          }
33  
34          // skip 'complicated' expressions
35          if (rtn.findChildrenOfType(ASTExpression.class).size() > 1 || rtn.findChildrenOfType(ASTPrimaryExpression.class).size() > 1 || isMethodCall(rtn)) {
36              return data;
37          }
38  
39          Map vars = name.getScope().getVariableDeclarations();
40          for (Iterator i = vars.entrySet().iterator(); i.hasNext();) {
41              Map.Entry entry = (Map.Entry) i.next();
42              VariableNameDeclaration key = (VariableNameDeclaration) entry.getKey();
43              List usages = (List) entry.getValue();
44              for (Iterator j = usages.iterator(); j.hasNext();) {
45                  NameOccurrence occ = (NameOccurrence) j.next();
46                  if (occ.getLocation().equals(name)) {
47                      // only check declarations that occur one line earlier
48                      if (key.getNode().getBeginLine() == name.getBeginLine() - 1) {
49                          String var = name.getImage();
50                          if (var.indexOf('.') != -1) {
51                              var = var.substring(0, var.indexOf('.'));
52                          }
53                          addViolation(data, rtn, var);
54                      }
55                  }
56              }
57          }
58          return data;
59      }
60      
61      /***
62       * Determine if the given return statement has any embedded method calls.
63       * 
64       * @param rtn
65       *          return statement to analyze
66       * @return true if any method calls are made within the given return
67       */
68      private boolean isMethodCall(ASTReturnStatement rtn) {
69       List suffix = rtn.findChildrenOfType( ASTPrimarySuffix.class );
70       for ( Iterator iter = suffix.iterator(); iter.hasNext(); ) {
71          ASTPrimarySuffix element = (ASTPrimarySuffix) iter.next();
72          if ( element.isArguments() ) {
73            return true;
74          }
75        }
76        return false;
77      }
78  }