LambdaBodyLengthCheck.java

1
///////////////////////////////////////////////////////////////////////////////////////////////
2
// checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3
// Copyright (C) 2001-2022 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
 * <p>
29
 * Checks lambda body length.
30
 * </p>
31
 * <p>
32
 * Rationale: Similar to anonymous inner classes, if lambda body becomes very long
33
 * it is hard to understand and to see the flow of the method
34
 * where the lambda is defined. Therefore, long lambda body
35
 * should usually be extracted to method.
36
 * </p>
37
 * <ul>
38
 * <li>
39
 * Property {@code max} - Specify the maximum number of lines allowed.
40
 * Type is {@code int}.
41
 * Default value is {@code 10}.
42
 * </li>
43
 * </ul>
44
 * <p>
45
 * To configure the check to accept lambda bodies with up to 10 lines:
46
 * </p>
47
 * <pre>
48
 * &lt;module name="LambdaBodyLength"/&gt;
49
 * </pre>
50
 * <p>
51
 * Example:
52
 * </p>
53
 * <pre>
54
 * class Test {
55
 *   Runnable r = () -&gt; { // violation, 11 lines
56
 *       System.out.println(2); // line 2 of lambda
57
 *       System.out.println(3);
58
 *       System.out.println(4);
59
 *       System.out.println(5);
60
 *       System.out.println(6);
61
 *       System.out.println(7);
62
 *       System.out.println(8);
63
 *       System.out.println(9);
64
 *       System.out.println(10);
65
 *   }; // line 11
66
 *
67
 *   Runnable r2 = () -&gt; // violation, 11 lines
68
 *       "someString".concat("1") // line 1 of lambda
69
 *                   .concat("2")
70
 *                   .concat("3")
71
 *                   .concat("4")
72
 *                   .concat("5")
73
 *                   .concat("6")
74
 *                   .concat("7")
75
 *                   .concat("8")
76
 *                   .concat("9")
77
 *                   .concat("10")
78
 *                   .concat("11"); // line 11
79
 *
80
 *   Runnable r3 = () -&gt; { // ok, 10 lines
81
 *       System.out.println(2); // line 2 of lambda
82
 *       System.out.println(3);
83
 *       System.out.println(4);
84
 *       System.out.println(5);
85
 *       System.out.println(6);
86
 *       System.out.println(7);
87
 *       System.out.println(8);
88
 *       System.out.println(9);
89
 *   }; // line 10
90
 * }
91
 * </pre>
92
 * <p>
93
 * To configure the check to accept lambda bodies with max 5 lines:
94
 * </p>
95
 * <pre>
96
 * &lt;module name="LambdaBodyLength"&gt;
97
 *   &lt;property name="max" value="5"/&gt;
98
 * &lt;/module&gt;
99
 * </pre>
100
 * <p>
101
 * Example:
102
 * </p>
103
 * <pre>
104
 * class Test {
105
 *   Runnable r = () -&gt; { // violation, 6 lines
106
 *       System.out.println(2); // line 2 of lambda
107
 *       System.out.println(3);
108
 *       System.out.println(4);
109
 *       System.out.println(5);
110
 *   };
111
 *
112
 *   Runnable r2 = () -&gt; // violation, 6 lines
113
 *       "someString".concat("1")
114
 *                   .concat("2")
115
 *                   .concat("3")
116
 *                   .concat("4")
117
 *                   .concat("5")
118
 *                   .concat("6");
119
 *
120
 *   Runnable r3 = () -&gt; { // ok, 5 lines
121
 *       System.out.println(2);
122
 *       System.out.println(3);
123
 *       System.out.println(4);
124
 *   };
125
 * }
126
 * </pre>
127
 * <p>
128
 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
129
 * </p>
130
 * <p>
131
 * Violation Message Keys:
132
 * </p>
133
 * <ul>
134
 * <li>
135
 * {@code maxLen.lambdaBody}
136
 * </li>
137
 * </ul>
138
 *
139
 * @since 8.37
140
 */
141
@StatelessCheck
142
public class LambdaBodyLengthCheck extends AbstractCheck {
143
144
    /**
145
     * A key is pointing to the warning message text in "messages.properties"
146
     * file.
147
     */
148
    public static final String MSG_KEY = "maxLen.lambdaBody";
149
150
    /** Default maximum number of lines. */
151
    private static final int DEFAULT_MAX = 10;
152
153
    /** Specify the maximum number of lines allowed. */
154
    private int max = DEFAULT_MAX;
155
156
    /**
157
     * Setter to specify the maximum number of lines allowed.
158
     *
159
     * @param length the maximum length of lambda body.
160
     */
161
    public void setMax(int length) {
162
        max = length;
163
    }
164
165
    @Override
166
    public int[] getDefaultTokens() {
167 1 1. getDefaultTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/sizes/LambdaBodyLengthCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return getRequiredTokens();
168
    }
169
170
    @Override
171
    public int[] getAcceptableTokens() {
172 1 1. getAcceptableTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/sizes/LambdaBodyLengthCheck::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return getRequiredTokens();
173
    }
174
175
    @Override
176
    public int[] getRequiredTokens() {
177 1 1. getRequiredTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/sizes/LambdaBodyLengthCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return new int[] {TokenTypes.LAMBDA};
178
    }
179
180
    @Override
181
    public void visitToken(DetailAST ast) {
182 3 1. visitToken : negated conditional → KILLED
2. visitToken : removed conditional - replaced equality check with false → KILLED
3. visitToken : removed conditional - replaced equality check with true → KILLED
        if (ast.getParent().getType() != TokenTypes.SWITCH_RULE) {
183
            final int length = getLength(ast);
184 4 1. visitToken : changed conditional boundary → KILLED
2. visitToken : negated conditional → KILLED
3. visitToken : removed conditional - replaced comparison check with false → KILLED
4. visitToken : removed conditional - replaced comparison check with true → KILLED
            if (length > max) {
185 1 1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/sizes/LambdaBodyLengthCheck::log → KILLED
                log(ast, MSG_KEY, length, max);
186
            }
187
        }
188
    }
189
190
    /**
191
     * Get length of lambda body.
192
     *
193
     * @param ast lambda body node.
194
     * @return length of lambda body.
195
     */
196
    private static int getLength(DetailAST ast) {
197
        final DetailAST lambdaBody = ast.getLastChild();
198
        final int length;
199 3 1. getLength : negated conditional → KILLED
2. getLength : removed conditional - replaced equality check with false → KILLED
3. getLength : removed conditional - replaced equality check with true → KILLED
        if (lambdaBody.getType() == TokenTypes.SLIST) {
200 1 1. getLength : Replaced integer subtraction with addition → KILLED
            length = lambdaBody.getLastChild().getLineNo() - lambdaBody.getLineNo();
201
        }
202
        else {
203 1 1. getLength : Replaced integer subtraction with addition → KILLED
            length = getLastNodeLineNumber(lambdaBody) - getFirstNodeLineNumber(lambdaBody);
204
        }
205 2 1. getLength : Replaced integer addition with subtraction → KILLED
2. getLength : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
        return length + 1;
206
    }
207
208
    /**
209
     * Get last child node in the tree line number.
210
     *
211
     * @param lambdaBody lambda body node.
212
     * @return last child node in the tree line number.
213
     */
214
    private static int getLastNodeLineNumber(DetailAST lambdaBody) {
215
        DetailAST node = lambdaBody;
216
        int result;
217
        do {
218
            result = node.getLineNo();
219
            node = node.getLastChild();
220 3 1. getLastNodeLineNumber : negated conditional → KILLED
2. getLastNodeLineNumber : removed conditional - replaced equality check with false → KILLED
3. getLastNodeLineNumber : removed conditional - replaced equality check with true → KILLED
        } while (node != null);
221 1 1. getLastNodeLineNumber : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
        return result;
222
    }
223
224
    /**
225
     * Get first child node in the tree line number.
226
     *
227
     * @param lambdaBody lambda body node.
228
     * @return first child node in the tree line number.
229
     */
230
    private static int getFirstNodeLineNumber(DetailAST lambdaBody) {
231
        DetailAST node = lambdaBody;
232
        int result;
233
        do {
234
            result = node.getLineNo();
235
            node = node.getFirstChild();
236 3 1. getFirstNodeLineNumber : negated conditional → KILLED
2. getFirstNodeLineNumber : removed conditional - replaced equality check with false → KILLED
3. getFirstNodeLineNumber : removed conditional - replaced equality check with true → KILLED
        } while (node != null);
237 1 1. getFirstNodeLineNumber : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
        return result;
238
    }
239
240
}

Mutations

167

1.1
Location : getDefaultTokens
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testDefaultSwitchExpressions()]
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/sizes/LambdaBodyLengthCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED

172

1.1
Location : getAcceptableTokens
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testGetAcceptableTokens()]
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/sizes/LambdaBodyLengthCheck::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED

177

1.1
Location : getRequiredTokens
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testGetAcceptableTokens()]
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/sizes/LambdaBodyLengthCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED

182

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testDefaultSwitchExpressions()]
negated conditional → KILLED

2.2
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
removed conditional - replaced equality check with false → KILLED

3.3
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testDefaultSwitchExpressions()]
removed conditional - replaced equality check with true → KILLED

184

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
changed conditional boundary → KILLED

2.2
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testDefaultSwitchExpressions()]
negated conditional → KILLED

3.3
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
removed conditional - replaced comparison check with false → KILLED

4.4
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testDefaultSwitchExpressions()]
removed conditional - replaced comparison check with true → KILLED

185

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
removed call to com/puppycrawl/tools/checkstyle/checks/sizes/LambdaBodyLengthCheck::log → KILLED

199

1.1
Location : getLength
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
negated conditional → KILLED

2.2
Location : getLength
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
removed conditional - replaced equality check with false → KILLED

3.3
Location : getLength
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
removed conditional - replaced equality check with true → KILLED

200

1.1
Location : getLength
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
Replaced integer subtraction with addition → KILLED

203

1.1
Location : getLength
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testDefaultSwitchExpressions()]
Replaced integer subtraction with addition → KILLED

205

1.1
Location : getLength
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
Replaced integer addition with subtraction → KILLED

2.2
Location : getLength
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

220

1.1
Location : getLastNodeLineNumber
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
negated conditional → KILLED

2.2
Location : getLastNodeLineNumber
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testDefaultSwitchExpressions()]
removed conditional - replaced equality check with false → KILLED

3.3
Location : getLastNodeLineNumber
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
removed conditional - replaced equality check with true → KILLED

221

1.1
Location : getLastNodeLineNumber
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

236

1.1
Location : getFirstNodeLineNumber
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
negated conditional → KILLED

2.2
Location : getFirstNodeLineNumber
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testDefaultSwitchExpressions()]
removed conditional - replaced equality check with false → KILLED

3.3
Location : getFirstNodeLineNumber
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testMaxLimitIsDifferent()]
removed conditional - replaced equality check with true → KILLED

237

1.1
Location : getFirstNodeLineNumber
Killed by : com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheckTest]/[method:testDefaultSwitchExpressions()]
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

Active mutators

Tests examined


Report generated by PIT 1.8.0