1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.checks;
21
22 import java.util.BitSet;
23
24 import com.puppycrawl.tools.checkstyle.StatelessCheck;
25 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
26 import com.puppycrawl.tools.checkstyle.api.DetailAST;
27 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
28 import com.puppycrawl.tools.checkstyle.utils.CheckUtil;
29 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
30 import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 @StatelessCheck
86 public class FinalParametersCheck extends AbstractCheck {
87
88
89
90
91
92 public static final String MSG_KEY = "final.parameter";
93
94
95
96
97
98
99 private final BitSet primitiveDataTypes = TokenUtil.asBitSet(
100 TokenTypes.LITERAL_BYTE,
101 TokenTypes.LITERAL_SHORT,
102 TokenTypes.LITERAL_INT,
103 TokenTypes.LITERAL_LONG,
104 TokenTypes.LITERAL_FLOAT,
105 TokenTypes.LITERAL_DOUBLE,
106 TokenTypes.LITERAL_BOOLEAN,
107 TokenTypes.LITERAL_CHAR
108 );
109
110
111
112
113 private boolean ignorePrimitiveTypes;
114
115
116
117
118
119 private boolean ignoreUnnamedParameters = true;
120
121
122
123
124
125
126
127 public void setIgnorePrimitiveTypes(boolean ignorePrimitiveTypes) {
128 this.ignorePrimitiveTypes = ignorePrimitiveTypes;
129 }
130
131
132
133
134
135
136
137
138
139 public void setIgnoreUnnamedParameters(boolean ignoreUnnamedParameters) {
140 this.ignoreUnnamedParameters = ignoreUnnamedParameters;
141 }
142
143 @Override
144 public int[] getDefaultTokens() {
145 return new int[] {
146 TokenTypes.METHOD_DEF,
147 TokenTypes.CTOR_DEF,
148 };
149 }
150
151 @Override
152 public int[] getAcceptableTokens() {
153 return new int[] {
154 TokenTypes.METHOD_DEF,
155 TokenTypes.CTOR_DEF,
156 TokenTypes.LITERAL_CATCH,
157 TokenTypes.FOR_EACH_CLAUSE,
158 TokenTypes.PATTERN_VARIABLE_DEF,
159 };
160 }
161
162 @Override
163 public int[] getRequiredTokens() {
164 return CommonUtil.EMPTY_INT_ARRAY;
165 }
166
167 @Override
168 public void visitToken(DetailAST ast) {
169 if (ast.getType() == TokenTypes.LITERAL_CATCH) {
170 visitCatch(ast);
171 }
172 else if (ast.getType() == TokenTypes.FOR_EACH_CLAUSE) {
173 visitForEachClause(ast);
174 }
175 else if (ast.getType() == TokenTypes.PATTERN_VARIABLE_DEF) {
176 visitPatternVariableDef(ast);
177 }
178 else {
179 visitMethod(ast);
180 }
181 }
182
183
184
185
186
187
188 private void visitPatternVariableDef(final DetailAST patternVariableDef) {
189 checkParam(patternVariableDef);
190 }
191
192
193
194
195
196
197 private void visitMethod(final DetailAST method) {
198
199
200
201
202 if (method.findFirstToken(TokenTypes.SLIST) != null) {
203 final DetailAST parameters =
204 method.findFirstToken(TokenTypes.PARAMETERS);
205 TokenUtil.forEachChild(parameters, TokenTypes.PARAMETER_DEF, this::checkParam);
206 }
207 }
208
209
210
211
212
213
214 private void visitCatch(final DetailAST catchClause) {
215 checkParam(catchClause.findFirstToken(TokenTypes.PARAMETER_DEF));
216 }
217
218
219
220
221
222
223 private void visitForEachClause(final DetailAST forEachClause) {
224 final DetailAST variableDef = forEachClause.findFirstToken(TokenTypes.VARIABLE_DEF);
225 if (variableDef != null) {
226
227
228 checkParam(variableDef);
229 }
230 }
231
232
233
234
235
236
237 private void checkParam(final DetailAST param) {
238 if (param.findFirstToken(TokenTypes.MODIFIERS).findFirstToken(TokenTypes.FINAL) == null
239 && !isIgnoredPrimitiveParam(param)
240 && !isIgnoredUnnamedParam(param)
241 && !CheckUtil.isReceiverParameter(param)) {
242 final DetailAST paramName = param.findFirstToken(TokenTypes.IDENT);
243 final DetailAST firstNode = CheckUtil.getFirstNode(param);
244 log(firstNode,
245 MSG_KEY, paramName.getText());
246 }
247 }
248
249
250
251
252
253
254
255 private boolean isIgnoredPrimitiveParam(DetailAST paramDef) {
256 boolean result = false;
257 if (ignorePrimitiveTypes) {
258 final DetailAST type = paramDef.findFirstToken(TokenTypes.TYPE);
259 final DetailAST parameterType = type.getFirstChild();
260 final DetailAST arrayDeclarator = type
261 .findFirstToken(TokenTypes.ARRAY_DECLARATOR);
262 if (arrayDeclarator == null
263 && primitiveDataTypes.get(parameterType.getType())) {
264 result = true;
265 }
266 }
267 return result;
268 }
269
270
271
272
273
274
275
276 private boolean isIgnoredUnnamedParam(final DetailAST paramDef) {
277 final DetailAST paramName = paramDef.findFirstToken(TokenTypes.IDENT);
278 return ignoreUnnamedParameters && paramName != null && "_".equals(paramName.getText());
279 }
280
281 }