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.JavadocCommentsTokenTypes;
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 =
80 TokenUtil.nameToValueMapFromPublicIntFields(JavadocCommentsTokenTypes.class);
81 TOKEN_VALUE_TO_NAME = TokenUtil.invertMap(TOKEN_NAME_TO_VALUE);
82 }
83
84
85 private JavadocUtil() {
86 }
87
88
89
90
91
92
93
94
95
96
97 public static JavadocTags getJavadocTags(TextBlock textBlock,
98 JavadocTagType tagType) {
99 final List<TagInfo> tags = new ArrayList<>();
100 final boolean isBlockTags = tagType == JavadocTagType.ALL
101 || tagType == JavadocTagType.BLOCK;
102 if (isBlockTags) {
103 tags.addAll(BlockTagUtil.extractBlockTags(textBlock.getText()));
104 }
105 final boolean isInlineTags = tagType == JavadocTagType.ALL
106 || tagType == JavadocTagType.INLINE;
107 if (isInlineTags) {
108 tags.addAll(InlineTagUtil.extractInlineTags(textBlock.getText()));
109 }
110
111 final List<JavadocTag> validTags = new ArrayList<>();
112 final List<InvalidJavadocTag> invalidTags = new ArrayList<>();
113
114 for (TagInfo tag : tags) {
115 final int col = tag.getPosition().getColumn();
116
117
118
119
120 final int line = textBlock.getStartLineNo() + tag.getPosition().getLine() - 1;
121
122 if (JavadocTagInfo.isValidName(tag.getName())) {
123 validTags.add(
124 new JavadocTag(line, col, tag.getName(), tag.getValue()));
125 }
126 else {
127 invalidTags.add(new InvalidJavadocTag(line, col, tag.getName()));
128 }
129 }
130
131 return new JavadocTags(validTags, invalidTags);
132 }
133
134
135
136
137
138
139
140
141
142 public static boolean isJavadocComment(String commentContent) {
143 boolean result = false;
144
145 if (!commentContent.isEmpty()) {
146 final char docCommentIdentifier = commentContent.charAt(0);
147 result = docCommentIdentifier == '*';
148 }
149
150 return result;
151 }
152
153
154
155
156
157
158
159
160
161 public static boolean isJavadocComment(DetailAST blockCommentBegin) {
162 final String commentContent = getBlockCommentContent(blockCommentBegin);
163 return isJavadocComment(commentContent) && isCorrectJavadocPosition(blockCommentBegin);
164 }
165
166
167
168
169
170
171
172
173 public static String getBlockCommentContent(DetailAST blockCommentBegin) {
174 final DetailAST commentContent = blockCommentBegin.getFirstChild();
175 return commentContent.getText();
176 }
177
178
179
180
181
182
183
184
185 public static String getJavadocCommentContent(DetailAST javadocCommentBegin) {
186 final DetailAST commentContent = javadocCommentBegin.getFirstChild();
187 return commentContent.getText().substring(1);
188 }
189
190
191
192
193
194
195
196
197
198
199 public static DetailNode findFirstToken(DetailNode detailNode, int type) {
200 DetailNode returnValue = null;
201 DetailNode node = detailNode.getFirstChild();
202 while (node != null) {
203 if (node.getType() == type) {
204 returnValue = node;
205 break;
206 }
207 node = node.getNextSibling();
208 }
209 return returnValue;
210 }
211
212
213
214
215
216
217
218
219 public static List<DetailNode> getAllNodesOfType(DetailNode detailNode, int type) {
220 final List<DetailNode> nodes = new ArrayList<>();
221 DetailNode node = detailNode.getFirstChild();
222 while (node != null) {
223 if (node.getType() == type) {
224 nodes.add(node);
225 }
226 node = node.getNextSibling();
227 }
228 return nodes;
229 }
230
231
232
233
234
235
236
237
238
239
240 public static boolean isTag(DetailNode ast, String expectedTagName) {
241 final DetailNode htmlTagStart = findFirstToken(ast,
242 JavadocCommentsTokenTypes.HTML_TAG_START);
243 boolean isTag = false;
244 if (htmlTagStart != null) {
245 final String tagName = findFirstToken(htmlTagStart,
246 JavadocCommentsTokenTypes.TAG_NAME).getText();
247 isTag = expectedTagName.equalsIgnoreCase(tagName);
248 }
249 return isTag;
250 }
251
252
253
254
255
256
257
258
259 public static DetailNode getNextSibling(DetailNode node, int tokenType) {
260 DetailNode nextSibling = node.getNextSibling();
261 while (nextSibling != null && nextSibling.getType() != tokenType) {
262 nextSibling = nextSibling.getNextSibling();
263 }
264 return nextSibling;
265 }
266
267
268
269
270
271
272
273
274
275 public static String getTokenName(int id) {
276 final String name = TOKEN_VALUE_TO_NAME.get(id);
277 if (name == null) {
278 throw new IllegalArgumentException(UNKNOWN_JAVADOC_TOKEN_ID_EXCEPTION_MESSAGE + id);
279 }
280 return name;
281 }
282
283
284
285
286
287
288
289
290
291 public static int getTokenId(String name) {
292 final Integer id = TOKEN_NAME_TO_VALUE.get(name);
293 if (id == null) {
294 throw new IllegalArgumentException("Unknown javadoc token name. Given name " + name);
295 }
296 return id;
297 }
298
299
300
301
302
303
304
305
306
307 public static String getTagName(DetailNode javadocTagSection) {
308 return findFirstToken(javadocTagSection.getFirstChild(),
309 JavadocCommentsTokenTypes.TAG_NAME).getText();
310 }
311
312
313
314
315
316
317
318 public static String escapeAllControlChars(String text) {
319 final String textWithoutNewlines = NEWLINE.matcher(text).replaceAll("\\\\n");
320 final String textWithoutReturns = RETURN.matcher(textWithoutNewlines).replaceAll("\\\\r");
321 return TAB.matcher(textWithoutReturns).replaceAll("\\\\t");
322 }
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341 public static boolean isCorrectJavadocPosition(DetailAST blockComment) {
342
343 DetailAST sibling = blockComment.getNextSibling();
344 while (sibling != null) {
345 if (sibling.getType() == TokenTypes.BLOCK_COMMENT_BEGIN) {
346 if (isJavadocComment(getBlockCommentContent(sibling))) {
347
348 break;
349 }
350 sibling = sibling.getNextSibling();
351 }
352 else if (sibling.getType() == TokenTypes.SINGLE_LINE_COMMENT) {
353 sibling = sibling.getNextSibling();
354 }
355 else {
356
357 sibling = null;
358 }
359 }
360 return sibling == null
361 && (BlockCommentPosition.isOnType(blockComment)
362 || BlockCommentPosition.isOnMember(blockComment)
363 || BlockCommentPosition.isOnPackage(blockComment));
364 }
365
366 }