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  }