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