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 java.util.ArrayDeque; | |
23 | import java.util.Deque; | |
24 | ||
25 | import com.puppycrawl.tools.checkstyle.FileStatefulCheck; | |
26 | import com.puppycrawl.tools.checkstyle.api.AbstractCheck; | |
27 | import com.puppycrawl.tools.checkstyle.api.DetailAST; | |
28 | import com.puppycrawl.tools.checkstyle.api.TokenTypes; | |
29 | import com.puppycrawl.tools.checkstyle.utils.TokenUtil; | |
30 | ||
31 | /** | |
32 | * <p> | |
33 | * Restricts the number of executable statements to a specified limit. | |
34 | * </p> | |
35 | * <ul> | |
36 | * <li> | |
37 | * Property {@code max} - Specify the maximum threshold allowed. | |
38 | * Type is {@code int}. | |
39 | * Default value is {@code 30}. | |
40 | * </li> | |
41 | * <li> | |
42 | * Property {@code tokens} - tokens to check | |
43 | * Type is {@code java.lang.String[]}. | |
44 | * Validation type is {@code tokenSet}. | |
45 | * Default value is: | |
46 | * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CTOR_DEF"> | |
47 | * CTOR_DEF</a>, | |
48 | * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF"> | |
49 | * METHOD_DEF</a>, | |
50 | * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INSTANCE_INIT"> | |
51 | * INSTANCE_INIT</a>, | |
52 | * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#STATIC_INIT"> | |
53 | * STATIC_INIT</a>, | |
54 | * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#COMPACT_CTOR_DEF"> | |
55 | * COMPACT_CTOR_DEF</a>, | |
56 | * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LAMBDA"> | |
57 | * LAMBDA</a>. | |
58 | * </li> | |
59 | * </ul> | |
60 | * <p> | |
61 | * To configure the check: | |
62 | * </p> | |
63 | * <pre> | |
64 | * <module name="ExecutableStatementCount"/> | |
65 | * </pre> | |
66 | * <p> | |
67 | * To configure the check with a threshold of 20 for constructor and method definitions: | |
68 | * </p> | |
69 | * <pre> | |
70 | * <module name="ExecutableStatementCount"> | |
71 | * <property name="max" value="20"/> | |
72 | * <property name="tokens" value="CTOR_DEF,METHOD_DEF"/> | |
73 | * </module> | |
74 | * </pre> | |
75 | * <p> | |
76 | * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} | |
77 | * </p> | |
78 | * <p> | |
79 | * Violation Message Keys: | |
80 | * </p> | |
81 | * <ul> | |
82 | * <li> | |
83 | * {@code executableStatementCount} | |
84 | * </li> | |
85 | * </ul> | |
86 | * | |
87 | * @since 3.2 | |
88 | */ | |
89 | @FileStatefulCheck | |
90 | public final class ExecutableStatementCountCheck | |
91 | extends AbstractCheck { | |
92 | ||
93 | /** | |
94 | * A key is pointing to the warning message text in "messages.properties" | |
95 | * file. | |
96 | */ | |
97 | public static final String MSG_KEY = "executableStatementCount"; | |
98 | ||
99 | /** Default threshold. */ | |
100 | private static final int DEFAULT_MAX = 30; | |
101 | ||
102 | /** Stack of method contexts. */ | |
103 |
1
1. <init> : removed call to java/util/ArrayDeque::<init> → KILLED |
private final Deque<Context> contextStack = new ArrayDeque<>(); |
104 | ||
105 | /** Specify the maximum threshold allowed. */ | |
106 | private int max; | |
107 | ||
108 | /** Current method context. */ | |
109 | private Context context; | |
110 | ||
111 | /** Constructs a {@code ExecutableStatementCountCheck}. */ | |
112 | public ExecutableStatementCountCheck() { | |
113 | max = DEFAULT_MAX; | |
114 | } | |
115 | ||
116 | @Override | |
117 | public int[] getDefaultTokens() { | |
118 |
1
1. getDefaultTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return new int[] { |
119 | TokenTypes.CTOR_DEF, | |
120 | TokenTypes.METHOD_DEF, | |
121 | TokenTypes.INSTANCE_INIT, | |
122 | TokenTypes.STATIC_INIT, | |
123 | TokenTypes.SLIST, | |
124 | TokenTypes.COMPACT_CTOR_DEF, | |
125 | TokenTypes.LAMBDA, | |
126 | }; | |
127 | } | |
128 | ||
129 | @Override | |
130 | public int[] getRequiredTokens() { | |
131 |
1
1. getRequiredTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return new int[] {TokenTypes.SLIST}; |
132 | } | |
133 | ||
134 | @Override | |
135 | public int[] getAcceptableTokens() { | |
136 |
1
1. getAcceptableTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return new int[] { |
137 | TokenTypes.CTOR_DEF, | |
138 | TokenTypes.METHOD_DEF, | |
139 | TokenTypes.INSTANCE_INIT, | |
140 | TokenTypes.STATIC_INIT, | |
141 | TokenTypes.SLIST, | |
142 | TokenTypes.COMPACT_CTOR_DEF, | |
143 | TokenTypes.LAMBDA, | |
144 | }; | |
145 | } | |
146 | ||
147 | /** | |
148 | * Setter to specify the maximum threshold allowed. | |
149 | * | |
150 | * @param max the maximum threshold. | |
151 | */ | |
152 | public void setMax(int max) { | |
153 | this.max = max; | |
154 | } | |
155 | ||
156 | @Override | |
157 | public void beginTree(DetailAST rootAST) { | |
158 |
1
1. beginTree : removed call to com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck$Context::<init> → KILLED |
context = new Context(null); |
159 |
1
1. beginTree : removed call to java/util/Deque::clear → KILLED |
contextStack.clear(); |
160 | } | |
161 | ||
162 | @Override | |
163 | public void visitToken(DetailAST ast) { | |
164 |
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 (isContainerNode(ast)) { |
165 |
1
1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck::visitContainerNode → KILLED |
visitContainerNode(ast); |
166 | } | |
167 |
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 |
else if (TokenUtil.isOfType(ast, TokenTypes.SLIST)) { |
168 |
1
1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck::visitSlist → KILLED |
visitSlist(ast); |
169 | } | |
170 | else { | |
171 |
1
1. visitToken : removed call to java/lang/IllegalStateException::<init> → KILLED |
throw new IllegalStateException(ast.toString()); |
172 | } | |
173 | } | |
174 | ||
175 | @Override | |
176 | public void leaveToken(DetailAST ast) { | |
177 |
3
1. leaveToken : negated conditional → KILLED 2. leaveToken : removed conditional - replaced equality check with false → KILLED 3. leaveToken : removed conditional - replaced equality check with true → KILLED |
if (isContainerNode(ast)) { |
178 |
1
1. leaveToken : removed call to com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck::leaveContainerNode → KILLED |
leaveContainerNode(ast); |
179 | } | |
180 |
3
1. leaveToken : negated conditional → KILLED 2. leaveToken : removed conditional - replaced equality check with false → KILLED 3. leaveToken : removed conditional - replaced equality check with true → KILLED |
else if (!TokenUtil.isOfType(ast, TokenTypes.SLIST)) { |
181 |
1
1. leaveToken : removed call to java/lang/IllegalStateException::<init> → KILLED |
throw new IllegalStateException(ast.toString()); |
182 | } | |
183 | } | |
184 | ||
185 | /** | |
186 | * Process the start of the container node. | |
187 | * | |
188 | * @param ast the token representing the container node. | |
189 | */ | |
190 | private void visitContainerNode(DetailAST ast) { | |
191 |
1
1. visitContainerNode : removed call to java/util/Deque::push → KILLED |
contextStack.push(context); |
192 |
1
1. visitContainerNode : removed call to com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck$Context::<init> → KILLED |
context = new Context(ast); |
193 | } | |
194 | ||
195 | /** | |
196 | * Process the end of a container node. | |
197 | * | |
198 | * @param ast the token representing the container node. | |
199 | */ | |
200 | private void leaveContainerNode(DetailAST ast) { | |
201 | final int count = context.getCount(); | |
202 |
4
1. leaveContainerNode : changed conditional boundary → KILLED 2. leaveContainerNode : negated conditional → KILLED 3. leaveContainerNode : removed conditional - replaced comparison check with false → KILLED 4. leaveContainerNode : removed conditional - replaced comparison check with true → KILLED |
if (count > max) { |
203 |
1
1. leaveContainerNode : removed call to com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck::log → KILLED |
log(ast, MSG_KEY, count, max); |
204 | } | |
205 | context = contextStack.pop(); | |
206 | } | |
207 | ||
208 | /** | |
209 | * Process the end of a statement list. | |
210 | * | |
211 | * @param ast the token representing the statement list. | |
212 | */ | |
213 | private void visitSlist(DetailAST ast) { | |
214 | final DetailAST contextAST = context.getAST(); | |
215 | DetailAST parent = ast.getParent(); | |
216 |
6
1. visitSlist : negated conditional → KILLED 2. visitSlist : negated conditional → KILLED 3. visitSlist : removed conditional - replaced equality check with false → KILLED 4. visitSlist : removed conditional - replaced equality check with false → KILLED 5. visitSlist : removed conditional - replaced equality check with true → KILLED 6. visitSlist : removed conditional - replaced equality check with true → KILLED |
while (parent != null && !isContainerNode(parent)) { |
217 | parent = parent.getParent(); | |
218 | } | |
219 |
3
1. visitSlist : negated conditional → KILLED 2. visitSlist : removed conditional - replaced equality check with false → KILLED 3. visitSlist : removed conditional - replaced equality check with true → KILLED |
if (parent == contextAST) { |
220 |
2
1. visitSlist : Replaced integer division with multiplication → KILLED 2. visitSlist : removed call to com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck$Context::addCount → KILLED |
context.addCount(ast.getChildCount() / 2); |
221 | } | |
222 | } | |
223 | ||
224 | /** | |
225 | * Check if the node is of type ctor (compact or canonical), | |
226 | * instance/ static initializer, method definition or lambda. | |
227 | * | |
228 | * @param node AST node we are checking | |
229 | * @return true if node is of the given types | |
230 | */ | |
231 | private static boolean isContainerNode(DetailAST node) { | |
232 |
3
1. isContainerNode : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED 2. isContainerNode : replaced boolean return with false for com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck::isContainerNode → KILLED 3. isContainerNode : replaced boolean return with true for com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck::isContainerNode → KILLED |
return TokenUtil.isOfType(node, TokenTypes.METHOD_DEF, |
233 | TokenTypes.LAMBDA, TokenTypes.CTOR_DEF, TokenTypes.INSTANCE_INIT, | |
234 | TokenTypes.STATIC_INIT, TokenTypes.COMPACT_CTOR_DEF); | |
235 | } | |
236 | ||
237 | /** | |
238 | * Class to encapsulate counting information about one member. | |
239 | */ | |
240 | private static class Context { | |
241 | ||
242 | /** Member AST node. */ | |
243 | private final DetailAST ast; | |
244 | ||
245 | /** Counter for context elements. */ | |
246 | private int count; | |
247 | ||
248 | /** | |
249 | * Creates new member context. | |
250 | * | |
251 | * @param ast member AST node. | |
252 | */ | |
253 | /* package */ Context(DetailAST ast) { | |
254 | this.ast = ast; | |
255 | count = 0; | |
256 | } | |
257 | ||
258 | /** | |
259 | * Increase count. | |
260 | * | |
261 | * @param addition the count increment. | |
262 | */ | |
263 | public void addCount(int addition) { | |
264 |
1
1. addCount : Replaced integer addition with subtraction → KILLED |
count += addition; |
265 | } | |
266 | ||
267 | /** | |
268 | * Gets the member AST node. | |
269 | * | |
270 | * @return the member AST node. | |
271 | */ | |
272 | public DetailAST getAST() { | |
273 |
1
1. getAST : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck$Context::getAST to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return ast; |
274 | } | |
275 | ||
276 | /** | |
277 | * Gets the count. | |
278 | * | |
279 | * @return the count. | |
280 | */ | |
281 | public int getCount() { | |
282 |
1
1. getCount : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return count; |
283 | } | |
284 | ||
285 | } | |
286 | ||
287 | } | |
Mutations | ||
103 |
1.1 |
|
118 |
1.1 |
|
131 |
1.1 |
|
136 |
1.1 |
|
158 |
1.1 |
|
159 |
1.1 |
|
164 |
1.1 2.2 3.3 |
|
165 |
1.1 |
|
167 |
1.1 2.2 3.3 |
|
168 |
1.1 |
|
171 |
1.1 |
|
177 |
1.1 2.2 3.3 |
|
178 |
1.1 |
|
180 |
1.1 2.2 3.3 |
|
181 |
1.1 |
|
191 |
1.1 |
|
192 |
1.1 |
|
202 |
1.1 2.2 3.3 4.4 |
|
203 |
1.1 |
|
216 |
1.1 2.2 3.3 4.4 5.5 6.6 |
|
219 |
1.1 2.2 3.3 |
|
220 |
1.1 2.2 |
|
232 |
1.1 2.2 3.3 |
|
264 |
1.1 |
|
273 |
1.1 |
|
282 |
1.1 |