| 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 |