1 | //////////////////////////////////////////////////////////////////////////////// | |
2 | // checkstyle: Checks Java source code for adherence to a set of rules. | |
3 | // Copyright (C) 2001-2017 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; | |
21 | ||
22 | import java.util.Collections; | |
23 | import java.util.HashMap; | |
24 | import java.util.LinkedList; | |
25 | import java.util.List; | |
26 | import java.util.Locale; | |
27 | import java.util.Map; | |
28 | ||
29 | import com.puppycrawl.tools.checkstyle.api.AbstractCheck; | |
30 | import com.puppycrawl.tools.checkstyle.api.AuditEvent; | |
31 | import com.puppycrawl.tools.checkstyle.api.DetailAST; | |
32 | import com.puppycrawl.tools.checkstyle.api.TokenTypes; | |
33 | ||
34 | /** | |
35 | * Maintains a set of check suppressions from {@link SuppressWarnings} | |
36 | * annotations. | |
37 | * @author Trevor Robinson | |
38 | * @author Stéphane Galland | |
39 | */ | |
40 | public class SuppressWarningsHolder | |
41 | extends AbstractCheck { | |
42 | ||
43 | /** | |
44 | * A key is pointing to the warning message text in "messages.properties" | |
45 | * file. | |
46 | */ | |
47 | public static final String MSG_KEY = "suppress.warnings.invalid.target"; | |
48 | ||
49 | /** | |
50 | * Optional prefix for warning suppressions that are only intended to be | |
51 | * recognized by checkstyle. For instance, to suppress {@code | |
52 | * FallThroughCheck} only in checkstyle (and not in javac), use the | |
53 | * suppression {@code "checkstyle:fallthrough"} or {@code "checkstyle:FallThrough"}. | |
54 | * To suppress the warning in both tools, just use {@code "fallthrough"}. | |
55 | */ | |
56 | private static final String CHECKSTYLE_PREFIX = "checkstyle:"; | |
57 | ||
58 | /** Java.lang namespace prefix, which is stripped from SuppressWarnings */ | |
59 | private static final String JAVA_LANG_PREFIX = "java.lang."; | |
60 | ||
61 | /** Suffix to be removed from subclasses of Check. */ | |
62 | private static final String CHECK_SUFFIX = "Check"; | |
63 | ||
64 | /** Special warning id for matching all the warnings. */ | |
65 | private static final String ALL_WARNING_MATCHING_ID = "all"; | |
66 | ||
67 | /** A map from check source names to suppression aliases. */ | |
68 | private static final Map<String, String> CHECK_ALIAS_MAP = new HashMap<>(); | |
69 | ||
70 | /** | |
71 | * A thread-local holder for the list of suppression entries for the last | |
72 | * file parsed. | |
73 | */ | |
74 | private static final ThreadLocal<List<Entry>> ENTRIES = | |
75 | ThreadLocal.withInitial(LinkedList::new); | |
76 | ||
77 | /** | |
78 | * Returns the default alias for the source name of a check, which is the | |
79 | * source name in lower case with any dotted prefix or "Check" suffix | |
80 | * removed. | |
81 | * @param sourceName the source name of the check (generally the class | |
82 | * name) | |
83 | * @return the default alias for the given check | |
84 | */ | |
85 | public static String getDefaultAlias(String sourceName) { | |
86 | int endIndex = sourceName.length(); | |
87 |
1
1. getDefaultAlias : negated conditional → KILLED |
if (sourceName.endsWith(CHECK_SUFFIX)) { |
88 |
1
1. getDefaultAlias : Replaced integer subtraction with addition → KILLED |
endIndex -= CHECK_SUFFIX.length(); |
89 | } | |
90 |
1
1. getDefaultAlias : Replaced integer addition with subtraction → KILLED |
final int startIndex = sourceName.lastIndexOf('.') + 1; |
91 |
1
1. getDefaultAlias : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::getDefaultAlias to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return sourceName.substring(startIndex, endIndex).toLowerCase(Locale.ENGLISH); |
92 | } | |
93 | ||
94 | /** | |
95 | * Returns the alias for the source name of a check. If an alias has been | |
96 | * explicitly registered via {@link #registerAlias(String, String)}, that | |
97 | * alias is returned; otherwise, the default alias is used. | |
98 | * @param sourceName the source name of the check (generally the class | |
99 | * name) | |
100 | * @return the current alias for the given check | |
101 | */ | |
102 | public static String getAlias(String sourceName) { | |
103 | String checkAlias = CHECK_ALIAS_MAP.get(sourceName); | |
104 |
1
1. getAlias : negated conditional → KILLED |
if (checkAlias == null) { |
105 | checkAlias = getDefaultAlias(sourceName); | |
106 | } | |
107 |
1
1. getAlias : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::getAlias to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return checkAlias; |
108 | } | |
109 | ||
110 | /** | |
111 | * Registers an alias for the source name of a check. | |
112 | * @param sourceName the source name of the check (generally the class | |
113 | * name) | |
114 | * @param checkAlias the alias used in {@link SuppressWarnings} annotations | |
115 | */ | |
116 | private static void registerAlias(String sourceName, String checkAlias) { | |
117 | CHECK_ALIAS_MAP.put(sourceName, checkAlias); | |
118 | } | |
119 | ||
120 | /** | |
121 | * Registers a list of source name aliases based on a comma-separated list | |
122 | * of {@code source=alias} items, such as {@code | |
123 | * com.puppycrawl.tools.checkstyle.checks.sizes.ParameterNumberCheck= | |
124 | * paramnum}. | |
125 | * @param aliasList the list of comma-separated alias assignments | |
126 | */ | |
127 | public void setAliasList(String... aliasList) { | |
128 |
3
1. setAliasList : changed conditional boundary → KILLED 2. setAliasList : Changed increment from 1 to -1 → KILLED 3. setAliasList : negated conditional → KILLED |
for (String sourceAlias : aliasList) { |
129 | final int index = sourceAlias.indexOf('='); | |
130 |
2
1. setAliasList : changed conditional boundary → KILLED 2. setAliasList : negated conditional → KILLED |
if (index > 0) { |
131 |
2
1. setAliasList : Replaced integer addition with subtraction → KILLED 2. setAliasList : removed call to com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::registerAlias → KILLED |
registerAlias(sourceAlias.substring(0, index), sourceAlias |
132 | .substring(index + 1)); | |
133 | } | |
134 |
1
1. setAliasList : negated conditional → KILLED |
else if (!sourceAlias.isEmpty()) { |
135 | throw new IllegalArgumentException( | |
136 | "'=' expected in alias list item: " + sourceAlias); | |
137 | } | |
138 | } | |
139 | } | |
140 | ||
141 | /** | |
142 | * Checks for a suppression of a check with the given source name and | |
143 | * location in the last file processed. | |
144 | * @param event audit event. | |
145 | * @return whether the check with the given name is suppressed at the given | |
146 | * source location | |
147 | */ | |
148 | public static boolean isSuppressed(AuditEvent event) { | |
149 | final List<Entry> entries = ENTRIES.get(); | |
150 | final String sourceName = event.getSourceName(); | |
151 | final String checkAlias = getAlias(sourceName); | |
152 | final int line = event.getLine(); | |
153 | final int column = event.getColumn(); | |
154 | boolean suppressed = false; | |
155 |
1
1. isSuppressed : negated conditional → KILLED |
for (Entry entry : entries) { |
156 | final boolean afterStart = isSuppressedAfterEventStart(line, column, entry); | |
157 | final boolean beforeEnd = isSuppressedBeforeEventEnd(line, column, entry); | |
158 | final boolean nameMatches = | |
159 |
1
1. isSuppressed : negated conditional → KILLED |
ALL_WARNING_MATCHING_ID.equals(entry.getCheckName()) |
160 |
1
1. isSuppressed : negated conditional → KILLED |
|| entry.getCheckName().equalsIgnoreCase(checkAlias); |
161 |
1
1. isSuppressed : negated conditional → KILLED |
final boolean idMatches = event.getModuleId() != null |
162 |
1
1. isSuppressed : negated conditional → KILLED |
&& event.getModuleId().equals(entry.getCheckName()); |
163 |
4
1. isSuppressed : negated conditional → KILLED 2. isSuppressed : negated conditional → KILLED 3. isSuppressed : negated conditional → KILLED 4. isSuppressed : negated conditional → KILLED |
if (afterStart && beforeEnd && (nameMatches || idMatches)) { |
164 | suppressed = true; | |
165 | break; | |
166 | } | |
167 | } | |
168 |
1
1. isSuppressed : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return suppressed; |
169 | } | |
170 | ||
171 | /** | |
172 | * Checks whether suppression entry position is after the audit event occurrence position | |
173 | * in the source file. | |
174 | * @param line the line number in the source file where the event occurred. | |
175 | * @param column the column number in the source file where the event occurred. | |
176 | * @param entry suppression entry. | |
177 | * @return true if suppression entry position is after the audit event occurrence position | |
178 | * in the source file. | |
179 | */ | |
180 | private static boolean isSuppressedAfterEventStart(int line, int column, Entry entry) { | |
181 |
3
1. isSuppressedAfterEventStart : changed conditional boundary → KILLED 2. isSuppressedAfterEventStart : negated conditional → KILLED 3. isSuppressedAfterEventStart : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return entry.getFirstLine() < line |
182 |
2
1. isSuppressedAfterEventStart : negated conditional → KILLED 2. isSuppressedAfterEventStart : negated conditional → KILLED |
|| entry.getFirstLine() == line |
183 |
2
1. isSuppressedAfterEventStart : changed conditional boundary → KILLED 2. isSuppressedAfterEventStart : negated conditional → KILLED |
&& (column == 0 || entry.getFirstColumn() <= column); |
184 | } | |
185 | ||
186 | /** | |
187 | * Checks whether suppression entry position is before the audit event occurrence position | |
188 | * in the source file. | |
189 | * @param line the line number in the source file where the event occurred. | |
190 | * @param column the column number in the source file where the event occurred. | |
191 | * @param entry suppression entry. | |
192 | * @return true if suppression entry position is before the audit event occurrence position | |
193 | * in the source file. | |
194 | */ | |
195 | private static boolean isSuppressedBeforeEventEnd(int line, int column, Entry entry) { | |
196 |
3
1. isSuppressedBeforeEventEnd : changed conditional boundary → KILLED 2. isSuppressedBeforeEventEnd : negated conditional → KILLED 3. isSuppressedBeforeEventEnd : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return entry.getLastLine() > line |
197 |
1
1. isSuppressedBeforeEventEnd : negated conditional → KILLED |
|| entry.getLastLine() == line && entry |
198 |
2
1. isSuppressedBeforeEventEnd : changed conditional boundary → KILLED 2. isSuppressedBeforeEventEnd : negated conditional → KILLED |
.getLastColumn() >= column; |
199 | } | |
200 | ||
201 | @Override | |
202 | public int[] getDefaultTokens() { | |
203 |
1
1. getDefaultTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return getAcceptableTokens(); |
204 | } | |
205 | ||
206 | @Override | |
207 | public int[] getAcceptableTokens() { | |
208 |
1
1. getAcceptableTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return new int[] {TokenTypes.ANNOTATION}; |
209 | } | |
210 | ||
211 | @Override | |
212 | public int[] getRequiredTokens() { | |
213 |
1
1. getRequiredTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return getAcceptableTokens(); |
214 | } | |
215 | ||
216 | @Override | |
217 | public void beginTree(DetailAST rootAST) { | |
218 |
1
1. beginTree : removed call to java/util/List::clear → SURVIVED |
ENTRIES.get().clear(); |
219 | } | |
220 | ||
221 | @Override | |
222 | public void visitToken(DetailAST ast) { | |
223 | // check whether annotation is SuppressWarnings | |
224 | // expected children: AT ( IDENT | DOT ) LPAREN <values> RPAREN | |
225 | String identifier = getIdentifier(getNthChild(ast, 1)); | |
226 |
1
1. visitToken : negated conditional → KILLED |
if (identifier.startsWith(JAVA_LANG_PREFIX)) { |
227 | identifier = identifier.substring(JAVA_LANG_PREFIX.length()); | |
228 | } | |
229 |
1
1. visitToken : negated conditional → KILLED |
if ("SuppressWarnings".equals(identifier)) { |
230 | ||
231 | final List<String> values = getAllAnnotationValues(ast); | |
232 |
1
1. visitToken : negated conditional → KILLED |
if (!isAnnotationEmpty(values)) { |
233 | final DetailAST targetAST = getAnnotationTarget(ast); | |
234 | ||
235 |
1
1. visitToken : negated conditional → KILLED |
if (targetAST == null) { |
236 |
1
1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::log → KILLED |
log(ast.getLineNo(), MSG_KEY); |
237 | } | |
238 | else { | |
239 | // get text range of target | |
240 | final int firstLine = targetAST.getLineNo(); | |
241 | final int firstColumn = targetAST.getColumnNo(); | |
242 | final DetailAST nextAST = targetAST.getNextSibling(); | |
243 | final int lastLine; | |
244 | final int lastColumn; | |
245 |
1
1. visitToken : negated conditional → KILLED |
if (nextAST == null) { |
246 | lastLine = Integer.MAX_VALUE; | |
247 | lastColumn = Integer.MAX_VALUE; | |
248 | } | |
249 | else { | |
250 | lastLine = nextAST.getLineNo(); | |
251 |
1
1. visitToken : Replaced integer subtraction with addition → SURVIVED |
lastColumn = nextAST.getColumnNo() - 1; |
252 | } | |
253 | ||
254 | // add suppression entries for listed checks | |
255 | final List<Entry> entries = ENTRIES.get(); | |
256 |
1
1. visitToken : negated conditional → KILLED |
for (String value : values) { |
257 | String checkName = value; | |
258 | // strip off the checkstyle-only prefix if present | |
259 | checkName = removeCheckstylePrefixIfExists(checkName); | |
260 | entries.add(new Entry(checkName, firstLine, firstColumn, | |
261 | lastLine, lastColumn)); | |
262 | } | |
263 | } | |
264 | } | |
265 | } | |
266 | } | |
267 | ||
268 | /** | |
269 | * Method removes checkstyle prefix (checkstyle:) from check name if exists. | |
270 | * | |
271 | * @param checkName | |
272 | * - name of the check | |
273 | * @return check name without prefix | |
274 | */ | |
275 | private static String removeCheckstylePrefixIfExists(String checkName) { | |
276 | String result = checkName; | |
277 |
1
1. removeCheckstylePrefixIfExists : negated conditional → KILLED |
if (checkName.startsWith(CHECKSTYLE_PREFIX)) { |
278 | result = checkName.substring(CHECKSTYLE_PREFIX.length()); | |
279 | } | |
280 |
1
1. removeCheckstylePrefixIfExists : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::removeCheckstylePrefixIfExists to ( if (x != null) null else throw new RuntimeException ) → SURVIVED |
return result; |
281 | } | |
282 | ||
283 | /** | |
284 | * Get all annotation values. | |
285 | * @param ast annotation token | |
286 | * @return list values | |
287 | */ | |
288 | private static List<String> getAllAnnotationValues(DetailAST ast) { | |
289 | // get values of annotation | |
290 | List<String> values = null; | |
291 | final DetailAST lparenAST = ast.findFirstToken(TokenTypes.LPAREN); | |
292 |
1
1. getAllAnnotationValues : negated conditional → KILLED |
if (lparenAST != null) { |
293 | final DetailAST nextAST = lparenAST.getNextSibling(); | |
294 | final int nextType = nextAST.getType(); | |
295 | switch (nextType) { | |
296 | case TokenTypes.EXPR: | |
297 | case TokenTypes.ANNOTATION_ARRAY_INIT: | |
298 | values = getAnnotationValues(nextAST); | |
299 | break; | |
300 | ||
301 | case TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR: | |
302 | // expected children: IDENT ASSIGN ( EXPR | | |
303 | // ANNOTATION_ARRAY_INIT ) | |
304 | values = getAnnotationValues(getNthChild(nextAST, 2)); | |
305 | break; | |
306 | ||
307 | case TokenTypes.RPAREN: | |
308 | // no value present (not valid Java) | |
309 | break; | |
310 | ||
311 | default: | |
312 | // unknown annotation value type (new syntax?) | |
313 | throw new IllegalArgumentException("Unexpected AST: " + nextAST); | |
314 | } | |
315 | } | |
316 |
1
1. getAllAnnotationValues : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::getAllAnnotationValues to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return values; |
317 | } | |
318 | ||
319 | /** | |
320 | * Checks that annotation is empty. | |
321 | * @param values list of values in the annotation | |
322 | * @return whether annotation is empty or contains some values | |
323 | */ | |
324 | private static boolean isAnnotationEmpty(List<String> values) { | |
325 |
2
1. isAnnotationEmpty : negated conditional → KILLED 2. isAnnotationEmpty : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return values == null; |
326 | } | |
327 | ||
328 | /** | |
329 | * Get target of annotation. | |
330 | * @param ast the AST node to get the child of | |
331 | * @return get target of annotation | |
332 | */ | |
333 | private static DetailAST getAnnotationTarget(DetailAST ast) { | |
334 | final DetailAST targetAST; | |
335 | final DetailAST parentAST = ast.getParent(); | |
336 | switch (parentAST.getType()) { | |
337 | case TokenTypes.MODIFIERS: | |
338 | case TokenTypes.ANNOTATIONS: | |
339 | targetAST = getAcceptableParent(parentAST); | |
340 | break; | |
341 | default: | |
342 | // unexpected container type | |
343 | throw new IllegalArgumentException("Unexpected container AST: " + parentAST); | |
344 | } | |
345 |
1
1. getAnnotationTarget : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::getAnnotationTarget to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return targetAST; |
346 | } | |
347 | ||
348 | /** | |
349 | * Returns parent of given ast if parent has one of the following types: | |
350 | * ANNOTATION_DEF, PACKAGE_DEF, CLASS_DEF, ENUM_DEF, ENUM_CONSTANT_DEF, CTOR_DEF, | |
351 | * METHOD_DEF, PARAMETER_DEF, VARIABLE_DEF, ANNOTATION_FIELD_DEF, TYPE, LITERAL_NEW, | |
352 | * LITERAL_THROWS, TYPE_ARGUMENT, IMPLEMENTS_CLAUSE, DOT. | |
353 | * @param child an ast | |
354 | * @return returns ast - parent of given | |
355 | */ | |
356 | private static DetailAST getAcceptableParent(DetailAST child) { | |
357 | final DetailAST result; | |
358 | final DetailAST parent = child.getParent(); | |
359 | switch (parent.getType()) { | |
360 | case TokenTypes.ANNOTATION_DEF: | |
361 | case TokenTypes.PACKAGE_DEF: | |
362 | case TokenTypes.CLASS_DEF: | |
363 | case TokenTypes.INTERFACE_DEF: | |
364 | case TokenTypes.ENUM_DEF: | |
365 | case TokenTypes.ENUM_CONSTANT_DEF: | |
366 | case TokenTypes.CTOR_DEF: | |
367 | case TokenTypes.METHOD_DEF: | |
368 | case TokenTypes.PARAMETER_DEF: | |
369 | case TokenTypes.VARIABLE_DEF: | |
370 | case TokenTypes.ANNOTATION_FIELD_DEF: | |
371 | case TokenTypes.TYPE: | |
372 | case TokenTypes.LITERAL_NEW: | |
373 | case TokenTypes.LITERAL_THROWS: | |
374 | case TokenTypes.TYPE_ARGUMENT: | |
375 | case TokenTypes.IMPLEMENTS_CLAUSE: | |
376 | case TokenTypes.DOT: | |
377 | result = parent; | |
378 | break; | |
379 | default: | |
380 | // it's possible case, but shouldn't be processed here | |
381 | result = null; | |
382 | } | |
383 |
1
1. getAcceptableParent : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::getAcceptableParent to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return result; |
384 | } | |
385 | ||
386 | /** | |
387 | * Returns the n'th child of an AST node. | |
388 | * @param ast the AST node to get the child of | |
389 | * @param index the index of the child to get | |
390 | * @return the n'th child of the given AST node, or {@code null} if none | |
391 | */ | |
392 | private static DetailAST getNthChild(DetailAST ast, int index) { | |
393 | DetailAST child = ast.getFirstChild(); | |
394 |
4
1. getNthChild : changed conditional boundary → KILLED 2. getNthChild : Changed increment from 1 to -1 → KILLED 3. getNthChild : negated conditional → KILLED 4. getNthChild : negated conditional → KILLED |
for (int i = 0; i < index && child != null; ++i) { |
395 | child = child.getNextSibling(); | |
396 | } | |
397 |
1
1. getNthChild : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::getNthChild to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return child; |
398 | } | |
399 | ||
400 | /** | |
401 | * Returns the Java identifier represented by an AST. | |
402 | * @param ast an AST node for an IDENT or DOT | |
403 | * @return the Java identifier represented by the given AST subtree | |
404 | * @throws IllegalArgumentException if the AST is invalid | |
405 | */ | |
406 | private static String getIdentifier(DetailAST ast) { | |
407 |
1
1. getIdentifier : negated conditional → KILLED |
if (ast == null) { |
408 | throw new IllegalArgumentException("Identifier AST expected, but get null."); | |
409 | } | |
410 | final String identifier; | |
411 |
1
1. getIdentifier : negated conditional → KILLED |
if (ast.getType() == TokenTypes.IDENT) { |
412 | identifier = ast.getText(); | |
413 | } | |
414 | else { | |
415 | identifier = getIdentifier(ast.getFirstChild()) + "." | |
416 | + getIdentifier(ast.getLastChild()); | |
417 | } | |
418 |
1
1. getIdentifier : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::getIdentifier to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return identifier; |
419 | } | |
420 | ||
421 | /** | |
422 | * Returns the literal string expression represented by an AST. | |
423 | * @param ast an AST node for an EXPR | |
424 | * @return the Java string represented by the given AST expression | |
425 | * or empty string if expression is too complex | |
426 | * @throws IllegalArgumentException if the AST is invalid | |
427 | */ | |
428 | private static String getStringExpr(DetailAST ast) { | |
429 | final DetailAST firstChild = ast.getFirstChild(); | |
430 | String expr = ""; | |
431 | ||
432 | switch (firstChild.getType()) { | |
433 | case TokenTypes.STRING_LITERAL: | |
434 | // NOTE: escaped characters are not unescaped | |
435 | final String quotedText = firstChild.getText(); | |
436 |
1
1. getStringExpr : Replaced integer subtraction with addition → KILLED |
expr = quotedText.substring(1, quotedText.length() - 1); |
437 | break; | |
438 | case TokenTypes.IDENT: | |
439 | expr = firstChild.getText(); | |
440 | break; | |
441 | case TokenTypes.DOT: | |
442 | expr = firstChild.getLastChild().getText(); | |
443 | break; | |
444 | default: | |
445 | // annotations with complex expressions cannot suppress warnings | |
446 | } | |
447 |
1
1. getStringExpr : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::getStringExpr to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return expr; |
448 | } | |
449 | ||
450 | /** | |
451 | * Returns the annotation values represented by an AST. | |
452 | * @param ast an AST node for an EXPR or ANNOTATION_ARRAY_INIT | |
453 | * @return the list of Java string represented by the given AST for an | |
454 | * expression or annotation array initializer | |
455 | * @throws IllegalArgumentException if the AST is invalid | |
456 | */ | |
457 | private static List<String> getAnnotationValues(DetailAST ast) { | |
458 | final List<String> annotationValues; | |
459 | switch (ast.getType()) { | |
460 | case TokenTypes.EXPR: | |
461 | annotationValues = Collections.singletonList(getStringExpr(ast)); | |
462 | break; | |
463 | case TokenTypes.ANNOTATION_ARRAY_INIT: | |
464 | annotationValues = findAllExpressionsInChildren(ast); | |
465 | break; | |
466 | default: | |
467 | throw new IllegalArgumentException( | |
468 | "Expression or annotation array initializer AST expected: " + ast); | |
469 | } | |
470 |
1
1. getAnnotationValues : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::getAnnotationValues to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return annotationValues; |
471 | } | |
472 | ||
473 | /** | |
474 | * Method looks at children and returns list of expressions in strings. | |
475 | * @param parent ast, that contains children | |
476 | * @return list of expressions in strings | |
477 | */ | |
478 | private static List<String> findAllExpressionsInChildren(DetailAST parent) { | |
479 | final List<String> valueList = new LinkedList<>(); | |
480 | DetailAST childAST = parent.getFirstChild(); | |
481 |
1
1. findAllExpressionsInChildren : negated conditional → SURVIVED |
while (childAST != null) { |
482 |
1
1. findAllExpressionsInChildren : negated conditional → KILLED |
if (childAST.getType() == TokenTypes.EXPR) { |
483 | valueList.add(getStringExpr(childAST)); | |
484 | } | |
485 | childAST = childAST.getNextSibling(); | |
486 | } | |
487 |
1
1. findAllExpressionsInChildren : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder::findAllExpressionsInChildren to ( if (x != null) null else throw new RuntimeException ) → SURVIVED |
return valueList; |
488 | } | |
489 | ||
490 | /** Records a particular suppression for a region of a file. */ | |
491 | private static class Entry { | |
492 | /** The source name of the suppressed check. */ | |
493 | private final String checkName; | |
494 | /** The suppression region for the check - first line. */ | |
495 | private final int firstLine; | |
496 | /** The suppression region for the check - first column. */ | |
497 | private final int firstColumn; | |
498 | /** The suppression region for the check - last line. */ | |
499 | private final int lastLine; | |
500 | /** The suppression region for the check - last column. */ | |
501 | private final int lastColumn; | |
502 | ||
503 | /** | |
504 | * Constructs a new suppression region entry. | |
505 | * @param checkName the source name of the suppressed check | |
506 | * @param firstLine the first line of the suppression region | |
507 | * @param firstColumn the first column of the suppression region | |
508 | * @param lastLine the last line of the suppression region | |
509 | * @param lastColumn the last column of the suppression region | |
510 | */ | |
511 | Entry(String checkName, int firstLine, int firstColumn, | |
512 | int lastLine, int lastColumn) { | |
513 | this.checkName = checkName; | |
514 | this.firstLine = firstLine; | |
515 | this.firstColumn = firstColumn; | |
516 | this.lastLine = lastLine; | |
517 | this.lastColumn = lastColumn; | |
518 | } | |
519 | ||
520 | /** | |
521 | * Gets he source name of the suppressed check. | |
522 | * @return the source name of the suppressed check | |
523 | */ | |
524 | public String getCheckName() { | |
525 | return checkName; | |
526 | } | |
527 | ||
528 | /** | |
529 | * Gets the first line of the suppression region. | |
530 | * @return the first line of the suppression region | |
531 | */ | |
532 | public int getFirstLine() { | |
533 | return firstLine; | |
534 | } | |
535 | ||
536 | /** | |
537 | * Gets the first column of the suppression region. | |
538 | * @return the first column of the suppression region | |
539 | */ | |
540 | public int getFirstColumn() { | |
541 | return firstColumn; | |
542 | } | |
543 | ||
544 | /** | |
545 | * Gets the last line of the suppression region. | |
546 | * @return the last line of the suppression region | |
547 | */ | |
548 | public int getLastLine() { | |
549 | return lastLine; | |
550 | } | |
551 | ||
552 | /** | |
553 | * Gets the last column of the suppression region. | |
554 | * @return the last column of the suppression region | |
555 | */ | |
556 | public int getLastColumn() { | |
557 | return lastColumn; | |
558 | } | |
559 | } | |
560 | } | |
Mutations | ||
87 |
1.1 |
|
88 |
1.1 |
|
90 |
1.1 |
|
91 |
1.1 |
|
104 |
1.1 |
|
107 |
1.1 |
|
128 |
1.1 2.2 3.3 |
|
130 |
1.1 2.2 |
|
131 |
1.1 2.2 |
|
134 |
1.1 |
|
155 |
1.1 |
|
159 |
1.1 |
|
160 |
1.1 |
|
161 |
1.1 |
|
162 |
1.1 |
|
163 |
1.1 2.2 3.3 4.4 |
|
168 |
1.1 |
|
181 |
1.1 2.2 3.3 |
|
182 |
1.1 2.2 |
|
183 |
1.1 2.2 |
|
196 |
1.1 2.2 3.3 |
|
197 |
1.1 |
|
198 |
1.1 2.2 |
|
203 |
1.1 |
|
208 |
1.1 |
|
213 |
1.1 |
|
218 |
1.1 |
|
226 |
1.1 |
|
229 |
1.1 |
|
232 |
1.1 |
|
235 |
1.1 |
|
236 |
1.1 |
|
245 |
1.1 |
|
251 |
1.1 |
|
256 |
1.1 |
|
277 |
1.1 |
|
280 |
1.1 |
|
292 |
1.1 |
|
316 |
1.1 |
|
325 |
1.1 2.2 |
|
345 |
1.1 |
|
383 |
1.1 |
|
394 |
1.1 2.2 3.3 4.4 |
|
397 |
1.1 |
|
407 |
1.1 |
|
411 |
1.1 |
|
418 |
1.1 |
|
436 |
1.1 |
|
447 |
1.1 |
|
470 |
1.1 |
|
481 |
1.1 |
|
482 |
1.1 |
|
487 |
1.1 |