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