| 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.Arrays; | |
| 23 | import java.util.Collections; | |
| 24 | import java.util.Set; | |
| 25 | import java.util.stream.Collectors; | |
| 26 | ||
| 27 | import com.puppycrawl.tools.checkstyle.api.AbstractCheck; | |
| 28 | import com.puppycrawl.tools.checkstyle.api.DetailAST; | |
| 29 | import com.puppycrawl.tools.checkstyle.api.TokenTypes; | |
| 30 | import com.puppycrawl.tools.checkstyle.utils.CheckUtils; | |
| 31 | import com.puppycrawl.tools.checkstyle.utils.CommonUtils; | |
| 32 | ||
| 33 | /** | |
| 34 | * Check that method/constructor/catch/foreach parameters are final. | |
| 35 | * The user can set the token set to METHOD_DEF, CONSTRUCTOR_DEF, | |
| 36 | * LITERAL_CATCH, FOR_EACH_CLAUSE or any combination of these token | |
| 37 | * types, to control the scope of this check. | |
| 38 | * Default scope is both METHOD_DEF and CONSTRUCTOR_DEF. | |
| 39 | * <p> | |
| 40 | * Check has an option <b>ignorePrimitiveTypes</b> which allows ignoring lack of | |
| 41 | * final modifier at | |
| 42 | * <a href="http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html"> | |
| 43 | * primitive data type</a> parameter. Default value <b>false</b>. | |
| 44 | * </p> | |
| 45 | * E.g.: | |
| 46 | * <p> | |
| 47 | * {@code | |
| 48 | * private void foo(int x) { ... } //parameter is of primitive type | |
| 49 | * } | |
| 50 | * </p> | |
| 51 | * | |
| 52 | * @author lkuehne | |
| 53 | * @author o_sukhodolsky | |
| 54 | * @author Michael Studman | |
| 55 | * @author <a href="mailto:nesterenko-aleksey@list.ru">Aleksey Nesterenko</a> | |
| 56 | */ | |
| 57 | public class FinalParametersCheck extends AbstractCheck { | |
| 58 | ||
| 59 | /** | |
| 60 | * A key is pointing to the warning message text in "messages.properties" | |
| 61 | * file. | |
| 62 | */ | |
| 63 | public static final String MSG_KEY = "final.parameter"; | |
| 64 | ||
| 65 | /** | |
| 66 | * Contains | |
| 67 | * <a href="http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html"> | |
| 68 | * primitive datatypes</a>. | |
| 69 | */ | |
| 70 | private final Set<Integer> primitiveDataTypes = Collections.unmodifiableSet( | |
| 71 | Arrays.stream(new Integer[] { | |
| 72 | TokenTypes.LITERAL_BYTE, | |
| 73 | TokenTypes.LITERAL_SHORT, | |
| 74 | TokenTypes.LITERAL_INT, | |
| 75 | TokenTypes.LITERAL_LONG, | |
| 76 | TokenTypes.LITERAL_FLOAT, | |
| 77 | TokenTypes.LITERAL_DOUBLE, | |
| 78 | TokenTypes.LITERAL_BOOLEAN, | |
| 79 | TokenTypes.LITERAL_CHAR, }) | |
| 80 | .collect(Collectors.toSet())); | |
| 81 | ||
| 82 | /** | |
| 83 | * Option to ignore primitive types as params. | |
| 84 | */ | |
| 85 | private boolean ignorePrimitiveTypes; | |
| 86 | ||
| 87 | /** | |
| 88 | * Sets ignoring primitive types as params. | |
| 89 | * @param ignorePrimitiveTypes true or false. | |
| 90 | */ | |
| 91 | public void setIgnorePrimitiveTypes(boolean ignorePrimitiveTypes) { | |
| 92 | this.ignorePrimitiveTypes = ignorePrimitiveTypes; | |
| 93 | } | |
| 94 | ||
| 95 | @Override | |
| 96 | public int[] getDefaultTokens() { | |
| 97 |
1
1. getDefaultTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/FinalParametersCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return new int[] { |
| 98 | TokenTypes.METHOD_DEF, | |
| 99 | TokenTypes.CTOR_DEF, | |
| 100 | }; | |
| 101 | } | |
| 102 | ||
| 103 | @Override | |
| 104 | public int[] getAcceptableTokens() { | |
| 105 |
1
1. getAcceptableTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/FinalParametersCheck::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return new int[] { |
| 106 | TokenTypes.METHOD_DEF, | |
| 107 | TokenTypes.CTOR_DEF, | |
| 108 | TokenTypes.LITERAL_CATCH, | |
| 109 | TokenTypes.FOR_EACH_CLAUSE, | |
| 110 | }; | |
| 111 | } | |
| 112 | ||
| 113 | @Override | |
| 114 | public int[] getRequiredTokens() { | |
| 115 |
1
1. getRequiredTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/FinalParametersCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return CommonUtils.EMPTY_INT_ARRAY; |
| 116 | } | |
| 117 | ||
| 118 | @Override | |
| 119 | public void visitToken(DetailAST ast) { | |
| 120 | // don't flag interfaces | |
| 121 | final DetailAST container = ast.getParent().getParent(); | |
| 122 |
1
1. visitToken : negated conditional → KILLED |
if (container.getType() != TokenTypes.INTERFACE_DEF) { |
| 123 |
1
1. visitToken : negated conditional → KILLED |
if (ast.getType() == TokenTypes.LITERAL_CATCH) { |
| 124 |
1
1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/FinalParametersCheck::visitCatch → KILLED |
visitCatch(ast); |
| 125 | } | |
| 126 |
1
1. visitToken : negated conditional → KILLED |
else if (ast.getType() == TokenTypes.FOR_EACH_CLAUSE) { |
| 127 |
1
1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/FinalParametersCheck::visitForEachClause → KILLED |
visitForEachClause(ast); |
| 128 | } | |
| 129 | else { | |
| 130 |
1
1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/FinalParametersCheck::visitMethod → KILLED |
visitMethod(ast); |
| 131 | } | |
| 132 | } | |
| 133 | } | |
| 134 | ||
| 135 | /** | |
| 136 | * Checks parameters of the method or ctor. | |
| 137 | * @param method method or ctor to check. | |
| 138 | */ | |
| 139 | private void visitMethod(final DetailAST method) { | |
| 140 | final DetailAST modifiers = | |
| 141 | method.findFirstToken(TokenTypes.MODIFIERS); | |
| 142 | // exit on fast lane if there is nothing to check here | |
| 143 | ||
| 144 |
1
1. visitMethod : negated conditional → KILLED |
if (method.branchContains(TokenTypes.PARAMETER_DEF) |
| 145 | // ignore abstract and native methods | |
| 146 |
1
1. visitMethod : negated conditional → KILLED |
&& !modifiers.branchContains(TokenTypes.ABSTRACT) |
| 147 |
1
1. visitMethod : negated conditional → KILLED |
&& !modifiers.branchContains(TokenTypes.LITERAL_NATIVE)) { |
| 148 | // we can now be sure that there is at least one parameter | |
| 149 | final DetailAST parameters = | |
| 150 | method.findFirstToken(TokenTypes.PARAMETERS); | |
| 151 | DetailAST child = parameters.getFirstChild(); | |
| 152 |
1
1. visitMethod : negated conditional → KILLED |
while (child != null) { |
| 153 | // children are PARAMETER_DEF and COMMA | |
| 154 |
1
1. visitMethod : negated conditional → KILLED |
if (child.getType() == TokenTypes.PARAMETER_DEF) { |
| 155 |
1
1. visitMethod : removed call to com/puppycrawl/tools/checkstyle/checks/FinalParametersCheck::checkParam → KILLED |
checkParam(child); |
| 156 | } | |
| 157 | child = child.getNextSibling(); | |
| 158 | } | |
| 159 | } | |
| 160 | } | |
| 161 | ||
| 162 | /** | |
| 163 | * Checks parameter of the catch block. | |
| 164 | * @param catchClause catch block to check. | |
| 165 | */ | |
| 166 | private void visitCatch(final DetailAST catchClause) { | |
| 167 |
1
1. visitCatch : removed call to com/puppycrawl/tools/checkstyle/checks/FinalParametersCheck::checkParam → KILLED |
checkParam(catchClause.findFirstToken(TokenTypes.PARAMETER_DEF)); |
| 168 | } | |
| 169 | ||
| 170 | /** | |
| 171 | * Checks parameter of the for each clause. | |
| 172 | * @param forEachClause for each clause to check. | |
| 173 | */ | |
| 174 | private void visitForEachClause(final DetailAST forEachClause) { | |
| 175 |
1
1. visitForEachClause : removed call to com/puppycrawl/tools/checkstyle/checks/FinalParametersCheck::checkParam → KILLED |
checkParam(forEachClause.findFirstToken(TokenTypes.VARIABLE_DEF)); |
| 176 | } | |
| 177 | ||
| 178 | /** | |
| 179 | * Checks if the given parameter is final. | |
| 180 | * @param param parameter to check. | |
| 181 | */ | |
| 182 | private void checkParam(final DetailAST param) { | |
| 183 |
2
1. checkParam : negated conditional → KILLED 2. checkParam : negated conditional → KILLED |
if (!param.branchContains(TokenTypes.FINAL) && !isIgnoredParam(param) |
| 184 |
1
1. checkParam : negated conditional → KILLED |
&& !CheckUtils.isReceiverParameter(param)) { |
| 185 | final DetailAST paramName = param.findFirstToken(TokenTypes.IDENT); | |
| 186 | final DetailAST firstNode = CheckUtils.getFirstNode(param); | |
| 187 |
1
1. checkParam : removed call to com/puppycrawl/tools/checkstyle/checks/FinalParametersCheck::log → KILLED |
log(firstNode.getLineNo(), firstNode.getColumnNo(), |
| 188 | MSG_KEY, paramName.getText()); | |
| 189 | } | |
| 190 | } | |
| 191 | ||
| 192 | /** | |
| 193 | * Checks for skip current param due to <b>ignorePrimitiveTypes</b> option. | |
| 194 | * @param paramDef {@link TokenTypes#PARAMETER_DEF PARAMETER_DEF} | |
| 195 | * @return true if param has to be skipped. | |
| 196 | */ | |
| 197 | private boolean isIgnoredParam(DetailAST paramDef) { | |
| 198 | boolean result = false; | |
| 199 |
1
1. isIgnoredParam : negated conditional → KILLED |
if (ignorePrimitiveTypes) { |
| 200 | final DetailAST parameterType = paramDef | |
| 201 | .findFirstToken(TokenTypes.TYPE).getFirstChild(); | |
| 202 |
1
1. isIgnoredParam : negated conditional → KILLED |
if (primitiveDataTypes.contains(parameterType.getType())) { |
| 203 | result = true; | |
| 204 | } | |
| 205 | } | |
| 206 |
1
1. isIgnoredParam : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return result; |
| 207 | } | |
| 208 | } | |
Mutations | ||
| 97 |
1.1 |
|
| 105 |
1.1 |
|
| 115 |
1.1 |
|
| 122 |
1.1 |
|
| 123 |
1.1 |
|
| 124 |
1.1 |
|
| 126 |
1.1 |
|
| 127 |
1.1 |
|
| 130 |
1.1 |
|
| 144 |
1.1 |
|
| 146 |
1.1 |
|
| 147 |
1.1 |
|
| 152 |
1.1 |
|
| 154 |
1.1 |
|
| 155 |
1.1 |
|
| 167 |
1.1 |
|
| 175 |
1.1 |
|
| 183 |
1.1 2.2 |
|
| 184 |
1.1 |
|
| 187 |
1.1 |
|
| 199 |
1.1 |
|
| 202 |
1.1 |
|
| 206 |
1.1 |