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 036 * should usually be extracted to method. 037 * </p> 038 * 039 * @since 8.37 040 */ 041@StatelessCheck 042public class LambdaBodyLengthCheck extends AbstractCheck { 043 044 /** 045 * A key is pointing to the warning message text in "messages.properties" 046 * file. 047 */ 048 public static final String MSG_KEY = "maxLen.lambdaBody"; 049 050 /** Default maximum number of lines. */ 051 private static final int DEFAULT_MAX = 10; 052 053 /** Specify the maximum number of lines allowed. */ 054 private int max = DEFAULT_MAX; 055 056 /** 057 * Creates a new {@code LambdaBodyLengthCheck} instance. 058 */ 059 public LambdaBodyLengthCheck() { 060 // no code by default 061 } 062 063 /** 064 * Setter to specify the maximum number of lines allowed. 065 * 066 * @param length the maximum length of lambda body. 067 * @since 8.37 068 */ 069 public void setMax(int length) { 070 max = length; 071 } 072 073 @Override 074 public int[] getDefaultTokens() { 075 return getRequiredTokens(); 076 } 077 078 @Override 079 public int[] getAcceptableTokens() { 080 return getRequiredTokens(); 081 } 082 083 @Override 084 public int[] getRequiredTokens() { 085 return new int[] {TokenTypes.LAMBDA}; 086 } 087 088 @Override 089 public void visitToken(DetailAST ast) { 090 if (ast.getParent().getType() != TokenTypes.SWITCH_RULE) { 091 final int length = getLength(ast); 092 if (length > max) { 093 log(ast, MSG_KEY, length, max); 094 } 095 } 096 } 097 098 /** 099 * Get length of lambda body. 100 * 101 * @param ast lambda body node. 102 * @return length of lambda body. 103 */ 104 private static int getLength(DetailAST ast) { 105 final DetailAST lambdaBody = ast.getLastChild(); 106 final int length; 107 if (lambdaBody.getType() == TokenTypes.SLIST) { 108 length = lambdaBody.getLastChild().getLineNo() - lambdaBody.getLineNo(); 109 } 110 else { 111 length = getLastNodeLineNumber(lambdaBody) - getFirstNodeLineNumber(lambdaBody); 112 } 113 return length + 1; 114 } 115 116 /** 117 * Get last child node in the tree line number. 118 * 119 * @param lambdaBody lambda body node. 120 * @return last child node in the tree line number. 121 */ 122 private static int getLastNodeLineNumber(DetailAST lambdaBody) { 123 DetailAST node = lambdaBody; 124 int result; 125 do { 126 result = node.getLineNo(); 127 node = node.getLastChild(); 128 } while (node != null); 129 return result; 130 } 131 132 /** 133 * Get first child node in the tree line number. 134 * 135 * @param lambdaBody lambda body node. 136 * @return first child node in the tree line number. 137 */ 138 private static int getFirstNodeLineNumber(DetailAST lambdaBody) { 139 DetailAST node = lambdaBody; 140 int result; 141 do { 142 result = node.getLineNo(); 143 node = node.getFirstChild(); 144 } while (node != null); 145 return result; 146 } 147 148}