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 @StatelessCheck
83 public class FinalParametersCheck extends AbstractCheck {
84
85
86
87
88
89 public static final String MSG_KEY = "final.parameter";
90
91
92
93
94
95
96 private final BitSet primitiveDataTypes = TokenUtil.asBitSet(
97 TokenTypes.LITERAL_BYTE,
98 TokenTypes.LITERAL_SHORT,
99 TokenTypes.LITERAL_INT,
100 TokenTypes.LITERAL_LONG,
101 TokenTypes.LITERAL_FLOAT,
102 TokenTypes.LITERAL_DOUBLE,
103 TokenTypes.LITERAL_BOOLEAN,
104 TokenTypes.LITERAL_CHAR
105 );
106
107
108
109
110 private boolean ignorePrimitiveTypes;
111
112
113
114
115
116 private boolean ignoreUnnamedParameters = true;
117
118
119
120
121
122
123
124 public void setIgnorePrimitiveTypes(boolean ignorePrimitiveTypes) {
125 this.ignorePrimitiveTypes = ignorePrimitiveTypes;
126 }
127
128
129
130
131
132
133
134
135
136 public void setIgnoreUnnamedParameters(boolean ignoreUnnamedParameters) {
137 this.ignoreUnnamedParameters = ignoreUnnamedParameters;
138 }
139
140 @Override
141 public int[] getDefaultTokens() {
142 return new int[] {
143 TokenTypes.METHOD_DEF,
144 TokenTypes.CTOR_DEF,
145 };
146 }
147
148 @Override
149 public int[] getAcceptableTokens() {
150 return new int[] {
151 TokenTypes.METHOD_DEF,
152 TokenTypes.CTOR_DEF,
153 TokenTypes.LITERAL_CATCH,
154 TokenTypes.FOR_EACH_CLAUSE,
155 };
156 }
157
158 @Override
159 public int[] getRequiredTokens() {
160 return CommonUtil.EMPTY_INT_ARRAY;
161 }
162
163 @Override
164 public void visitToken(DetailAST ast) {
165
166 final DetailAST container = ast.getParent().getParent();
167 if (container.getType() != TokenTypes.INTERFACE_DEF) {
168 if (ast.getType() == TokenTypes.LITERAL_CATCH) {
169 visitCatch(ast);
170 }
171 else if (ast.getType() == TokenTypes.FOR_EACH_CLAUSE) {
172 visitForEachClause(ast);
173 }
174 else {
175 visitMethod(ast);
176 }
177 }
178 }
179
180
181
182
183
184
185 private void visitMethod(final DetailAST method) {
186 final DetailAST modifiers =
187 method.findFirstToken(TokenTypes.MODIFIERS);
188
189
190 if (modifiers.findFirstToken(TokenTypes.ABSTRACT) == null
191 && modifiers.findFirstToken(TokenTypes.LITERAL_NATIVE) == null) {
192 final DetailAST parameters =
193 method.findFirstToken(TokenTypes.PARAMETERS);
194 TokenUtil.forEachChild(parameters, TokenTypes.PARAMETER_DEF, this::checkParam);
195 }
196 }
197
198
199
200
201
202
203 private void visitCatch(final DetailAST catchClause) {
204 checkParam(catchClause.findFirstToken(TokenTypes.PARAMETER_DEF));
205 }
206
207
208
209
210
211
212 private void visitForEachClause(final DetailAST forEachClause) {
213 checkParam(forEachClause.findFirstToken(TokenTypes.VARIABLE_DEF));
214 }
215
216
217
218
219
220
221 private void checkParam(final DetailAST param) {
222 if (param.findFirstToken(TokenTypes.MODIFIERS).findFirstToken(TokenTypes.FINAL) == null
223 && !isIgnoredPrimitiveParam(param)
224 && !isIgnoredUnnamedParam(param)
225 && !CheckUtil.isReceiverParameter(param)) {
226 final DetailAST paramName = param.findFirstToken(TokenTypes.IDENT);
227 final DetailAST firstNode = CheckUtil.getFirstNode(param);
228 log(firstNode,
229 MSG_KEY, paramName.getText());
230 }
231 }
232
233
234
235
236
237
238
239 private boolean isIgnoredPrimitiveParam(DetailAST paramDef) {
240 boolean result = false;
241 if (ignorePrimitiveTypes) {
242 final DetailAST type = paramDef.findFirstToken(TokenTypes.TYPE);
243 final DetailAST parameterType = type.getFirstChild();
244 final DetailAST arrayDeclarator = type
245 .findFirstToken(TokenTypes.ARRAY_DECLARATOR);
246 if (arrayDeclarator == null
247 && primitiveDataTypes.get(parameterType.getType())) {
248 result = true;
249 }
250 }
251 return result;
252 }
253
254
255
256
257
258
259
260 private boolean isIgnoredUnnamedParam(final DetailAST paramDef) {
261 final DetailAST paramName = paramDef.findFirstToken(TokenTypes.IDENT);
262 return ignoreUnnamedParameters && paramName != null && "_".equals(paramName.getText());
263 }
264
265 }