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.modifier;
21
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import com.puppycrawl.tools.checkstyle.StatelessCheck;
26 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
27 import com.puppycrawl.tools.checkstyle.api.DetailAST;
28 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
29 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
30
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 @StatelessCheck
115 public class RedundantModifierCheck
116 extends AbstractCheck {
117
118
119
120
121
122 public static final String MSG_KEY = "redundantModifier";
123
124
125
126
127 private static final int[] TOKENS_FOR_INTERFACE_MODIFIERS = {
128 TokenTypes.LITERAL_STATIC,
129 TokenTypes.ABSTRACT,
130 };
131
132 @Override
133 public int[] getDefaultTokens() {
134 return getAcceptableTokens();
135 }
136
137 @Override
138 public int[] getRequiredTokens() {
139 return CommonUtil.EMPTY_INT_ARRAY;
140 }
141
142 @Override
143 public int[] getAcceptableTokens() {
144 return new int[] {
145 TokenTypes.METHOD_DEF,
146 TokenTypes.VARIABLE_DEF,
147 TokenTypes.ANNOTATION_FIELD_DEF,
148 TokenTypes.INTERFACE_DEF,
149 TokenTypes.CTOR_DEF,
150 TokenTypes.CLASS_DEF,
151 TokenTypes.ENUM_DEF,
152 TokenTypes.RESOURCE,
153 };
154 }
155
156 @Override
157 public void visitToken(DetailAST ast) {
158 if (ast.getType() == TokenTypes.INTERFACE_DEF) {
159 checkInterfaceModifiers(ast);
160 }
161 else if (ast.getType() == TokenTypes.ENUM_DEF) {
162 checkEnumDef(ast);
163 }
164 else {
165 if (ast.getType() == TokenTypes.CTOR_DEF) {
166 if (isEnumMember(ast)) {
167 checkEnumConstructorModifiers(ast);
168 }
169 else {
170 checkClassConstructorModifiers(ast);
171 }
172 }
173 else if (ast.getType() == TokenTypes.METHOD_DEF) {
174 processMethods(ast);
175 }
176 else if (ast.getType() == TokenTypes.RESOURCE) {
177 processResources(ast);
178 }
179
180 if (isInterfaceOrAnnotationMember(ast)) {
181 processInterfaceOrAnnotation(ast);
182 }
183 }
184 }
185
186
187
188
189
190 private void checkInterfaceModifiers(DetailAST ast) {
191 final DetailAST modifiers =
192 ast.findFirstToken(TokenTypes.MODIFIERS);
193
194 for (final int tokenType : TOKENS_FOR_INTERFACE_MODIFIERS) {
195 final DetailAST modifier =
196 modifiers.findFirstToken(tokenType);
197 if (modifier != null) {
198 log(modifier, MSG_KEY, modifier.getText());
199 }
200 }
201 }
202
203
204
205
206
207 private void checkEnumConstructorModifiers(DetailAST ast) {
208 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS);
209 final DetailAST modifier = getFirstModifierAst(modifiers);
210
211 if (modifier != null) {
212 log(modifier, MSG_KEY, modifier.getText());
213 }
214 }
215
216
217
218
219
220
221 private static DetailAST getFirstModifierAst(DetailAST modifiers) {
222 DetailAST modifier = modifiers.getFirstChild();
223
224 while (modifier != null && modifier.getType() == TokenTypes.ANNOTATION) {
225 modifier = modifier.getNextSibling();
226 }
227
228 return modifier;
229 }
230
231
232
233
234
235 private void checkEnumDef(DetailAST ast) {
236 if (isInterfaceOrAnnotationMember(ast)) {
237 processInterfaceOrAnnotation(ast);
238 }
239 else {
240 checkForRedundantModifier(ast, TokenTypes.LITERAL_STATIC);
241 }
242 }
243
244
245
246
247
248 private void processInterfaceOrAnnotation(DetailAST ast) {
249 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS);
250 DetailAST modifier = modifiers.getFirstChild();
251 while (modifier != null) {
252
253
254
255
256 final int type = modifier.getType();
257 if (type == TokenTypes.LITERAL_PUBLIC
258 || type == TokenTypes.LITERAL_STATIC
259 && ast.getType() != TokenTypes.METHOD_DEF
260 || type == TokenTypes.ABSTRACT
261 && ast.getType() != TokenTypes.CLASS_DEF
262 || type == TokenTypes.FINAL
263 && ast.getType() != TokenTypes.CLASS_DEF) {
264 log(modifier, MSG_KEY, modifier.getText());
265 break;
266 }
267
268 modifier = modifier.getNextSibling();
269 }
270 }
271
272
273
274
275
276 private void processMethods(DetailAST ast) {
277 final DetailAST modifiers =
278 ast.findFirstToken(TokenTypes.MODIFIERS);
279
280 boolean checkFinal =
281 modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) != null;
282
283 DetailAST parent = ast.getParent();
284 while (parent != null && !checkFinal) {
285 if (parent.getType() == TokenTypes.CLASS_DEF) {
286 final DetailAST classModifiers =
287 parent.findFirstToken(TokenTypes.MODIFIERS);
288 checkFinal = classModifiers.findFirstToken(TokenTypes.FINAL) != null;
289 parent = null;
290 }
291 else if (parent.getType() == TokenTypes.LITERAL_NEW
292 || parent.getType() == TokenTypes.ENUM_CONSTANT_DEF) {
293 checkFinal = true;
294 parent = null;
295 }
296 else if (parent.getType() == TokenTypes.ENUM_DEF) {
297 checkFinal = modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) != null;
298 parent = null;
299 }
300 else {
301 parent = parent.getParent();
302 }
303 }
304 if (checkFinal && !isAnnotatedWithSafeVarargs(ast)) {
305 checkForRedundantModifier(ast, TokenTypes.FINAL);
306 }
307
308 if (ast.findFirstToken(TokenTypes.SLIST) == null) {
309 processAbstractMethodParameters(ast);
310 }
311 }
312
313
314
315
316
317 private void processAbstractMethodParameters(DetailAST ast) {
318 final DetailAST parameters = ast.findFirstToken(TokenTypes.PARAMETERS);
319
320 for (DetailAST child = parameters.getFirstChild(); child != null; child = child
321 .getNextSibling()) {
322 if (child.getType() == TokenTypes.PARAMETER_DEF) {
323 checkForRedundantModifier(child, TokenTypes.FINAL);
324 }
325 }
326 }
327
328
329
330
331
332 private void checkClassConstructorModifiers(DetailAST classCtorAst) {
333 final DetailAST classDef = classCtorAst.getParent().getParent();
334 if (!isClassPublic(classDef) && !isClassProtected(classDef)) {
335 checkForRedundantModifier(classCtorAst, TokenTypes.LITERAL_PUBLIC);
336 }
337 }
338
339
340
341
342
343 private void processResources(DetailAST ast) {
344 checkForRedundantModifier(ast, TokenTypes.FINAL);
345 }
346
347
348
349
350
351
352 private void checkForRedundantModifier(DetailAST ast, int modifierType) {
353 final DetailAST astModifiers = ast.findFirstToken(TokenTypes.MODIFIERS);
354 DetailAST astModifier = astModifiers.getFirstChild();
355 while (astModifier != null) {
356 if (astModifier.getType() == modifierType) {
357 log(astModifier, MSG_KEY, astModifier.getText());
358 }
359
360 astModifier = astModifier.getNextSibling();
361 }
362 }
363
364
365
366
367
368
369 private static boolean isClassProtected(DetailAST classDef) {
370 final DetailAST classModifiers =
371 classDef.findFirstToken(TokenTypes.MODIFIERS);
372 return classModifiers.findFirstToken(TokenTypes.LITERAL_PROTECTED) != null;
373 }
374
375
376
377
378
379
380 private static boolean isClassPublic(DetailAST ast) {
381 boolean isAccessibleFromPublic = false;
382 final boolean isMostOuterScope = ast.getParent() == null;
383 final DetailAST modifiersAst = ast.findFirstToken(TokenTypes.MODIFIERS);
384 final boolean hasPublicModifier =
385 modifiersAst.findFirstToken(TokenTypes.LITERAL_PUBLIC) != null;
386
387 if (isMostOuterScope) {
388 isAccessibleFromPublic = hasPublicModifier;
389 }
390 else {
391 final DetailAST parentClassAst = ast.getParent().getParent();
392
393 if (hasPublicModifier || parentClassAst.getType() == TokenTypes.INTERFACE_DEF) {
394 isAccessibleFromPublic = isClassPublic(parentClassAst);
395 }
396 }
397
398 return isAccessibleFromPublic;
399 }
400
401
402
403
404
405
406 private static boolean isEnumMember(DetailAST ast) {
407 final DetailAST parentTypeDef = ast.getParent().getParent();
408 return parentTypeDef.getType() == TokenTypes.ENUM_DEF;
409 }
410
411
412
413
414
415
416 private static boolean isInterfaceOrAnnotationMember(DetailAST ast) {
417 DetailAST parentTypeDef = ast.getParent();
418
419 if (parentTypeDef != null) {
420 parentTypeDef = parentTypeDef.getParent();
421 }
422 return parentTypeDef != null
423 && (parentTypeDef.getType() == TokenTypes.INTERFACE_DEF
424 || parentTypeDef.getType() == TokenTypes.ANNOTATION_DEF);
425 }
426
427
428
429
430
431
432
433
434 private static boolean isAnnotatedWithSafeVarargs(DetailAST methodDef) {
435 boolean result = false;
436 final List<DetailAST> methodAnnotationsList = getMethodAnnotationsList(methodDef);
437 for (DetailAST annotationNode : methodAnnotationsList) {
438 if ("SafeVarargs".equals(annotationNode.getLastChild().getText())) {
439 result = true;
440 break;
441 }
442 }
443 return result;
444 }
445
446
447
448
449
450
451 private static List<DetailAST> getMethodAnnotationsList(DetailAST methodDef) {
452 final List<DetailAST> annotationsList = new ArrayList<>();
453 final DetailAST modifiers = methodDef.findFirstToken(TokenTypes.MODIFIERS);
454 DetailAST modifier = modifiers.getFirstChild();
455 while (modifier != null) {
456 if (modifier.getType() == TokenTypes.ANNOTATION) {
457 annotationsList.add(modifier);
458 }
459 modifier = modifier.getNextSibling();
460 }
461 return annotationsList;
462 }
463
464 }