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 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.valueToNameArrayFromNameToValueMap(TOKEN_NAME_TO_VALUE);
81 }
82
83
84 private JavadocUtil() {
85 }
86
87
88
89
90
91
92
93
94
95 public static JavadocTags getJavadocTags(TextBlock textBlock,
96 JavadocTagType tagType) {
97 final boolean getBlockTags = tagType == JavadocTagType.ALL
98 || tagType == JavadocTagType.BLOCK;
99 final boolean getInlineTags = tagType == JavadocTagType.ALL
100 || tagType == JavadocTagType.INLINE;
101
102 final List<TagInfo> tags = new ArrayList<>();
103
104 if (getBlockTags) {
105 tags.addAll(BlockTagUtil.extractBlockTags(textBlock.getText()));
106 }
107
108 if (getInlineTags) {
109 tags.addAll(InlineTagUtil.extractInlineTags(textBlock.getText()));
110 }
111
112 final List<JavadocTag> validTags = new ArrayList<>();
113 final List<InvalidJavadocTag> invalidTags = new ArrayList<>();
114
115 for (TagInfo tag : tags) {
116 final int col = tag.getPosition().getColumn();
117
118
119
120
121 final int line = textBlock.getStartLineNo() + tag.getPosition().getLine() - 1;
122
123 if (JavadocTagInfo.isValidName(tag.getName())) {
124 validTags.add(
125 new JavadocTag(line, col, tag.getName(), tag.getValue()));
126 }
127 else {
128 invalidTags.add(new InvalidJavadocTag(line, col, tag.getName()));
129 }
130 }
131
132 return new JavadocTags(validTags, invalidTags);
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 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 private static String getBlockCommentContent(DetailAST blockCommentBegin) {
172 final DetailAST commentContent = blockCommentBegin.getFirstChild();
173 return commentContent.getText();
174 }
175
176
177
178
179
180
181
182 public static String getJavadocCommentContent(DetailAST javadocCommentBegin) {
183 final DetailAST commentContent = javadocCommentBegin.getFirstChild();
184 return commentContent.getText().substring(1);
185 }
186
187
188
189
190
191
192
193
194
195 public static DetailNode findFirstToken(DetailNode detailNode, int type) {
196 DetailNode returnValue = null;
197 DetailNode node = getFirstChild(detailNode);
198 while (node != null) {
199 if (node.getType() == type) {
200 returnValue = node;
201 break;
202 }
203 node = getNextSibling(node);
204 }
205 return returnValue;
206 }
207
208
209
210
211
212
213
214 public static DetailNode getFirstChild(DetailNode node) {
215 DetailNode resultNode = null;
216
217 if (node.getChildren().length > 0) {
218 resultNode = node.getChildren()[0];
219 }
220 return resultNode;
221 }
222
223
224
225
226
227
228
229
230 public static boolean containsInBranch(DetailNode node, int type) {
231 boolean result = true;
232 DetailNode curNode = node;
233 while (type != curNode.getType()) {
234 DetailNode toVisit = getFirstChild(curNode);
235 while (curNode != null && toVisit == null) {
236 toVisit = getNextSibling(curNode);
237 if (toVisit == null) {
238 curNode = curNode.getParent();
239 }
240 }
241
242 if (curNode == toVisit) {
243 result = false;
244 break;
245 }
246
247 curNode = toVisit;
248 }
249 return result;
250 }
251
252
253
254
255
256
257
258 public static DetailNode getNextSibling(DetailNode node) {
259 DetailNode nextSibling = null;
260 final DetailNode parent = node.getParent();
261 if (parent != null) {
262 final int nextSiblingIndex = node.getIndex() + 1;
263 final DetailNode[] children = parent.getChildren();
264 if (nextSiblingIndex <= children.length - 1) {
265 nextSibling = children[nextSiblingIndex];
266 }
267 }
268 return nextSibling;
269 }
270
271
272
273
274
275
276
277
278 public static DetailNode getNextSibling(DetailNode node, int tokenType) {
279 DetailNode nextSibling = getNextSibling(node);
280 while (nextSibling != null && nextSibling.getType() != tokenType) {
281 nextSibling = getNextSibling(nextSibling);
282 }
283 return nextSibling;
284 }
285
286
287
288
289
290
291 public static DetailNode getPreviousSibling(DetailNode node) {
292 DetailNode previousSibling = null;
293 final int previousSiblingIndex = node.getIndex() - 1;
294 if (previousSiblingIndex >= 0) {
295 final DetailNode parent = node.getParent();
296 final DetailNode[] children = parent.getChildren();
297 previousSibling = children[previousSiblingIndex];
298 }
299 return previousSibling;
300 }
301
302
303
304
305
306
307
308 public static String getTokenName(int id) {
309 final String name;
310 if (id == JavadocTokenTypes.EOF) {
311 name = "EOF";
312 }
313 else if (id > TOKEN_VALUE_TO_NAME.length - 1) {
314 throw new IllegalArgumentException(UNKNOWN_JAVADOC_TOKEN_ID_EXCEPTION_MESSAGE + id);
315 }
316 else {
317 name = TOKEN_VALUE_TO_NAME[id];
318 if (name == null) {
319 throw new IllegalArgumentException(UNKNOWN_JAVADOC_TOKEN_ID_EXCEPTION_MESSAGE + id);
320 }
321 }
322 return name;
323 }
324
325
326
327
328
329
330
331 public static int getTokenId(String name) {
332 final Integer id = TOKEN_NAME_TO_VALUE.get(name);
333 if (id == null) {
334 throw new IllegalArgumentException("Unknown javadoc token name. Given name " + name);
335 }
336 return id;
337 }
338
339
340
341
342
343
344
345 public static String getTagName(DetailNode javadocTagSection) {
346 final String javadocTagName;
347 if (javadocTagSection.getType() == JavadocTokenTypes.JAVADOC_INLINE_TAG) {
348 javadocTagName = getNextSibling(
349 getFirstChild(javadocTagSection)).getText();
350 }
351 else {
352 javadocTagName = getFirstChild(javadocTagSection).getText();
353 }
354 return javadocTagName;
355 }
356
357
358
359
360
361
362 public static String escapeAllControlChars(String text) {
363 final String textWithoutNewlines = NEWLINE.matcher(text).replaceAll("\\\\n");
364 final String textWithoutReturns = RETURN.matcher(textWithoutNewlines).replaceAll("\\\\r");
365 return TAB.matcher(textWithoutReturns).replaceAll("\\\\t");
366 }
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383 private static boolean isCorrectJavadocPosition(DetailAST blockComment) {
384
385 DetailAST sibling = blockComment.getNextSibling();
386 while (sibling != null) {
387 if (sibling.getType() == TokenTypes.BLOCK_COMMENT_BEGIN) {
388 if (isJavadocComment(getBlockCommentContent(sibling))) {
389
390 break;
391 }
392 sibling = sibling.getNextSibling();
393 }
394 else if (sibling.getType() == TokenTypes.SINGLE_LINE_COMMENT) {
395 sibling = sibling.getNextSibling();
396 }
397 else {
398
399 sibling = null;
400 }
401 }
402 return sibling == null
403 && (BlockCommentPosition.isOnType(blockComment)
404 || BlockCommentPosition.isOnMember(blockComment)
405 || BlockCommentPosition.isOnPackage(blockComment));
406 }
407
408 }