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 };
159 }
160
161 @Override
162 public int[] getRequiredTokens() {
163 return CommonUtil.EMPTY_INT_ARRAY;
164 }
165
166 @Override
167 public void visitToken(DetailAST ast) {
168
169 final DetailAST container = ast.getParent().getParent();
170 if (container.getType() != TokenTypes.INTERFACE_DEF) {
171 if (ast.getType() == TokenTypes.LITERAL_CATCH) {
172 visitCatch(ast);
173 }
174 else if (ast.getType() == TokenTypes.FOR_EACH_CLAUSE) {
175 visitForEachClause(ast);
176 }
177 else {
178 visitMethod(ast);
179 }
180 }
181 }
182
183
184
185
186
187
188 private void visitMethod(final DetailAST method) {
189 final DetailAST modifiers =
190 method.findFirstToken(TokenTypes.MODIFIERS);
191
192
193 if (modifiers.findFirstToken(TokenTypes.ABSTRACT) == null
194 && modifiers.findFirstToken(TokenTypes.LITERAL_NATIVE) == null) {
195 final DetailAST parameters =
196 method.findFirstToken(TokenTypes.PARAMETERS);
197 TokenUtil.forEachChild(parameters, TokenTypes.PARAMETER_DEF, this::checkParam);
198 }
199 }
200
201
202
203
204
205
206 private void visitCatch(final DetailAST catchClause) {
207 checkParam(catchClause.findFirstToken(TokenTypes.PARAMETER_DEF));
208 }
209
210
211
212
213
214
215 private void visitForEachClause(final DetailAST forEachClause) {
216 checkParam(forEachClause.findFirstToken(TokenTypes.VARIABLE_DEF));
217 }
218
219
220
221
222
223
224 private void checkParam(final DetailAST param) {
225 if (param.findFirstToken(TokenTypes.MODIFIERS).findFirstToken(TokenTypes.FINAL) == null
226 && !isIgnoredPrimitiveParam(param)
227 && !isIgnoredUnnamedParam(param)
228 && !CheckUtil.isReceiverParameter(param)) {
229 final DetailAST paramName = param.findFirstToken(TokenTypes.IDENT);
230 final DetailAST firstNode = CheckUtil.getFirstNode(param);
231 log(firstNode,
232 MSG_KEY, paramName.getText());
233 }
234 }
235
236
237
238
239
240
241
242 private boolean isIgnoredPrimitiveParam(DetailAST paramDef) {
243 boolean result = false;
244 if (ignorePrimitiveTypes) {
245 final DetailAST type = paramDef.findFirstToken(TokenTypes.TYPE);
246 final DetailAST parameterType = type.getFirstChild();
247 final DetailAST arrayDeclarator = type
248 .findFirstToken(TokenTypes.ARRAY_DECLARATOR);
249 if (arrayDeclarator == null
250 && primitiveDataTypes.get(parameterType.getType())) {
251 result = true;
252 }
253 }
254 return result;
255 }
256
257
258
259
260
261
262
263 private boolean isIgnoredUnnamedParam(final DetailAST paramDef) {
264 final DetailAST paramName = paramDef.findFirstToken(TokenTypes.IDENT);
265 return ignoreUnnamedParameters && paramName != null && "_".equals(paramName.getText());
266 }
267
268 }