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  }