View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2025 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ///////////////////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.checks.sizes;
21  
22  import com.puppycrawl.tools.checkstyle.StatelessCheck;
23  import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
24  import com.puppycrawl.tools.checkstyle.api.DetailAST;
25  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
26  
27  /**
28   * <div>
29   * Checks lambda body length.
30   * </div>
31   *
32   * <p>
33   * Rationale: Similar to anonymous inner classes, if lambda body becomes very long
34   * it is hard to understand and to see the flow of the method
35   * where the lambda is defined. Therefore, long lambda body
36   * should usually be extracted to method.
37   * </p>
38   *
39   * @since 8.37
40   */
41  @StatelessCheck
42  public class LambdaBodyLengthCheck extends AbstractCheck {
43  
44      /**
45       * A key is pointing to the warning message text in "messages.properties"
46       * file.
47       */
48      public static final String MSG_KEY = "maxLen.lambdaBody";
49  
50      /** Default maximum number of lines. */
51      private static final int DEFAULT_MAX = 10;
52  
53      /** Specify the maximum number of lines allowed. */
54      private int max = DEFAULT_MAX;
55  
56      /**
57       * Setter to specify the maximum number of lines allowed.
58       *
59       * @param length the maximum length of lambda body.
60       * @since 8.37
61       */
62      public void setMax(int length) {
63          max = length;
64      }
65  
66      @Override
67      public int[] getDefaultTokens() {
68          return getRequiredTokens();
69      }
70  
71      @Override
72      public int[] getAcceptableTokens() {
73          return getRequiredTokens();
74      }
75  
76      @Override
77      public int[] getRequiredTokens() {
78          return new int[] {TokenTypes.LAMBDA};
79      }
80  
81      @Override
82      public void visitToken(DetailAST ast) {
83          if (ast.getParent().getType() != TokenTypes.SWITCH_RULE) {
84              final int length = getLength(ast);
85              if (length > max) {
86                  log(ast, MSG_KEY, length, max);
87              }
88          }
89      }
90  
91      /**
92       * Get length of lambda body.
93       *
94       * @param ast lambda body node.
95       * @return length of lambda body.
96       */
97      private static int getLength(DetailAST ast) {
98          final DetailAST lambdaBody = ast.getLastChild();
99          final int length;
100         if (lambdaBody.getType() == TokenTypes.SLIST) {
101             length = lambdaBody.getLastChild().getLineNo() - lambdaBody.getLineNo();
102         }
103         else {
104             length = getLastNodeLineNumber(lambdaBody) - getFirstNodeLineNumber(lambdaBody);
105         }
106         return length + 1;
107     }
108 
109     /**
110      * Get last child node in the tree line number.
111      *
112      * @param lambdaBody lambda body node.
113      * @return last child node in the tree line number.
114      */
115     private static int getLastNodeLineNumber(DetailAST lambdaBody) {
116         DetailAST node = lambdaBody;
117         int result;
118         do {
119             result = node.getLineNo();
120             node = node.getLastChild();
121         } while (node != null);
122         return result;
123     }
124 
125     /**
126      * Get first child node in the tree line number.
127      *
128      * @param lambdaBody lambda body node.
129      * @return first child node in the tree line number.
130      */
131     private static int getFirstNodeLineNumber(DetailAST lambdaBody) {
132         DetailAST node = lambdaBody;
133         int result;
134         do {
135             result = node.getLineNo();
136             node = node.getFirstChild();
137         } while (node != null);
138         return result;
139     }
140 
141 }