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  }