| 1 | //////////////////////////////////////////////////////////////////////////////// | |
| 2 | // checkstyle: Checks Java source code for adherence to a set of rules. | |
| 3 | // Copyright (C) 2001-2018 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.coding; | |
| 21 | ||
| 22 | import java.util.HashSet; | |
| 23 | import java.util.Locale; | |
| 24 | import java.util.Objects; | |
| 25 | import java.util.Set; | |
| 26 | import java.util.regex.Pattern; | |
| 27 | ||
| 28 | import com.puppycrawl.tools.checkstyle.FileStatefulCheck; | |
| 29 | import com.puppycrawl.tools.checkstyle.api.AbstractCheck; | |
| 30 | import com.puppycrawl.tools.checkstyle.api.DetailAST; | |
| 31 | import com.puppycrawl.tools.checkstyle.api.Scope; | |
| 32 | import com.puppycrawl.tools.checkstyle.api.TokenTypes; | |
| 33 | import com.puppycrawl.tools.checkstyle.utils.CheckUtils; | |
| 34 | import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; | |
| 35 | ||
| 36 | /** | |
| 37 | * Checks that a local variable or a parameter does not shadow | |
| 38 | * a field that is defined in the same class. | |
| 39 | * | |
| 40 | * <p>An example of how to configure the check is: | |
| 41 | * <pre> | |
| 42 | * <module name="HiddenField"/> | |
| 43 | * </pre> | |
| 44 | * | |
| 45 | * <p>An example of how to configure the check so that it checks variables but not | |
| 46 | * parameters is: | |
| 47 | * <pre> | |
| 48 | * <module name="HiddenField"> | |
| 49 | * <property name="tokens" value="VARIABLE_DEF"/> | |
| 50 | * </module> | |
| 51 | * </pre> | |
| 52 | * | |
| 53 | * <p>An example of how to configure the check so that it ignores the parameter of | |
| 54 | * a setter method is: | |
| 55 | * <pre> | |
| 56 | * <module name="HiddenField"> | |
| 57 | * <property name="ignoreSetter" value="true"/> | |
| 58 | * </module> | |
| 59 | * </pre> | |
| 60 | * | |
| 61 | * <p>A method is recognized as a setter if it is in the following form | |
| 62 | * <pre> | |
| 63 | * ${returnType} set${Name}(${anyType} ${name}) { ... } | |
| 64 | * </pre> | |
| 65 | * where ${anyType} is any primitive type, class or interface name; | |
| 66 | * ${name} is name of the variable that is being set and ${Name} its | |
| 67 | * capitalized form that appears in the method name. By default it is expected | |
| 68 | * that setter returns void, i.e. ${returnType} is 'void'. For example | |
| 69 | * <pre> | |
| 70 | * void setTime(long time) { ... } | |
| 71 | * </pre> | |
| 72 | * Any other return types will not let method match a setter pattern. However, | |
| 73 | * by setting <em>setterCanReturnItsClass</em> property to <em>true</em> | |
| 74 | * definition of a setter is expanded, so that setter return type can also be | |
| 75 | * a class in which setter is declared. For example | |
| 76 | * <pre> | |
| 77 | * class PageBuilder { | |
| 78 | * PageBuilder setName(String name) { ... } | |
| 79 | * } | |
| 80 | * </pre> | |
| 81 | * Such methods are known as chain-setters and a common when Builder-pattern | |
| 82 | * is used. Property <em>setterCanReturnItsClass</em> has effect only if | |
| 83 | * <em>ignoreSetter</em> is set to true. | |
| 84 | * | |
| 85 | * <p>An example of how to configure the check so that it ignores the parameter | |
| 86 | * of either a setter that returns void or a chain-setter. | |
| 87 | * <pre> | |
| 88 | * <module name="HiddenField"> | |
| 89 | * <property name="ignoreSetter" value="true"/> | |
| 90 | * <property name="setterCanReturnItsClass" value="true"/> | |
| 91 | * </module> | |
| 92 | * </pre> | |
| 93 | * | |
| 94 | * <p>An example of how to configure the check so that it ignores constructor | |
| 95 | * parameters is: | |
| 96 | * <pre> | |
| 97 | * <module name="HiddenField"> | |
| 98 | * <property name="ignoreConstructorParameter" value="true"/> | |
| 99 | * </module> | |
| 100 | * </pre> | |
| 101 | * | |
| 102 | * <p>An example of how to configure the check so that it ignores variables and parameters | |
| 103 | * named 'test': | |
| 104 | * <pre> | |
| 105 | * <module name="HiddenField"> | |
| 106 | * <property name="ignoreFormat" value="^test$"/> | |
| 107 | * </module> | |
| 108 | * </pre> | |
| 109 | * | |
| 110 | * <pre> | |
| 111 | * {@code | |
| 112 | * class SomeClass | |
| 113 | * { | |
| 114 | * private List<String> test; | |
| 115 | * | |
| 116 | * private void addTest(List<String> test) // no violation | |
| 117 | * { | |
| 118 | * this.test.addAll(test); | |
| 119 | * } | |
| 120 | * | |
| 121 | * private void foo() | |
| 122 | * { | |
| 123 | * final List<String> test = new ArrayList<>(); // no violation | |
| 124 | * ... | |
| 125 | * } | |
| 126 | * } | |
| 127 | * } | |
| 128 | * </pre> | |
| 129 | * | |
| 130 | * @author Dmitri Priimak | |
| 131 | */ | |
| 132 | @FileStatefulCheck | |
| 133 | public class HiddenFieldCheck | |
| 134 | extends AbstractCheck { | |
| 135 | ||
| 136 | /** | |
| 137 | * A key is pointing to the warning message text in "messages.properties" | |
| 138 | * file. | |
| 139 | */ | |
| 140 | public static final String MSG_KEY = "hidden.field"; | |
| 141 | ||
| 142 | /** Stack of sets of field names, | |
| 143 | * one for each class of a set of nested classes. | |
| 144 | */ | |
| 145 | private FieldFrame frame; | |
| 146 | ||
| 147 | /** Pattern for names of variables and parameters to ignore. */ | |
| 148 | private Pattern ignoreFormat; | |
| 149 | ||
| 150 | /** Controls whether to check the parameter of a property setter method. */ | |
| 151 | private boolean ignoreSetter; | |
| 152 | ||
| 153 | /** | |
| 154 | * If ignoreSetter is set to true then this variable controls what | |
| 155 | * the setter method can return By default setter must return void. | |
| 156 | * However, is this variable is set to true then setter can also | |
| 157 | * return class in which is declared. | |
| 158 | */ | |
| 159 | private boolean setterCanReturnItsClass; | |
| 160 | ||
| 161 | /** Controls whether to check the parameter of a constructor. */ | |
| 162 | private boolean ignoreConstructorParameter; | |
| 163 | ||
| 164 | /** Controls whether to check the parameter of abstract methods. */ | |
| 165 | private boolean ignoreAbstractMethods; | |
| 166 | ||
| 167 | @Override | |
| 168 | public int[] getDefaultTokens() { | |
| 169 |
1
1. getDefaultTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return getAcceptableTokens(); |
| 170 | } | |
| 171 | ||
| 172 | @Override | |
| 173 | public int[] getAcceptableTokens() { | |
| 174 |
1
1. getAcceptableTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return new int[] { |
| 175 | TokenTypes.VARIABLE_DEF, | |
| 176 | TokenTypes.PARAMETER_DEF, | |
| 177 | TokenTypes.CLASS_DEF, | |
| 178 | TokenTypes.ENUM_DEF, | |
| 179 | TokenTypes.ENUM_CONSTANT_DEF, | |
| 180 | TokenTypes.LAMBDA, | |
| 181 | }; | |
| 182 | } | |
| 183 | ||
| 184 | @Override | |
| 185 | public int[] getRequiredTokens() { | |
| 186 |
1
1. getRequiredTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return new int[] { |
| 187 | TokenTypes.CLASS_DEF, | |
| 188 | TokenTypes.ENUM_DEF, | |
| 189 | TokenTypes.ENUM_CONSTANT_DEF, | |
| 190 | }; | |
| 191 | } | |
| 192 | ||
| 193 | @Override | |
| 194 | public void beginTree(DetailAST rootAST) { | |
| 195 | frame = new FieldFrame(null, true, null); | |
| 196 | } | |
| 197 | ||
| 198 | @Override | |
| 199 | public void visitToken(DetailAST ast) { | |
| 200 | final int type = ast.getType(); | |
| 201 | switch (type) { | |
| 202 | case TokenTypes.VARIABLE_DEF: | |
| 203 | case TokenTypes.PARAMETER_DEF: | |
| 204 |
1
1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck::processVariable → KILLED |
processVariable(ast); |
| 205 | break; | |
| 206 | case TokenTypes.LAMBDA: | |
| 207 |
1
1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck::processLambda → KILLED |
processLambda(ast); |
| 208 | break; | |
| 209 | default: | |
| 210 |
1
1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck::visitOtherTokens → KILLED |
visitOtherTokens(ast, type); |
| 211 | } | |
| 212 | } | |
| 213 | ||
| 214 | /** | |
| 215 | * Process a lambda token. | |
| 216 | * Checks whether a lambda parameter shadows a field. | |
| 217 | * Note, that when parameter of lambda expression is untyped, | |
| 218 | * ANTLR parses the parameter as an identifier. | |
| 219 | * @param ast the lambda token. | |
| 220 | */ | |
| 221 | private void processLambda(DetailAST ast) { | |
| 222 | final DetailAST firstChild = ast.getFirstChild(); | |
| 223 |
1
1. processLambda : negated conditional → KILLED |
if (firstChild.getType() == TokenTypes.IDENT) { |
| 224 | final String untypedLambdaParameterName = firstChild.getText(); | |
| 225 |
1
1. processLambda : negated conditional → KILLED |
if (frame.containsStaticField(untypedLambdaParameterName) |
| 226 |
1
1. processLambda : negated conditional → KILLED |
|| isInstanceField(firstChild, untypedLambdaParameterName)) { |
| 227 |
1
1. processLambda : removed call to com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck::log → KILLED |
log(firstChild, MSG_KEY, untypedLambdaParameterName); |
| 228 | } | |
| 229 | } | |
| 230 | else { | |
| 231 | // Type of lambda parameter is not omitted. | |
| 232 |
1
1. processLambda : removed call to com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck::processVariable → SURVIVED |
processVariable(ast); |
| 233 | } | |
| 234 | } | |
| 235 | ||
| 236 | /** | |
| 237 | * Called to process tokens other than {@link TokenTypes#VARIABLE_DEF} | |
| 238 | * and {@link TokenTypes#PARAMETER_DEF}. | |
| 239 | * | |
| 240 | * @param ast token to process | |
| 241 | * @param type type of the token | |
| 242 | */ | |
| 243 | private void visitOtherTokens(DetailAST ast, int type) { | |
| 244 | //A more thorough check of enum constant class bodies is | |
| 245 | //possible (checking for hidden fields against the enum | |
| 246 | //class body in addition to enum constant class bodies) | |
| 247 | //but not attempted as it seems out of the scope of this | |
| 248 | //check. | |
| 249 | final DetailAST typeMods = ast.findFirstToken(TokenTypes.MODIFIERS); | |
| 250 |
1
1. visitOtherTokens : negated conditional → KILLED |
final boolean isStaticInnerType = |
| 251 | typeMods != null | |
| 252 |
1
1. visitOtherTokens : negated conditional → KILLED |
&& typeMods.findFirstToken(TokenTypes.LITERAL_STATIC) != null; |
| 253 | final String frameName; | |
| 254 | ||
| 255 |
2
1. visitOtherTokens : negated conditional → KILLED 2. visitOtherTokens : negated conditional → KILLED |
if (type == TokenTypes.CLASS_DEF || type == TokenTypes.ENUM_DEF) { |
| 256 | frameName = ast.findFirstToken(TokenTypes.IDENT).getText(); | |
| 257 | } | |
| 258 | else { | |
| 259 | frameName = null; | |
| 260 | } | |
| 261 | final FieldFrame newFrame = new FieldFrame(frame, isStaticInnerType, frameName); | |
| 262 | ||
| 263 | //add fields to container | |
| 264 | final DetailAST objBlock = ast.findFirstToken(TokenTypes.OBJBLOCK); | |
| 265 | // enum constants may not have bodies | |
| 266 |
1
1. visitOtherTokens : negated conditional → KILLED |
if (objBlock != null) { |
| 267 | DetailAST child = objBlock.getFirstChild(); | |
| 268 |
1
1. visitOtherTokens : negated conditional → KILLED |
while (child != null) { |
| 269 |
1
1. visitOtherTokens : negated conditional → KILLED |
if (child.getType() == TokenTypes.VARIABLE_DEF) { |
| 270 | final String name = | |
| 271 | child.findFirstToken(TokenTypes.IDENT).getText(); | |
| 272 | final DetailAST mods = | |
| 273 | child.findFirstToken(TokenTypes.MODIFIERS); | |
| 274 |
1
1. visitOtherTokens : negated conditional → KILLED |
if (mods.findFirstToken(TokenTypes.LITERAL_STATIC) == null) { |
| 275 |
1
1. visitOtherTokens : removed call to com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck$FieldFrame::addInstanceField → KILLED |
newFrame.addInstanceField(name); |
| 276 | } | |
| 277 | else { | |
| 278 |
1
1. visitOtherTokens : removed call to com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck$FieldFrame::addStaticField → KILLED |
newFrame.addStaticField(name); |
| 279 | } | |
| 280 | } | |
| 281 | child = child.getNextSibling(); | |
| 282 | } | |
| 283 | } | |
| 284 | // push container | |
| 285 | frame = newFrame; | |
| 286 | } | |
| 287 | ||
| 288 | @Override | |
| 289 | public void leaveToken(DetailAST ast) { | |
| 290 |
1
1. leaveToken : negated conditional → KILLED |
if (ast.getType() == TokenTypes.CLASS_DEF |
| 291 |
1
1. leaveToken : negated conditional → KILLED |
|| ast.getType() == TokenTypes.ENUM_DEF |
| 292 |
1
1. leaveToken : negated conditional → KILLED |
|| ast.getType() == TokenTypes.ENUM_CONSTANT_DEF) { |
| 293 | //pop | |
| 294 | frame = frame.getParent(); | |
| 295 | } | |
| 296 | } | |
| 297 | ||
| 298 | /** | |
| 299 | * Process a variable token. | |
| 300 | * Check whether a local variable or parameter shadows a field. | |
| 301 | * Store a field for later comparison with local variables and parameters. | |
| 302 | * @param ast the variable token. | |
| 303 | */ | |
| 304 | private void processVariable(DetailAST ast) { | |
| 305 |
1
1. processVariable : negated conditional → KILLED |
if (!ScopeUtils.isInInterfaceOrAnnotationBlock(ast) |
| 306 |
1
1. processVariable : negated conditional → KILLED |
&& !CheckUtils.isReceiverParameter(ast) |
| 307 |
1
1. processVariable : negated conditional → KILLED |
&& (ScopeUtils.isLocalVariableDef(ast) |
| 308 |
1
1. processVariable : negated conditional → KILLED |
|| ast.getType() == TokenTypes.PARAMETER_DEF)) { |
| 309 | // local variable or parameter. Does it shadow a field? | |
| 310 | final DetailAST nameAST = ast.findFirstToken(TokenTypes.IDENT); | |
| 311 | final String name = nameAST.getText(); | |
| 312 | ||
| 313 |
2
1. processVariable : negated conditional → KILLED 2. processVariable : negated conditional → KILLED |
if ((frame.containsStaticField(name) || isInstanceField(ast, name)) |
| 314 |
1
1. processVariable : negated conditional → KILLED |
&& !isMatchingRegexp(name) |
| 315 |
1
1. processVariable : negated conditional → KILLED |
&& !isIgnoredParam(ast, name)) { |
| 316 |
1
1. processVariable : removed call to com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck::log → KILLED |
log(nameAST, MSG_KEY, name); |
| 317 | } | |
| 318 | } | |
| 319 | } | |
| 320 | ||
| 321 | /** | |
| 322 | * Checks whether method or constructor parameter is ignored. | |
| 323 | * @param ast the parameter token. | |
| 324 | * @param name the parameter name. | |
| 325 | * @return true if parameter is ignored. | |
| 326 | */ | |
| 327 | private boolean isIgnoredParam(DetailAST ast, String name) { | |
| 328 |
2
1. isIgnoredParam : negated conditional → KILLED 2. isIgnoredParam : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return isIgnoredSetterParam(ast, name) |
| 329 |
1
1. isIgnoredParam : negated conditional → KILLED |
|| isIgnoredConstructorParam(ast) |
| 330 |
1
1. isIgnoredParam : negated conditional → KILLED |
|| isIgnoredParamOfAbstractMethod(ast); |
| 331 | } | |
| 332 | ||
| 333 | /** | |
| 334 | * Check for instance field. | |
| 335 | * @param ast token | |
| 336 | * @param name identifier of token | |
| 337 | * @return true if instance field | |
| 338 | */ | |
| 339 | private boolean isInstanceField(DetailAST ast, String name) { | |
| 340 |
3
1. isInstanceField : negated conditional → KILLED 2. isInstanceField : negated conditional → KILLED 3. isInstanceField : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return !isInStatic(ast) && frame.containsInstanceField(name); |
| 341 | } | |
| 342 | ||
| 343 | /** | |
| 344 | * Check name by regExp. | |
| 345 | * @param name string value to check | |
| 346 | * @return true is regexp is matching | |
| 347 | */ | |
| 348 | private boolean isMatchingRegexp(String name) { | |
| 349 |
3
1. isMatchingRegexp : negated conditional → KILLED 2. isMatchingRegexp : negated conditional → KILLED 3. isMatchingRegexp : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return ignoreFormat != null && ignoreFormat.matcher(name).find(); |
| 350 | } | |
| 351 | ||
| 352 | /** | |
| 353 | * Determines whether an AST node is in a static method or static | |
| 354 | * initializer. | |
| 355 | * @param ast the node to check. | |
| 356 | * @return true if ast is in a static method or a static block; | |
| 357 | */ | |
| 358 | private static boolean isInStatic(DetailAST ast) { | |
| 359 | DetailAST parent = ast.getParent(); | |
| 360 | boolean inStatic = false; | |
| 361 | ||
| 362 |
2
1. isInStatic : negated conditional → KILLED 2. isInStatic : negated conditional → KILLED |
while (parent != null && !inStatic) { |
| 363 |
1
1. isInStatic : negated conditional → KILLED |
if (parent.getType() == TokenTypes.STATIC_INIT) { |
| 364 | inStatic = true; | |
| 365 | } | |
| 366 |
1
1. isInStatic : negated conditional → KILLED |
else if (parent.getType() == TokenTypes.METHOD_DEF |
| 367 |
1
1. isInStatic : negated conditional → KILLED |
&& !ScopeUtils.isInScope(parent, Scope.ANONINNER) |
| 368 |
1
1. isInStatic : negated conditional → KILLED |
|| parent.getType() == TokenTypes.VARIABLE_DEF) { |
| 369 | final DetailAST mods = | |
| 370 | parent.findFirstToken(TokenTypes.MODIFIERS); | |
| 371 |
1
1. isInStatic : negated conditional → KILLED |
inStatic = mods.findFirstToken(TokenTypes.LITERAL_STATIC) != null; |
| 372 | break; | |
| 373 | } | |
| 374 | else { | |
| 375 | parent = parent.getParent(); | |
| 376 | } | |
| 377 | } | |
| 378 |
1
1. isInStatic : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return inStatic; |
| 379 | } | |
| 380 | ||
| 381 | /** | |
| 382 | * Decides whether to ignore an AST node that is the parameter of a | |
| 383 | * setter method, where the property setter method for field 'xyz' has | |
| 384 | * name 'setXyz', one parameter named 'xyz', and return type void | |
| 385 | * (default behavior) or return type is name of the class in which | |
| 386 | * such method is declared (allowed only if | |
| 387 | * {@link #setSetterCanReturnItsClass(boolean)} is called with | |
| 388 | * value <em>true</em>). | |
| 389 | * | |
| 390 | * @param ast the AST to check. | |
| 391 | * @param name the name of ast. | |
| 392 | * @return true if ast should be ignored because check property | |
| 393 | * ignoreSetter is true and ast is the parameter of a setter method. | |
| 394 | */ | |
| 395 | private boolean isIgnoredSetterParam(DetailAST ast, String name) { | |
| 396 | boolean isIgnoredSetterParam = false; | |
| 397 |
2
1. isIgnoredSetterParam : negated conditional → KILLED 2. isIgnoredSetterParam : negated conditional → KILLED |
if (ignoreSetter && ast.getType() == TokenTypes.PARAMETER_DEF) { |
| 398 | final DetailAST parametersAST = ast.getParent(); | |
| 399 | final DetailAST methodAST = parametersAST.getParent(); | |
| 400 |
1
1. isIgnoredSetterParam : negated conditional → KILLED |
if (parametersAST.getChildCount() == 1 |
| 401 |
1
1. isIgnoredSetterParam : negated conditional → KILLED |
&& methodAST.getType() == TokenTypes.METHOD_DEF |
| 402 |
1
1. isIgnoredSetterParam : negated conditional → KILLED |
&& isSetterMethod(methodAST, name)) { |
| 403 | isIgnoredSetterParam = true; | |
| 404 | } | |
| 405 | } | |
| 406 |
1
1. isIgnoredSetterParam : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return isIgnoredSetterParam; |
| 407 | } | |
| 408 | ||
| 409 | /** | |
| 410 | * Determine if a specific method identified by methodAST and a single | |
| 411 | * variable name aName is a setter. This recognition partially depends | |
| 412 | * on mSetterCanReturnItsClass property. | |
| 413 | * | |
| 414 | * @param aMethodAST AST corresponding to a method call | |
| 415 | * @param aName name of single parameter of this method. | |
| 416 | * @return true of false indicating of method is a setter or not. | |
| 417 | */ | |
| 418 | private boolean isSetterMethod(DetailAST aMethodAST, String aName) { | |
| 419 | final String methodName = | |
| 420 | aMethodAST.findFirstToken(TokenTypes.IDENT).getText(); | |
| 421 | boolean isSetterMethod = false; | |
| 422 | ||
| 423 |
1
1. isSetterMethod : negated conditional → KILLED |
if (("set" + capitalize(aName)).equals(methodName)) { |
| 424 | // method name did match set${Name}(${anyType} ${aName}) | |
| 425 | // where ${Name} is capitalized version of ${aName} | |
| 426 | // therefore this method is potentially a setter | |
| 427 | final DetailAST typeAST = aMethodAST.findFirstToken(TokenTypes.TYPE); | |
| 428 | final String returnType = typeAST.getFirstChild().getText(); | |
| 429 |
2
1. isSetterMethod : negated conditional → KILLED 2. isSetterMethod : negated conditional → KILLED |
if (typeAST.findFirstToken(TokenTypes.LITERAL_VOID) != null |
| 430 |
1
1. isSetterMethod : negated conditional → KILLED |
|| setterCanReturnItsClass && frame.isEmbeddedIn(returnType)) { |
| 431 | // this method has signature | |
| 432 | // | |
| 433 | // void set${Name}(${anyType} ${name}) | |
| 434 | // | |
| 435 | // and therefore considered to be a setter | |
| 436 | // | |
| 437 | // or | |
| 438 | // | |
| 439 | // return type is not void, but it is the same as the class | |
| 440 | // where method is declared and and mSetterCanReturnItsClass | |
| 441 | // is set to true | |
| 442 | isSetterMethod = true; | |
| 443 | } | |
| 444 | } | |
| 445 | ||
| 446 |
1
1. isSetterMethod : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return isSetterMethod; |
| 447 | } | |
| 448 | ||
| 449 | /** | |
| 450 | * Capitalizes a given property name the way we expect to see it in | |
| 451 | * a setter name. | |
| 452 | * @param name a property name | |
| 453 | * @return capitalized property name | |
| 454 | */ | |
| 455 | private static String capitalize(final String name) { | |
| 456 | String setterName = name; | |
| 457 | // we should not capitalize the first character if the second | |
| 458 | // one is a capital one, since according to JavaBeans spec | |
| 459 | // setXYzz() is a setter for XYzz property, not for xYzz one. | |
| 460 |
2
1. capitalize : negated conditional → KILLED 2. capitalize : negated conditional → KILLED |
if (name.length() == 1 || !Character.isUpperCase(name.charAt(1))) { |
| 461 | setterName = name.substring(0, 1).toUpperCase(Locale.ENGLISH) + name.substring(1); | |
| 462 | } | |
| 463 |
1
1. capitalize : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck::capitalize to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return setterName; |
| 464 | } | |
| 465 | ||
| 466 | /** | |
| 467 | * Decides whether to ignore an AST node that is the parameter of a | |
| 468 | * constructor. | |
| 469 | * @param ast the AST to check. | |
| 470 | * @return true if ast should be ignored because check property | |
| 471 | * ignoreConstructorParameter is true and ast is a constructor parameter. | |
| 472 | */ | |
| 473 | private boolean isIgnoredConstructorParam(DetailAST ast) { | |
| 474 | boolean result = false; | |
| 475 |
1
1. isIgnoredConstructorParam : negated conditional → KILLED |
if (ignoreConstructorParameter |
| 476 |
1
1. isIgnoredConstructorParam : negated conditional → KILLED |
&& ast.getType() == TokenTypes.PARAMETER_DEF) { |
| 477 | final DetailAST parametersAST = ast.getParent(); | |
| 478 | final DetailAST constructorAST = parametersAST.getParent(); | |
| 479 |
1
1. isIgnoredConstructorParam : negated conditional → KILLED |
result = constructorAST.getType() == TokenTypes.CTOR_DEF; |
| 480 | } | |
| 481 |
1
1. isIgnoredConstructorParam : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return result; |
| 482 | } | |
| 483 | ||
| 484 | /** | |
| 485 | * Decides whether to ignore an AST node that is the parameter of an | |
| 486 | * abstract method. | |
| 487 | * @param ast the AST to check. | |
| 488 | * @return true if ast should be ignored because check property | |
| 489 | * ignoreAbstractMethods is true and ast is a parameter of abstract methods. | |
| 490 | */ | |
| 491 | private boolean isIgnoredParamOfAbstractMethod(DetailAST ast) { | |
| 492 | boolean result = false; | |
| 493 |
1
1. isIgnoredParamOfAbstractMethod : negated conditional → KILLED |
if (ignoreAbstractMethods |
| 494 |
1
1. isIgnoredParamOfAbstractMethod : negated conditional → KILLED |
&& ast.getType() == TokenTypes.PARAMETER_DEF) { |
| 495 | final DetailAST method = ast.getParent().getParent(); | |
| 496 |
1
1. isIgnoredParamOfAbstractMethod : negated conditional → KILLED |
if (method.getType() == TokenTypes.METHOD_DEF) { |
| 497 | final DetailAST mods = method.findFirstToken(TokenTypes.MODIFIERS); | |
| 498 |
1
1. isIgnoredParamOfAbstractMethod : negated conditional → KILLED |
result = mods.findFirstToken(TokenTypes.ABSTRACT) != null; |
| 499 | } | |
| 500 | } | |
| 501 |
1
1. isIgnoredParamOfAbstractMethod : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return result; |
| 502 | } | |
| 503 | ||
| 504 | /** | |
| 505 | * Set the ignore format for the specified regular expression. | |
| 506 | * @param pattern a pattern. | |
| 507 | */ | |
| 508 | public void setIgnoreFormat(Pattern pattern) { | |
| 509 | ignoreFormat = pattern; | |
| 510 | } | |
| 511 | ||
| 512 | /** | |
| 513 | * Set whether to ignore the parameter of a property setter method. | |
| 514 | * @param ignoreSetter decide whether to ignore the parameter of | |
| 515 | * a property setter method. | |
| 516 | */ | |
| 517 | public void setIgnoreSetter(boolean ignoreSetter) { | |
| 518 | this.ignoreSetter = ignoreSetter; | |
| 519 | } | |
| 520 | ||
| 521 | /** | |
| 522 | * Controls if setter can return only void (default behavior) or it | |
| 523 | * can also return class in which it is declared. | |
| 524 | * | |
| 525 | * @param aSetterCanReturnItsClass if true then setter can return | |
| 526 | * either void or class in which it is declared. If false then | |
| 527 | * in order to be recognized as setter method (otherwise | |
| 528 | * already recognized as a setter) must return void. Later is | |
| 529 | * the default behavior. | |
| 530 | */ | |
| 531 | public void setSetterCanReturnItsClass( | |
| 532 | boolean aSetterCanReturnItsClass) { | |
| 533 | setterCanReturnItsClass = aSetterCanReturnItsClass; | |
| 534 | } | |
| 535 | ||
| 536 | /** | |
| 537 | * Set whether to ignore constructor parameters. | |
| 538 | * @param ignoreConstructorParameter decide whether to ignore | |
| 539 | * constructor parameters. | |
| 540 | */ | |
| 541 | public void setIgnoreConstructorParameter( | |
| 542 | boolean ignoreConstructorParameter) { | |
| 543 | this.ignoreConstructorParameter = ignoreConstructorParameter; | |
| 544 | } | |
| 545 | ||
| 546 | /** | |
| 547 | * Set whether to ignore parameters of abstract methods. | |
| 548 | * @param ignoreAbstractMethods decide whether to ignore | |
| 549 | * parameters of abstract methods. | |
| 550 | */ | |
| 551 | public void setIgnoreAbstractMethods( | |
| 552 | boolean ignoreAbstractMethods) { | |
| 553 | this.ignoreAbstractMethods = ignoreAbstractMethods; | |
| 554 | } | |
| 555 | ||
| 556 | /** | |
| 557 | * Holds the names of static and instance fields of a type. | |
| 558 | * @author Rick Giles | |
| 559 | */ | |
| 560 | private static class FieldFrame { | |
| 561 | ||
| 562 | /** Name of the frame, such name of the class or enum declaration. */ | |
| 563 | private final String frameName; | |
| 564 | ||
| 565 | /** Is this a static inner type. */ | |
| 566 | private final boolean staticType; | |
| 567 | ||
| 568 | /** Parent frame. */ | |
| 569 | private final FieldFrame parent; | |
| 570 | ||
| 571 | /** Set of instance field names. */ | |
| 572 | private final Set<String> instanceFields = new HashSet<>(); | |
| 573 | ||
| 574 | /** Set of static field names. */ | |
| 575 | private final Set<String> staticFields = new HashSet<>(); | |
| 576 | ||
| 577 | /** | |
| 578 | * Creates new frame. | |
| 579 | * @param parent parent frame. | |
| 580 | * @param staticType is this a static inner type (class or enum). | |
| 581 | * @param frameName name associated with the frame, which can be a | |
| 582 | */ | |
| 583 | FieldFrame(FieldFrame parent, boolean staticType, String frameName) { | |
| 584 | this.parent = parent; | |
| 585 | this.staticType = staticType; | |
| 586 | this.frameName = frameName; | |
| 587 | } | |
| 588 | ||
| 589 | /** | |
| 590 | * Adds an instance field to this FieldFrame. | |
| 591 | * @param field the name of the instance field. | |
| 592 | */ | |
| 593 | public void addInstanceField(String field) { | |
| 594 | instanceFields.add(field); | |
| 595 | } | |
| 596 | ||
| 597 | /** | |
| 598 | * Adds a static field to this FieldFrame. | |
| 599 | * @param field the name of the instance field. | |
| 600 | */ | |
| 601 | public void addStaticField(String field) { | |
| 602 | staticFields.add(field); | |
| 603 | } | |
| 604 | ||
| 605 | /** | |
| 606 | * Determines whether this FieldFrame contains an instance field. | |
| 607 | * @param field the field to check. | |
| 608 | * @return true if this FieldFrame contains instance field field. | |
| 609 | */ | |
| 610 | public boolean containsInstanceField(String field) { | |
| 611 |
4
1. containsInstanceField : negated conditional → KILLED 2. containsInstanceField : negated conditional → KILLED 3. containsInstanceField : negated conditional → KILLED 4. containsInstanceField : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return instanceFields.contains(field) |
| 612 | || parent != null | |
| 613 | && !staticType | |
| 614 |
1
1. containsInstanceField : negated conditional → KILLED |
&& parent.containsInstanceField(field); |
| 615 | } | |
| 616 | ||
| 617 | /** | |
| 618 | * Determines whether this FieldFrame contains a static field. | |
| 619 | * @param field the field to check. | |
| 620 | * @return true if this FieldFrame contains static field field. | |
| 621 | */ | |
| 622 | public boolean containsStaticField(String field) { | |
| 623 |
3
1. containsStaticField : negated conditional → KILLED 2. containsStaticField : negated conditional → KILLED 3. containsStaticField : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return staticFields.contains(field) |
| 624 | || parent != null | |
| 625 |
1
1. containsStaticField : negated conditional → KILLED |
&& parent.containsStaticField(field); |
| 626 | } | |
| 627 | ||
| 628 | /** | |
| 629 | * Getter for parent frame. | |
| 630 | * @return parent frame. | |
| 631 | */ | |
| 632 | public FieldFrame getParent() { | |
| 633 |
1
1. getParent : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck$FieldFrame::getParent to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return parent; |
| 634 | } | |
| 635 | ||
| 636 | /** | |
| 637 | * Check if current frame is embedded in class or enum with | |
| 638 | * specific name. | |
| 639 | * | |
| 640 | * @param classOrEnumName name of class or enum that we are looking | |
| 641 | * for in the chain of field frames. | |
| 642 | * | |
| 643 | * @return true if current frame is embedded in class or enum | |
| 644 | * with name classOrNameName | |
| 645 | */ | |
| 646 | private boolean isEmbeddedIn(String classOrEnumName) { | |
| 647 | FieldFrame currentFrame = this; | |
| 648 | boolean isEmbeddedIn = false; | |
| 649 |
1
1. isEmbeddedIn : negated conditional → KILLED |
while (currentFrame != null) { |
| 650 |
1
1. isEmbeddedIn : negated conditional → KILLED |
if (Objects.equals(currentFrame.frameName, classOrEnumName)) { |
| 651 | isEmbeddedIn = true; | |
| 652 | break; | |
| 653 | } | |
| 654 | currentFrame = currentFrame.parent; | |
| 655 | } | |
| 656 |
1
1. isEmbeddedIn : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return isEmbeddedIn; |
| 657 | } | |
| 658 | ||
| 659 | } | |
| 660 | ||
| 661 | } | |
Mutations | ||
| 169 |
1.1 |
|
| 174 |
1.1 |
|
| 186 |
1.1 |
|
| 204 |
1.1 |
|
| 207 |
1.1 |
|
| 210 |
1.1 |
|
| 223 |
1.1 |
|
| 225 |
1.1 |
|
| 226 |
1.1 |
|
| 227 |
1.1 |
|
| 232 |
1.1 |
|
| 250 |
1.1 |
|
| 252 |
1.1 |
|
| 255 |
1.1 2.2 |
|
| 266 |
1.1 |
|
| 268 |
1.1 |
|
| 269 |
1.1 |
|
| 274 |
1.1 |
|
| 275 |
1.1 |
|
| 278 |
1.1 |
|
| 290 |
1.1 |
|
| 291 |
1.1 |
|
| 292 |
1.1 |
|
| 305 |
1.1 |
|
| 306 |
1.1 |
|
| 307 |
1.1 |
|
| 308 |
1.1 |
|
| 313 |
1.1 2.2 |
|
| 314 |
1.1 |
|
| 315 |
1.1 |
|
| 316 |
1.1 |
|
| 328 |
1.1 2.2 |
|
| 329 |
1.1 |
|
| 330 |
1.1 |
|
| 340 |
1.1 2.2 3.3 |
|
| 349 |
1.1 2.2 3.3 |
|
| 362 |
1.1 2.2 |
|
| 363 |
1.1 |
|
| 366 |
1.1 |
|
| 367 |
1.1 |
|
| 368 |
1.1 |
|
| 371 |
1.1 |
|
| 378 |
1.1 |
|
| 397 |
1.1 2.2 |
|
| 400 |
1.1 |
|
| 401 |
1.1 |
|
| 402 |
1.1 |
|
| 406 |
1.1 |
|
| 423 |
1.1 |
|
| 429 |
1.1 2.2 |
|
| 430 |
1.1 |
|
| 446 |
1.1 |
|
| 460 |
1.1 2.2 |
|
| 463 |
1.1 |
|
| 475 |
1.1 |
|
| 476 |
1.1 |
|
| 479 |
1.1 |
|
| 481 |
1.1 |
|
| 493 |
1.1 |
|
| 494 |
1.1 |
|
| 496 |
1.1 |
|
| 498 |
1.1 |
|
| 501 |
1.1 |
|
| 611 |
1.1 2.2 3.3 4.4 |
|
| 614 |
1.1 |
|
| 623 |
1.1 2.2 3.3 |
|
| 625 |
1.1 |
|
| 633 |
1.1 |
|
| 649 |
1.1 |
|
| 650 |
1.1 |
|
| 656 |
1.1 |