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.Arrays; | |
23 | import java.util.concurrent.atomic.AtomicInteger; | |
24 | ||
25 | import com.puppycrawl.tools.checkstyle.StatelessCheck; | |
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.checks.naming.AccessModifierOption; | |
30 | import com.puppycrawl.tools.checkstyle.utils.CheckUtil; | |
31 | import com.puppycrawl.tools.checkstyle.utils.TokenUtil; | |
32 | ||
33 | /** | |
34 | * <p> | |
35 | * Checks the number of record components in the | |
36 | * <a href="https://docs.oracle.com/javase/specs/jls/se14/preview/specs/records-jls.html#jls-8.10.1"> | |
37 | * header</a> of a record definition. | |
38 | * </p> | |
39 | * <ul> | |
40 | * <li> | |
41 | * Property {@code max} - Specify the maximum number of components allowed in the header of a | |
42 | * record definition. | |
43 | * Type is {@code int}. | |
44 | * Default value is {@code 8}. | |
45 | * </li> | |
46 | * <li> | |
47 | * Property {@code accessModifiers} - Access modifiers of record definitions where | |
48 | * the number of record components should be checked. | |
49 | * Type is {@code com.puppycrawl.tools.checkstyle.checks.naming.AccessModifierOption[]}. | |
50 | * Default value is {@code public, protected, package, private}. | |
51 | * </li> | |
52 | * </ul> | |
53 | * <p> | |
54 | * To configure the check: | |
55 | * </p> | |
56 | * <pre> | |
57 | * <module name="RecordComponentNumber"/> | |
58 | * </pre> | |
59 | * <p> | |
60 | * Java code example: | |
61 | * </p> | |
62 | * <pre> | |
63 | * public record MyRecord1(int x, int y) { // ok, 2 components | |
64 | * ... | |
65 | * } | |
66 | * | |
67 | * record MyRecord2(int x, int y, String str, | |
68 | * Node node, Order order, Data data | |
69 | * String location, Date date, Image image) { // violation, 9 components | |
70 | * ... | |
71 | * } | |
72 | * </pre> | |
73 | * <p> | |
74 | * To configure the check to allow 5 record components at all access modifier levels | |
75 | * for record definitions: | |
76 | * </p> | |
77 | * <pre> | |
78 | * <module name="RecordComponentNumber"> | |
79 | * <property name="max" value="5"/> | |
80 | * </module> | |
81 | * </pre> | |
82 | * <p> | |
83 | * Java code example: | |
84 | * </p> | |
85 | * <pre> | |
86 | * public record MyRecord1(int x, int y, String str) { // ok, 3 components | |
87 | * ... | |
88 | * } | |
89 | * | |
90 | * public record MyRecord2(int x, int y, String str, | |
91 | * Node node, Order order, Data data) { // violation, 6 components | |
92 | * ... | |
93 | * } | |
94 | * </pre> | |
95 | * <p> | |
96 | * To configure the check to allow 10 record components for a public record definition, | |
97 | * but 3 for private record definitions: | |
98 | * </p> | |
99 | * <pre> | |
100 | * <module name="RecordComponentNumber"> | |
101 | * <property name="max" value="3"/> | |
102 | * <property name="accessModifiers" value="private"/> | |
103 | * </module> | |
104 | * <module name="RecordComponentNumber"> | |
105 | * <property name="max" value="10"/> | |
106 | * <property name="accessModifiers" value="public"/> | |
107 | * </module> | |
108 | * </pre> | |
109 | * <p> | |
110 | * Java code example: | |
111 | * </p> | |
112 | * <pre> | |
113 | * public record MyRecord1(int x, int y, String str) { // ok, public record definition allowed 10 | |
114 | * ... | |
115 | * } | |
116 | * | |
117 | * private record MyRecord2(int x, int y, String str, Node node) { // violation | |
118 | * ... // private record definition allowed 3 components | |
119 | * } | |
120 | * </pre> | |
121 | * <p> | |
122 | * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} | |
123 | * </p> | |
124 | * <p> | |
125 | * Violation Message Keys: | |
126 | * </p> | |
127 | * <ul> | |
128 | * <li> | |
129 | * {@code too.many.components} | |
130 | * </li> | |
131 | * </ul> | |
132 | * | |
133 | * @since 8.36 | |
134 | */ | |
135 | @StatelessCheck | |
136 | public class RecordComponentNumberCheck extends AbstractCheck { | |
137 | ||
138 | /** | |
139 | * A key is pointing to the warning message text in "messages.properties" | |
140 | * file. | |
141 | */ | |
142 | public static final String MSG_KEY = "too.many.components"; | |
143 | ||
144 | /** Default maximum number of allowed components. */ | |
145 | private static final int DEFAULT_MAX_COMPONENTS = 8; | |
146 | ||
147 | /** Specify the maximum number of components allowed in the header of a record definition. */ | |
148 | private int max = DEFAULT_MAX_COMPONENTS; | |
149 | ||
150 | /** | |
151 | * Access modifiers of record definitions where the number | |
152 | * of record components should be checked. | |
153 | */ | |
154 | private AccessModifierOption[] accessModifiers = { | |
155 | AccessModifierOption.PUBLIC, | |
156 | AccessModifierOption.PROTECTED, | |
157 | AccessModifierOption.PACKAGE, | |
158 | AccessModifierOption.PRIVATE, | |
159 | }; | |
160 | ||
161 | /** | |
162 | * Setter to specify the maximum number of components allowed in the header | |
163 | * of a record definition. | |
164 | * | |
165 | * @param value the maximum allowed. | |
166 | */ | |
167 | public void setMax(int value) { | |
168 | max = value; | |
169 | } | |
170 | ||
171 | /** | |
172 | * Setter to access modifiers of record definitions where the number of record | |
173 | * components should be checked. | |
174 | * | |
175 | * @param accessModifiers access modifiers of record definitions which should be checked. | |
176 | */ | |
177 | public void setAccessModifiers(AccessModifierOption... accessModifiers) { | |
178 | this.accessModifiers = | |
179 | Arrays.copyOf(accessModifiers, accessModifiers.length); | |
180 | } | |
181 | ||
182 | @Override | |
183 | public int[] getDefaultTokens() { | |
184 |
1
1. getDefaultTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/sizes/RecordComponentNumberCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return getAcceptableTokens(); |
185 | } | |
186 | ||
187 | @Override | |
188 | public int[] getAcceptableTokens() { | |
189 |
1
1. getAcceptableTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/sizes/RecordComponentNumberCheck::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return new int[] { |
190 | TokenTypes.RECORD_DEF, | |
191 | }; | |
192 | } | |
193 | ||
194 | @Override | |
195 | public int[] getRequiredTokens() { | |
196 |
1
1. getRequiredTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/sizes/RecordComponentNumberCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return getAcceptableTokens(); |
197 | } | |
198 | ||
199 | @Override | |
200 | public void visitToken(DetailAST ast) { | |
201 | final AccessModifierOption accessModifier = | |
202 | CheckUtil.getAccessModifierFromModifiersToken(ast); | |
203 | ||
204 |
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 (matchAccessModifiers(accessModifier)) { |
205 | final DetailAST recordComponents = | |
206 | ast.findFirstToken(TokenTypes.RECORD_COMPONENTS); | |
207 | final int componentCount = countComponents(recordComponents); | |
208 | ||
209 |
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 (componentCount > max) { |
210 |
1
1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/sizes/RecordComponentNumberCheck::log → KILLED |
log(ast, MSG_KEY, componentCount, max); |
211 | } | |
212 | } | |
213 | } | |
214 | ||
215 | /** | |
216 | * Method to count the number of record components in this record definition. | |
217 | * | |
218 | * @param recordComponents the ast to check | |
219 | * @return the number of record components in this record definition | |
220 | */ | |
221 | private static int countComponents(DetailAST recordComponents) { | |
222 |
1
1. countComponents : removed call to java/util/concurrent/atomic/AtomicInteger::<init> → KILLED |
final AtomicInteger count = new AtomicInteger(0); |
223 |
1
1. countComponents : removed call to com/puppycrawl/tools/checkstyle/utils/TokenUtil::forEachChild → KILLED |
TokenUtil.forEachChild(recordComponents, |
224 | TokenTypes.RECORD_COMPONENT_DEF, | |
225 | node -> count.getAndIncrement()); | |
226 |
1
1. countComponents : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return count.get(); |
227 | } | |
228 | ||
229 | /** | |
230 | * Checks whether a record definition has the correct access modifier to be checked. | |
231 | * | |
232 | * @param accessModifier the access modifier of the record definition. | |
233 | * @return whether the record definition matches the expected access modifier. | |
234 | */ | |
235 | private boolean matchAccessModifiers(final AccessModifierOption accessModifier) { | |
236 |
3
1. matchAccessModifiers : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED 2. matchAccessModifiers : replaced boolean return with false for com/puppycrawl/tools/checkstyle/checks/sizes/RecordComponentNumberCheck::matchAccessModifiers → KILLED 3. matchAccessModifiers : replaced boolean return with true for com/puppycrawl/tools/checkstyle/checks/sizes/RecordComponentNumberCheck::matchAccessModifiers → KILLED |
return Arrays.stream(accessModifiers) |
237 |
5
1. lambda$matchAccessModifiers$1 : negated conditional → KILLED 2. lambda$matchAccessModifiers$1 : removed conditional - replaced equality check with false → KILLED 3. lambda$matchAccessModifiers$1 : removed conditional - replaced equality check with true → KILLED 4. lambda$matchAccessModifiers$1 : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED 5. lambda$matchAccessModifiers$1 : replaced boolean return with true for com/puppycrawl/tools/checkstyle/checks/sizes/RecordComponentNumberCheck::lambda$matchAccessModifiers$1 → KILLED |
.anyMatch(modifier -> modifier == accessModifier); |
238 | } | |
239 | } | |
Mutations | ||
184 |
1.1 |
|
189 |
1.1 |
|
196 |
1.1 |
|
204 |
1.1 2.2 3.3 |
|
209 |
1.1 2.2 3.3 4.4 |
|
210 |
1.1 |
|
222 |
1.1 |
|
223 |
1.1 |
|
226 |
1.1 |
|
236 |
1.1 2.2 3.3 |
|
237 |
1.1 2.2 3.3 4.4 5.5 |