View Javadoc

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