001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2026 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018/////////////////////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.checks.sizes; 021 022import com.puppycrawl.tools.checkstyle.StatelessCheck; 023import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 024import com.puppycrawl.tools.checkstyle.api.DetailAST; 025import com.puppycrawl.tools.checkstyle.api.TokenTypes; 026 027/** 028 * <div> 029 * Checks lambda body length. 030 * </div> 031 * 032 * <p> 033 * Rationale: Similar to anonymous inner classes, if lambda body becomes very long 034 * it is hard to understand and to see the flow of the method 035 * where the lambda is defined. Therefore, long lambda body should usually be extracted to method. 036 * </p> 037 * 038 * @since 8.37 039 */ 040@StatelessCheck 041public class LambdaBodyLengthCheck extends AbstractCheck { 042 043 /** 044 * A key is pointing to the warning message text in "messages.properties" file. 045 */ 046 public static final String MSG_KEY = "maxLen.lambdaBody"; 047 048 /** Default maximum number of lines. */ 049 private static final int DEFAULT_MAX = 10; 050 051 /** Specify the maximum number of lines allowed. */ 052 private int max = DEFAULT_MAX; 053 054 /** 055 * Creates a new {@code LambdaBodyLengthCheck} instance. 056 */ 057 public LambdaBodyLengthCheck() { 058 // no code by default 059 } 060 061 /** 062 * Setter to specify the maximum number of lines allowed. 063 * 064 * @param length the maximum length of lambda body. 065 * @since 8.37 066 */ 067 public void setMax(int length) { 068 max = length; 069 } 070 071 @Override 072 public int[] getDefaultTokens() { 073 return getRequiredTokens(); 074 } 075 076 @Override 077 public int[] getAcceptableTokens() { 078 return getRequiredTokens(); 079 } 080 081 @Override 082 public int[] getRequiredTokens() { 083 return new int[] {TokenTypes.LAMBDA}; 084 } 085 086 @Override 087 public void visitToken(DetailAST ast) { 088 if (ast.getParent().getType() != TokenTypes.SWITCH_RULE) { 089 final int length = getLength(ast); 090 if (length > max) { 091 log(ast, MSG_KEY, length, max); 092 } 093 } 094 } 095 096 /** 097 * Get length of lambda body. 098 * 099 * @param ast lambda body node. 100 * @return length of lambda body. 101 */ 102 private static int getLength(DetailAST ast) { 103 final DetailAST lambdaBody = ast.getLastChild(); 104 final int length; 105 if (lambdaBody.getType() == TokenTypes.SLIST) { 106 length = lambdaBody.getLastChild().getLineNo() - lambdaBody.getLineNo(); 107 } 108 else { 109 length = getLastNodeLineNumber(lambdaBody) - getFirstNodeLineNumber(lambdaBody); 110 } 111 return length + 1; 112 } 113 114 /** 115 * Get last child node in the tree line number. 116 * 117 * @param lambdaBody lambda body node. 118 * @return last child node in the tree line number. 119 */ 120 private static int getLastNodeLineNumber(DetailAST lambdaBody) { 121 DetailAST node = lambdaBody; 122 int result; 123 do { 124 result = node.getLineNo(); 125 node = node.getLastChild(); 126 } while (node != null); 127 return result; 128 } 129 130 /** 131 * Get first child node in the tree line number. 132 * 133 * @param lambdaBody lambda body node. 134 * @return first child node in the tree line number. 135 */ 136 private static int getFirstNodeLineNumber(DetailAST lambdaBody) { 137 DetailAST node = lambdaBody; 138 int result; 139 do { 140 result = node.getLineNo(); 141 node = node.getFirstChild(); 142 } while (node != null); 143 return result; 144 } 145 146}