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.javadoc;
21
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.Map;
25 import java.util.stream.Collectors;
26
27 import com.puppycrawl.tools.checkstyle.api.DetailAST;
28 import com.puppycrawl.tools.checkstyle.api.Scope;
29 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
30 import com.puppycrawl.tools.checkstyle.utils.ScopeUtil;
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 public enum JavadocTagInfo {
68
69
70
71
72 AUTHOR("@author", "author", Type.BLOCK) {
73
74 @Override
75 public boolean isValidOn(final DetailAST ast) {
76 final int astType = ast.getType();
77 return astType == TokenTypes.PACKAGE_DEF
78 || astType == TokenTypes.CLASS_DEF
79 || astType == TokenTypes.INTERFACE_DEF
80 || astType == TokenTypes.ENUM_DEF
81 || astType == TokenTypes.ANNOTATION_DEF;
82 }
83
84 },
85
86
87
88
89 CODE("{@code}", "code", Type.INLINE) {
90
91 @Override
92 public boolean isValidOn(final DetailAST ast) {
93 final int astType = ast.getType();
94 return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
95 && !ScopeUtil.isLocalVariableDef(ast);
96 }
97
98 },
99
100
101
102
103 DOC_ROOT("{@docRoot}", "docRoot", Type.INLINE) {
104
105 @Override
106 public boolean isValidOn(final DetailAST ast) {
107 final int astType = ast.getType();
108 return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
109 && !ScopeUtil.isLocalVariableDef(ast);
110 }
111
112 },
113
114
115
116
117 DEPRECATED("@deprecated", "deprecated", Type.BLOCK) {
118
119 @Override
120 public boolean isValidOn(final DetailAST ast) {
121 final int astType = ast.getType();
122 return Arrays.binarySearch(DEF_TOKEN_TYPES_DEPRECATED, astType) >= 0
123 && !ScopeUtil.isLocalVariableDef(ast);
124 }
125
126 },
127
128
129
130
131 EXCEPTION("@exception", "exception", Type.BLOCK) {
132
133 @Override
134 public boolean isValidOn(final DetailAST ast) {
135 final int astType = ast.getType();
136 return astType == TokenTypes.METHOD_DEF || astType == TokenTypes.CTOR_DEF;
137 }
138
139 },
140
141
142
143
144 INHERIT_DOC("{@inheritDoc}", "inheritDoc", Type.INLINE) {
145
146 @Override
147 public boolean isValidOn(final DetailAST ast) {
148 final int astType = ast.getType();
149
150 return astType == TokenTypes.METHOD_DEF
151 && ast.findFirstToken(TokenTypes.MODIFIERS)
152 .findFirstToken(TokenTypes.LITERAL_STATIC) == null
153 && ScopeUtil.getScopeFromMods(ast
154 .findFirstToken(TokenTypes.MODIFIERS)) != Scope.PRIVATE;
155 }
156
157 },
158
159
160
161
162 LINK("{@link}", "link", Type.INLINE) {
163
164 @Override
165 public boolean isValidOn(final DetailAST ast) {
166 final int astType = ast.getType();
167 return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
168 && !ScopeUtil.isLocalVariableDef(ast);
169 }
170
171 },
172
173
174
175
176 LINKPLAIN("{@linkplain}", "linkplain", Type.INLINE) {
177
178 @Override
179 public boolean isValidOn(final DetailAST ast) {
180 final int astType = ast.getType();
181 return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
182 && !ScopeUtil.isLocalVariableDef(ast);
183 }
184
185 },
186
187
188
189
190 LITERAL("{@literal}", "literal", Type.INLINE) {
191
192 @Override
193 public boolean isValidOn(final DetailAST ast) {
194 final int astType = ast.getType();
195 return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
196 && !ScopeUtil.isLocalVariableDef(ast);
197 }
198
199 },
200
201
202
203
204 PARAM("@param", "param", Type.BLOCK) {
205
206 @Override
207 public boolean isValidOn(final DetailAST ast) {
208 final int astType = ast.getType();
209 return astType == TokenTypes.CLASS_DEF
210 || astType == TokenTypes.INTERFACE_DEF
211 || astType == TokenTypes.METHOD_DEF
212 || astType == TokenTypes.CTOR_DEF;
213 }
214
215 },
216
217
218
219
220 RETURN("@return", "return", Type.BLOCK) {
221
222 @Override
223 public boolean isValidOn(final DetailAST ast) {
224 final int astType = ast.getType();
225 final DetailAST returnType = ast.findFirstToken(TokenTypes.TYPE);
226
227 return astType == TokenTypes.METHOD_DEF
228 && returnType.getFirstChild().getType() != TokenTypes.LITERAL_VOID;
229 }
230
231 },
232
233
234
235
236 SEE("@see", "see", Type.BLOCK) {
237
238 @Override
239 public boolean isValidOn(final DetailAST ast) {
240 final int astType = ast.getType();
241 return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
242 && !ScopeUtil.isLocalVariableDef(ast);
243 }
244
245 },
246
247
248
249
250 SERIAL("@serial", "serial", Type.BLOCK) {
251
252 @Override
253 public boolean isValidOn(final DetailAST ast) {
254 final int astType = ast.getType();
255
256 return astType == TokenTypes.VARIABLE_DEF
257 && !ScopeUtil.isLocalVariableDef(ast);
258 }
259
260 },
261
262
263
264
265 SERIAL_DATA("@serialData", "serialData", Type.BLOCK) {
266
267 @Override
268 public boolean isValidOn(final DetailAST ast) {
269 final int astType = ast.getType();
270 final DetailAST methodNameAst = ast.findFirstToken(TokenTypes.IDENT);
271 final String methodName = methodNameAst.getText();
272
273 return astType == TokenTypes.METHOD_DEF
274 && ("writeObject".equals(methodName)
275 || "readObject".equals(methodName)
276 || "writeExternal".equals(methodName)
277 || "readExternal".equals(methodName)
278 || "writeReplace".equals(methodName)
279 || "readResolve".equals(methodName));
280 }
281
282 },
283
284
285
286
287 SERIAL_FIELD("@serialField", "serialField", Type.BLOCK) {
288
289 @Override
290 public boolean isValidOn(final DetailAST ast) {
291 final int astType = ast.getType();
292 final DetailAST varType = ast.findFirstToken(TokenTypes.TYPE);
293
294 return astType == TokenTypes.VARIABLE_DEF
295 && varType.getFirstChild().getType() == TokenTypes.ARRAY_DECLARATOR
296 && "ObjectStreamField".equals(varType.getFirstChild().getText());
297 }
298
299 },
300
301
302
303
304 SINCE("@since", "since", Type.BLOCK) {
305
306 @Override
307 public boolean isValidOn(final DetailAST ast) {
308 final int astType = ast.getType();
309 return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
310 && !ScopeUtil.isLocalVariableDef(ast);
311 }
312
313 },
314
315
316
317
318 THROWS("@throws", "throws", Type.BLOCK) {
319
320 @Override
321 public boolean isValidOn(final DetailAST ast) {
322 final int astType = ast.getType();
323 return astType == TokenTypes.METHOD_DEF
324 || astType == TokenTypes.CTOR_DEF;
325 }
326
327 },
328
329
330
331
332 VALUE("{@value}", "value", Type.INLINE) {
333
334 @Override
335 public boolean isValidOn(final DetailAST ast) {
336 final int astType = ast.getType();
337 return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
338 && !ScopeUtil.isLocalVariableDef(ast);
339 }
340
341 },
342
343
344
345
346 VERSION("@version", "version", Type.BLOCK) {
347
348 @Override
349 public boolean isValidOn(final DetailAST ast) {
350 final int astType = ast.getType();
351 return astType == TokenTypes.PACKAGE_DEF
352 || astType == TokenTypes.CLASS_DEF
353 || astType == TokenTypes.INTERFACE_DEF
354 || astType == TokenTypes.ENUM_DEF
355 || astType == TokenTypes.ANNOTATION_DEF;
356 }
357
358 };
359
360
361 private static final int[] DEF_TOKEN_TYPES_DEPRECATED = {
362 TokenTypes.CTOR_DEF,
363 TokenTypes.METHOD_DEF,
364 TokenTypes.VARIABLE_DEF,
365 TokenTypes.CLASS_DEF,
366 TokenTypes.INTERFACE_DEF,
367 TokenTypes.ENUM_DEF,
368 TokenTypes.ENUM_CONSTANT_DEF,
369 TokenTypes.ANNOTATION_DEF,
370 TokenTypes.ANNOTATION_FIELD_DEF,
371 };
372
373
374 private static final int[] DEF_TOKEN_TYPES = {
375 TokenTypes.CTOR_DEF,
376 TokenTypes.METHOD_DEF,
377 TokenTypes.VARIABLE_DEF,
378 TokenTypes.CLASS_DEF,
379 TokenTypes.INTERFACE_DEF,
380 TokenTypes.PACKAGE_DEF,
381 TokenTypes.ENUM_DEF,
382 TokenTypes.ANNOTATION_DEF,
383 };
384
385
386 private static final Map<String, JavadocTagInfo> TEXT_TO_TAG;
387
388 private static final Map<String, JavadocTagInfo> NAME_TO_TAG;
389
390 static {
391 TEXT_TO_TAG = Collections.unmodifiableMap(Arrays.stream(JavadocTagInfo.values())
392 .collect(Collectors.toMap(JavadocTagInfo::getText, tagText -> tagText)));
393 NAME_TO_TAG = Collections.unmodifiableMap(Arrays.stream(JavadocTagInfo.values())
394 .collect(Collectors.toMap(JavadocTagInfo::getName, tagName -> tagName)));
395
396
397 Arrays.sort(DEF_TOKEN_TYPES);
398 Arrays.sort(DEF_TOKEN_TYPES_DEPRECATED);
399 }
400
401
402 private final String text;
403
404 private final String name;
405
406 private final Type type;
407
408
409
410
411
412
413
414
415 JavadocTagInfo(final String text, final String name,
416 final Type type) {
417 this.text = text;
418 this.name = name;
419 this.type = type;
420 }
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436 public abstract boolean isValidOn(DetailAST ast);
437
438
439
440
441
442 public String getText() {
443 return text;
444 }
445
446
447
448
449
450 public String getName() {
451 return name;
452 }
453
454
455
456
457
458 public Type getType() {
459 return type;
460 }
461
462
463
464
465
466
467
468
469 public static JavadocTagInfo fromText(final String text) {
470 if (text == null) {
471 throw new IllegalArgumentException("the text is null");
472 }
473
474 final JavadocTagInfo tag = TEXT_TO_TAG.get(text);
475
476 if (tag == null) {
477 throw new IllegalArgumentException("the text [" + text
478 + "] is not a valid Javadoc tag text");
479 }
480
481 return tag;
482 }
483
484
485
486
487
488
489
490
491
492 public static JavadocTagInfo fromName(final String name) {
493 if (name == null) {
494 throw new IllegalArgumentException("the name is null");
495 }
496
497 final JavadocTagInfo tag = NAME_TO_TAG.get(name);
498
499 if (tag == null) {
500 throw new IllegalArgumentException("the name [" + name
501 + "] is not a valid Javadoc tag name");
502 }
503
504 return tag;
505 }
506
507
508
509
510
511
512 public static boolean isValidName(final String name) {
513 return NAME_TO_TAG.containsKey(name);
514 }
515
516 @Override
517 public String toString() {
518 return "text [" + text + "] name [" + name
519 + "] type [" + type + "]";
520 }
521
522
523
524
525
526
527
528
529 public enum Type {
530
531
532 BLOCK,
533
534
535 INLINE
536
537 }
538
539 }