View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.rule.controversial;
5   
6   import java.util.ArrayList;
7   import java.util.Iterator;
8   import java.util.List;
9   
10  import net.sourceforge.pmd.lang.ast.Node;
11  import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
12  import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression;
13  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
14  import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
15  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
16  
17  public class OnlyOneReturnRule extends AbstractJavaRule {
18  
19      @Override
20      public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
21          if (node.isInterface()) {
22              return data;
23          }
24          return super.visit(node, data);
25      }
26  
27      @Override
28      public Object visit(ASTMethodDeclaration node, Object data) {
29          if (node.isAbstract()) {
30              return data;
31          }
32  
33          List<ASTReturnStatement> returnNodes = new ArrayList<>();
34          node.findDescendantsOfType(ASTReturnStatement.class, returnNodes, false);
35          returnNodes = filterLambdaExpressions(returnNodes);
36  
37          if (returnNodes.size() > 1) {
38              for (Iterator<ASTReturnStatement> i = returnNodes.iterator(); i.hasNext();) {
39                  Node problem = i.next();
40                  // skip the last one, it's OK
41                  if (!i.hasNext()) {
42                      continue;
43                  }
44                  addViolation(data, problem);
45              }
46          }
47          return data;
48      }
49  
50      /**
51       * Checks whether the return statement is inside a lambda expression, and if
52       * so, this return statement is removed.
53       * 
54       * @param returnNodes
55       *            all the return statements inside the method
56       * @return all return statements, that are NOT within a lambda expression.
57       */
58      private List<ASTReturnStatement> filterLambdaExpressions(List<ASTReturnStatement> returnNodes) {
59          List<ASTReturnStatement> filtered = new ArrayList<>();
60          for (ASTReturnStatement ret : returnNodes) {
61              if (ret.getFirstParentOfType(ASTLambdaExpression.class) == null) {
62                  filtered.add(ret);
63              }
64          }
65          return filtered;
66      }
67  }