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 }