View Javadoc

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