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 |