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.utils;
21
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.regex.Pattern;
26
27 import com.puppycrawl.tools.checkstyle.api.DetailAST;
28 import com.puppycrawl.tools.checkstyle.api.DetailNode;
29 import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes;
30 import com.puppycrawl.tools.checkstyle.api.TextBlock;
31 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
32 import com.puppycrawl.tools.checkstyle.checks.javadoc.InvalidJavadocTag;
33 import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTag;
34 import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTagInfo;
35 import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTags;
36 import com.puppycrawl.tools.checkstyle.checks.javadoc.utils.BlockTagUtil;
37 import com.puppycrawl.tools.checkstyle.checks.javadoc.utils.InlineTagUtil;
38 import com.puppycrawl.tools.checkstyle.checks.javadoc.utils.TagInfo;
39
40
41
42
43 public final class JavadocUtil {
44
45
46
47
48 public enum JavadocTagType {
49
50
51 BLOCK,
52
53 INLINE,
54
55 ALL,
56
57 }
58
59
60 private static final Map<String, Integer> TOKEN_NAME_TO_VALUE;
61
62 private static final Map<Integer, String> TOKEN_VALUE_TO_NAME;
63
64
65 private static final String UNKNOWN_JAVADOC_TOKEN_ID_EXCEPTION_MESSAGE = "Unknown javadoc"
66 + " token id. Given id: ";
67
68
69 private static final Pattern NEWLINE = Pattern.compile("\n");
70
71
72 private static final Pattern RETURN = Pattern.compile("\r");
73
74
75 private static final Pattern TAB = Pattern.compile("\t");
76
77
78 static {
79 TOKEN_NAME_TO_VALUE = TokenUtil.nameToValueMapFromPublicIntFields(JavadocTokenTypes.class);
80 TOKEN_VALUE_TO_NAME = TokenUtil.invertMap(TOKEN_NAME_TO_VALUE);
81 }
82
83
84 private JavadocUtil() {
85 }
86
87
88
89
90
91
92
93
94
95
96 public static JavadocTags getJavadocTags(TextBlock textBlock,
97 JavadocTagType tagType) {
98 final List<TagInfo> tags = new ArrayList<>();
99 final boolean isBlockTags = tagType == JavadocTagType.ALL
100 || tagType == JavadocTagType.BLOCK;
101 if (isBlockTags) {
102 tags.addAll(BlockTagUtil.extractBlockTags(textBlock.getText()));
103 }
104 final boolean isInlineTags = tagType == JavadocTagType.ALL
105 || tagType == JavadocTagType.INLINE;
106 if (isInlineTags) {
107 tags.addAll(InlineTagUtil.extractInlineTags(textBlock.getText()));
108 }
109
110 final List<JavadocTag> validTags = new ArrayList<>();
111 final List<InvalidJavadocTag> invalidTags = new ArrayList<>();
112
113 for (TagInfo tag : tags) {
114 final int col = tag.getPosition().getColumn();
115
116
117
118
119 final int line = textBlock.getStartLineNo() + tag.getPosition().getLine() - 1;
120
121 if (JavadocTagInfo.isValidName(tag.getName())) {
122 validTags.add(
123 new JavadocTag(line, col, tag.getName(), tag.getValue()));
124 }
125 else {
126 invalidTags.add(new InvalidJavadocTag(line, col, tag.getName()));
127 }
128 }
129
130 return new JavadocTags(validTags, invalidTags);
131 }
132
133
134
135
136
137
138
139
140
141 public static boolean isJavadocComment(String commentContent) {
142 boolean result = false;
143
144 if (!commentContent.isEmpty()) {
145 final char docCommentIdentifier = commentContent.charAt(0);
146 result = docCommentIdentifier == '*';
147 }
148
149 return result;
150 }
151
152
153
154
155
156
157
158
159
160 public static boolean isJavadocComment(DetailAST blockCommentBegin) {
161 final String commentContent = getBlockCommentContent(blockCommentBegin);
162 return isJavadocComment(commentContent) && isCorrectJavadocPosition(blockCommentBegin);
163 }
164
165
166
167
168
169
170
171
172 public static String getBlockCommentContent(DetailAST blockCommentBegin) {
173 final DetailAST commentContent = blockCommentBegin.getFirstChild();
174 return commentContent.getText();
175 }
176
177
178
179
180
181
182
183
184 public static String getJavadocCommentContent(DetailAST javadocCommentBegin) {
185 final DetailAST commentContent = javadocCommentBegin.getFirstChild();
186 return commentContent.getText().substring(1);
187 }
188
189
190
191
192
193
194
195
196
197
198 public static DetailNode findFirstToken(DetailNode detailNode, int type) {
199 DetailNode returnValue = null;
200 DetailNode node = getFirstChild(detailNode);
201 while (node != null) {
202 if (node.getType() == type) {
203 returnValue = node;
204 break;
205 }
206 node = getNextSibling(node);
207 }
208 return returnValue;
209 }
210
211
212
213
214
215
216
217 public static DetailNode getFirstChild(DetailNode node) {
218 DetailNode resultNode = null;
219
220 if (node.getChildren().length > 0) {
221 resultNode = node.getChildren()[0];
222 }
223 return resultNode;
224 }
225
226
227
228
229
230
231
232 public static DetailNode getNextSibling(DetailNode node) {
233 DetailNode nextSibling = null;
234 final DetailNode parent = node.getParent();
235 if (parent != null) {
236 final int nextSiblingIndex = node.getIndex() + 1;
237 final DetailNode[] children = parent.getChildren();
238 if (nextSiblingIndex <= children.length - 1) {
239 nextSibling = children[nextSiblingIndex];
240 }
241 }
242 return nextSibling;
243 }
244
245
246
247
248
249
250
251
252 public static DetailNode getNextSibling(DetailNode node, int tokenType) {
253 DetailNode nextSibling = getNextSibling(node);
254 while (nextSibling != null && nextSibling.getType() != tokenType) {
255 nextSibling = getNextSibling(nextSibling);
256 }
257 return nextSibling;
258 }
259
260
261
262
263
264
265
266 public static DetailNode getPreviousSibling(DetailNode node) {
267 DetailNode previousSibling = null;
268 final int previousSiblingIndex = node.getIndex() - 1;
269 if (previousSiblingIndex >= 0) {
270 final DetailNode parent = node.getParent();
271 final DetailNode[] children = parent.getChildren();
272 previousSibling = children[previousSiblingIndex];
273 }
274 return previousSibling;
275 }
276
277
278
279
280
281
282
283
284
285 public static String getTokenName(int id) {
286 final String name = TOKEN_VALUE_TO_NAME.get(id);
287 if (name == null) {
288 throw new IllegalArgumentException(UNKNOWN_JAVADOC_TOKEN_ID_EXCEPTION_MESSAGE + id);
289 }
290 return name;
291 }
292
293
294
295
296
297
298
299
300
301 public static int getTokenId(String name) {
302 final Integer id = TOKEN_NAME_TO_VALUE.get(name);
303 if (id == null) {
304 throw new IllegalArgumentException("Unknown javadoc token name. Given name " + name);
305 }
306 return id;
307 }
308
309
310
311
312
313
314
315 public static String getTagName(DetailNode javadocTagSection) {
316 final String javadocTagName;
317 if (javadocTagSection.getType() == JavadocTokenTypes.JAVADOC_INLINE_TAG) {
318 javadocTagName = getNextSibling(
319 getFirstChild(javadocTagSection)).getText();
320 }
321 else {
322 javadocTagName = getFirstChild(javadocTagSection).getText();
323 }
324 return javadocTagName;
325 }
326
327
328
329
330
331
332
333 public static String escapeAllControlChars(String text) {
334 final String textWithoutNewlines = NEWLINE.matcher(text).replaceAll("\\\\n");
335 final String textWithoutReturns = RETURN.matcher(textWithoutNewlines).replaceAll("\\\\r");
336 return TAB.matcher(textWithoutReturns).replaceAll("\\\\t");
337 }
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356 public static boolean isCorrectJavadocPosition(DetailAST blockComment) {
357
358 DetailAST sibling = blockComment.getNextSibling();
359 while (sibling != null) {
360 if (sibling.getType() == TokenTypes.BLOCK_COMMENT_BEGIN) {
361 if (isJavadocComment(getBlockCommentContent(sibling))) {
362
363 break;
364 }
365 sibling = sibling.getNextSibling();
366 }
367 else if (sibling.getType() == TokenTypes.SINGLE_LINE_COMMENT) {
368 sibling = sibling.getNextSibling();
369 }
370 else {
371
372 sibling = null;
373 }
374 }
375 return sibling == null
376 && (BlockCommentPosition.isOnType(blockComment)
377 || BlockCommentPosition.isOnMember(blockComment)
378 || BlockCommentPosition.isOnPackage(blockComment));
379 }
380
381 }