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;
21
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Set;
25
26 import org.antlr.v4.runtime.BufferedTokenStream;
27 import org.antlr.v4.runtime.CommonTokenStream;
28 import org.antlr.v4.runtime.ParserRuleContext;
29 import org.antlr.v4.runtime.Token;
30 import org.antlr.v4.runtime.tree.ParseTree;
31 import org.antlr.v4.runtime.tree.TerminalNode;
32
33 import com.puppycrawl.tools.checkstyle.api.DetailNode;
34 import com.puppycrawl.tools.checkstyle.api.JavadocCommentsTokenTypes;
35 import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocNodeImpl;
36 import com.puppycrawl.tools.checkstyle.grammar.javadoc.JavadocCommentsLexer;
37 import com.puppycrawl.tools.checkstyle.grammar.javadoc.JavadocCommentsParser;
38 import com.puppycrawl.tools.checkstyle.grammar.javadoc.JavadocCommentsParserBaseVisitor;
39 import com.puppycrawl.tools.checkstyle.utils.JavadocUtil;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 public class JavadocCommentsAstVisitor extends JavadocCommentsParserBaseVisitor<JavadocNodeImpl> {
60
61
62
63
64 private static final Set<Integer> JAVADOC_TAG_TYPES = Set.of(
65 JavadocCommentsLexer.CODE,
66 JavadocCommentsLexer.LINK,
67 JavadocCommentsLexer.LINKPLAIN,
68 JavadocCommentsLexer.VALUE,
69 JavadocCommentsLexer.INHERIT_DOC,
70 JavadocCommentsLexer.SUMMARY,
71 JavadocCommentsLexer.SYSTEM_PROPERTY,
72 JavadocCommentsLexer.INDEX,
73 JavadocCommentsLexer.RETURN,
74 JavadocCommentsLexer.LITERAL,
75 JavadocCommentsLexer.SNIPPET,
76 JavadocCommentsLexer.CUSTOM_NAME,
77 JavadocCommentsLexer.AUTHOR,
78 JavadocCommentsLexer.DEPRECATED,
79 JavadocCommentsLexer.PARAM,
80 JavadocCommentsLexer.THROWS,
81 JavadocCommentsLexer.EXCEPTION,
82 JavadocCommentsLexer.SINCE,
83 JavadocCommentsLexer.VERSION,
84 JavadocCommentsLexer.SEE,
85 JavadocCommentsLexer.LITERAL_HIDDEN,
86 JavadocCommentsLexer.USES,
87 JavadocCommentsLexer.PROVIDES,
88 JavadocCommentsLexer.SERIAL,
89 JavadocCommentsLexer.SERIAL_DATA,
90 JavadocCommentsLexer.SERIAL_FIELD
91 );
92
93
94
95
96 private final int blockCommentLineNumber;
97
98
99
100
101 private final int javadocColumnNumber;
102
103
104
105
106 private final BufferedTokenStream tokens;
107
108
109
110
111
112 private final Set<Integer> processedTokenIndices = new HashSet<>();
113
114
115
116
117
118 private final TextAccumulator accumulator = new TextAccumulator();
119
120
121
122
123 private DetailNode firstNonTightHtmlTag;
124
125
126
127
128
129
130
131
132 public JavadocCommentsAstVisitor(CommonTokenStream tokens,
133 int blockCommentLineNumber, int javadocColumnNumber) {
134 this.tokens = tokens;
135 this.blockCommentLineNumber = blockCommentLineNumber;
136 this.javadocColumnNumber = javadocColumnNumber;
137 }
138
139 @Override
140 public JavadocNodeImpl visitJavadoc(JavadocCommentsParser.JavadocContext ctx) {
141 return buildImaginaryNode(JavadocCommentsTokenTypes.JAVADOC_CONTENT, ctx);
142 }
143
144 @Override
145 public JavadocNodeImpl visitMainDescription(JavadocCommentsParser.MainDescriptionContext ctx) {
146 return flattenedTree(ctx);
147 }
148
149 @Override
150 public JavadocNodeImpl visitBlockTag(JavadocCommentsParser.BlockTagContext ctx) {
151 final JavadocNodeImpl blockTagNode =
152 createImaginary(JavadocCommentsTokenTypes.JAVADOC_BLOCK_TAG);
153 final ParseTree tag = ctx.getChild(0);
154 final Token tagName = (Token) tag.getChild(1).getPayload();
155 final int tokenType = tagName.getType();
156 final JavadocNodeImpl specificTagNode = switch (tokenType) {
157 case JavadocCommentsLexer.AUTHOR ->
158 buildImaginaryNode(JavadocCommentsTokenTypes.AUTHOR_BLOCK_TAG, ctx);
159 case JavadocCommentsLexer.DEPRECATED ->
160 buildImaginaryNode(JavadocCommentsTokenTypes.DEPRECATED_BLOCK_TAG, ctx);
161 case JavadocCommentsLexer.RETURN ->
162 buildImaginaryNode(JavadocCommentsTokenTypes.RETURN_BLOCK_TAG, ctx);
163 case JavadocCommentsLexer.PARAM ->
164 buildImaginaryNode(JavadocCommentsTokenTypes.PARAM_BLOCK_TAG, ctx);
165 case JavadocCommentsLexer.THROWS ->
166 buildImaginaryNode(JavadocCommentsTokenTypes.THROWS_BLOCK_TAG, ctx);
167 case JavadocCommentsLexer.EXCEPTION ->
168 buildImaginaryNode(JavadocCommentsTokenTypes.EXCEPTION_BLOCK_TAG, ctx);
169 case JavadocCommentsLexer.SINCE ->
170 buildImaginaryNode(JavadocCommentsTokenTypes.SINCE_BLOCK_TAG, ctx);
171 case JavadocCommentsLexer.VERSION ->
172 buildImaginaryNode(JavadocCommentsTokenTypes.VERSION_BLOCK_TAG, ctx);
173 case JavadocCommentsLexer.SEE ->
174 buildImaginaryNode(JavadocCommentsTokenTypes.SEE_BLOCK_TAG, ctx);
175 case JavadocCommentsLexer.LITERAL_HIDDEN ->
176 buildImaginaryNode(JavadocCommentsTokenTypes.HIDDEN_BLOCK_TAG, ctx);
177 case JavadocCommentsLexer.USES ->
178 buildImaginaryNode(JavadocCommentsTokenTypes.USES_BLOCK_TAG, ctx);
179 case JavadocCommentsLexer.PROVIDES ->
180 buildImaginaryNode(JavadocCommentsTokenTypes.PROVIDES_BLOCK_TAG, ctx);
181 case JavadocCommentsLexer.SERIAL ->
182 buildImaginaryNode(JavadocCommentsTokenTypes.SERIAL_BLOCK_TAG, ctx);
183 case JavadocCommentsLexer.SERIAL_DATA ->
184 buildImaginaryNode(JavadocCommentsTokenTypes.SERIAL_DATA_BLOCK_TAG, ctx);
185 case JavadocCommentsLexer.SERIAL_FIELD ->
186 buildImaginaryNode(JavadocCommentsTokenTypes.SERIAL_FIELD_BLOCK_TAG, ctx);
187 default ->
188 buildImaginaryNode(JavadocCommentsTokenTypes.CUSTOM_BLOCK_TAG, ctx);
189 };
190 blockTagNode.addChild(specificTagNode);
191
192 return blockTagNode;
193 }
194
195 @Override
196 public JavadocNodeImpl visitAuthorTag(JavadocCommentsParser.AuthorTagContext ctx) {
197 return flattenedTree(ctx);
198 }
199
200 @Override
201 public JavadocNodeImpl visitDeprecatedTag(JavadocCommentsParser.DeprecatedTagContext ctx) {
202 return flattenedTree(ctx);
203 }
204
205 @Override
206 public JavadocNodeImpl visitReturnTag(JavadocCommentsParser.ReturnTagContext ctx) {
207 return flattenedTree(ctx);
208 }
209
210 @Override
211 public JavadocNodeImpl visitParameterTag(JavadocCommentsParser.ParameterTagContext ctx) {
212 return flattenedTree(ctx);
213 }
214
215 @Override
216 public JavadocNodeImpl visitThrowsTag(JavadocCommentsParser.ThrowsTagContext ctx) {
217 return flattenedTree(ctx);
218 }
219
220 @Override
221 public JavadocNodeImpl visitExceptionTag(JavadocCommentsParser.ExceptionTagContext ctx) {
222 return flattenedTree(ctx);
223 }
224
225 @Override
226 public JavadocNodeImpl visitSinceTag(JavadocCommentsParser.SinceTagContext ctx) {
227 return flattenedTree(ctx);
228 }
229
230 @Override
231 public JavadocNodeImpl visitVersionTag(JavadocCommentsParser.VersionTagContext ctx) {
232 return flattenedTree(ctx);
233 }
234
235 @Override
236 public JavadocNodeImpl visitSeeTag(JavadocCommentsParser.SeeTagContext ctx) {
237 return flattenedTree(ctx);
238 }
239
240 @Override
241 public JavadocNodeImpl visitHiddenTag(JavadocCommentsParser.HiddenTagContext ctx) {
242 return flattenedTree(ctx);
243 }
244
245 @Override
246 public JavadocNodeImpl visitUsesTag(JavadocCommentsParser.UsesTagContext ctx) {
247 return flattenedTree(ctx);
248 }
249
250 @Override
251 public JavadocNodeImpl visitProvidesTag(JavadocCommentsParser.ProvidesTagContext ctx) {
252 return flattenedTree(ctx);
253 }
254
255 @Override
256 public JavadocNodeImpl visitSerialTag(JavadocCommentsParser.SerialTagContext ctx) {
257 return flattenedTree(ctx);
258 }
259
260 @Override
261 public JavadocNodeImpl visitSerialDataTag(JavadocCommentsParser.SerialDataTagContext ctx) {
262 return flattenedTree(ctx);
263 }
264
265 @Override
266 public JavadocNodeImpl visitSerialFieldTag(JavadocCommentsParser.SerialFieldTagContext ctx) {
267 return flattenedTree(ctx);
268 }
269
270 @Override
271 public JavadocNodeImpl visitCustomBlockTag(JavadocCommentsParser.CustomBlockTagContext ctx) {
272 return flattenedTree(ctx);
273 }
274
275 @Override
276 public JavadocNodeImpl visitInlineTag(JavadocCommentsParser.InlineTagContext ctx) {
277 final JavadocNodeImpl inlineTagNode =
278 createImaginary(JavadocCommentsTokenTypes.JAVADOC_INLINE_TAG);
279 final ParseTree tagContent = ctx.inlineTagContent().getChild(0);
280 final Token tagName = (Token) tagContent.getChild(0).getPayload();
281 final int tokenType = tagName.getType();
282 final JavadocNodeImpl specificTagNode = switch (tokenType) {
283 case JavadocCommentsLexer.CODE ->
284 buildImaginaryNode(JavadocCommentsTokenTypes.CODE_INLINE_TAG, ctx);
285 case JavadocCommentsLexer.LINK ->
286 buildImaginaryNode(JavadocCommentsTokenTypes.LINK_INLINE_TAG, ctx);
287 case JavadocCommentsLexer.LINKPLAIN ->
288 buildImaginaryNode(JavadocCommentsTokenTypes.LINKPLAIN_INLINE_TAG, ctx);
289 case JavadocCommentsLexer.VALUE ->
290 buildImaginaryNode(JavadocCommentsTokenTypes.VALUE_INLINE_TAG, ctx);
291 case JavadocCommentsLexer.INHERIT_DOC ->
292 buildImaginaryNode(JavadocCommentsTokenTypes.INHERIT_DOC_INLINE_TAG, ctx);
293 case JavadocCommentsLexer.SUMMARY ->
294 buildImaginaryNode(JavadocCommentsTokenTypes.SUMMARY_INLINE_TAG, ctx);
295 case JavadocCommentsLexer.SYSTEM_PROPERTY ->
296 buildImaginaryNode(JavadocCommentsTokenTypes.SYSTEM_PROPERTY_INLINE_TAG, ctx);
297 case JavadocCommentsLexer.INDEX ->
298 buildImaginaryNode(JavadocCommentsTokenTypes.INDEX_INLINE_TAG, ctx);
299 case JavadocCommentsLexer.RETURN ->
300 buildImaginaryNode(JavadocCommentsTokenTypes.RETURN_INLINE_TAG, ctx);
301 case JavadocCommentsLexer.LITERAL ->
302 buildImaginaryNode(JavadocCommentsTokenTypes.LITERAL_INLINE_TAG, ctx);
303 case JavadocCommentsLexer.SNIPPET ->
304 buildImaginaryNode(JavadocCommentsTokenTypes.SNIPPET_INLINE_TAG, ctx);
305 default -> buildImaginaryNode(JavadocCommentsTokenTypes.CUSTOM_INLINE_TAG, ctx);
306 };
307 inlineTagNode.addChild(specificTagNode);
308
309 return inlineTagNode;
310 }
311
312 @Override
313 public JavadocNodeImpl visitInlineTagContent(
314 JavadocCommentsParser.InlineTagContentContext ctx) {
315 return flattenedTree(ctx);
316 }
317
318 @Override
319 public JavadocNodeImpl visitCodeInlineTag(JavadocCommentsParser.CodeInlineTagContext ctx) {
320 return flattenedTree(ctx);
321 }
322
323 @Override
324 public JavadocNodeImpl visitLinkPlainInlineTag(
325 JavadocCommentsParser.LinkPlainInlineTagContext ctx) {
326 return flattenedTree(ctx);
327 }
328
329 @Override
330 public JavadocNodeImpl visitLinkInlineTag(JavadocCommentsParser.LinkInlineTagContext ctx) {
331 return flattenedTree(ctx);
332 }
333
334 @Override
335 public JavadocNodeImpl visitValueInlineTag(JavadocCommentsParser.ValueInlineTagContext ctx) {
336 return flattenedTree(ctx);
337 }
338
339 @Override
340 public JavadocNodeImpl visitInheritDocInlineTag(
341 JavadocCommentsParser.InheritDocInlineTagContext ctx) {
342 return flattenedTree(ctx);
343 }
344
345 @Override
346 public JavadocNodeImpl visitSummaryInlineTag(
347 JavadocCommentsParser.SummaryInlineTagContext ctx) {
348 return flattenedTree(ctx);
349 }
350
351 @Override
352 public JavadocNodeImpl visitSystemPropertyInlineTag(
353 JavadocCommentsParser.SystemPropertyInlineTagContext ctx) {
354 return flattenedTree(ctx);
355 }
356
357 @Override
358 public JavadocNodeImpl visitIndexInlineTag(JavadocCommentsParser.IndexInlineTagContext ctx) {
359 return flattenedTree(ctx);
360 }
361
362 @Override
363 public JavadocNodeImpl visitReturnInlineTag(JavadocCommentsParser.ReturnInlineTagContext ctx) {
364 return flattenedTree(ctx);
365 }
366
367 @Override
368 public JavadocNodeImpl visitLiteralInlineTag(
369 JavadocCommentsParser.LiteralInlineTagContext ctx) {
370 return flattenedTree(ctx);
371 }
372
373 @Override
374 public JavadocNodeImpl visitSnippetInlineTag(
375 JavadocCommentsParser.SnippetInlineTagContext ctx) {
376 final JavadocNodeImpl dummyRoot = new JavadocNodeImpl();
377 if (!ctx.snippetAttributes.isEmpty()) {
378 final JavadocNodeImpl snippetAttributes =
379 createImaginary(JavadocCommentsTokenTypes.SNIPPET_ATTRIBUTES);
380 ctx.snippetAttributes.forEach(snippetAttributeContext -> {
381 final JavadocNodeImpl snippetAttribute = visit(snippetAttributeContext);
382 snippetAttributes.addChild(snippetAttribute);
383 });
384 dummyRoot.addChild(snippetAttributes);
385 }
386 if (ctx.COLON() != null) {
387 dummyRoot.addChild(create((Token) ctx.COLON().getPayload()));
388 }
389 if (ctx.snippetBody() != null) {
390 dummyRoot.addChild(visit(ctx.snippetBody()));
391 }
392 return dummyRoot.getFirstChild();
393 }
394
395 @Override
396 public JavadocNodeImpl visitCustomInlineTag(JavadocCommentsParser.CustomInlineTagContext ctx) {
397 return flattenedTree(ctx);
398 }
399
400 @Override
401 public JavadocNodeImpl visitReference(JavadocCommentsParser.ReferenceContext ctx) {
402 return buildImaginaryNode(JavadocCommentsTokenTypes.REFERENCE, ctx);
403 }
404
405 @Override
406 public JavadocNodeImpl visitTypeName(JavadocCommentsParser.TypeNameContext ctx) {
407 return flattenedTree(ctx);
408
409 }
410
411 @Override
412 public JavadocNodeImpl visitQualifiedName(JavadocCommentsParser.QualifiedNameContext ctx) {
413 return flattenedTree(ctx);
414 }
415
416 @Override
417 public JavadocNodeImpl visitTypeArguments(JavadocCommentsParser.TypeArgumentsContext ctx) {
418 return buildImaginaryNode(JavadocCommentsTokenTypes.TYPE_ARGUMENTS, ctx);
419 }
420
421 @Override
422 public JavadocNodeImpl visitTypeArgument(JavadocCommentsParser.TypeArgumentContext ctx) {
423 return buildImaginaryNode(JavadocCommentsTokenTypes.TYPE_ARGUMENT, ctx);
424 }
425
426 @Override
427 public JavadocNodeImpl visitMemberReference(JavadocCommentsParser.MemberReferenceContext ctx) {
428 return buildImaginaryNode(JavadocCommentsTokenTypes.MEMBER_REFERENCE, ctx);
429 }
430
431 @Override
432 public JavadocNodeImpl visitParameterTypeList(
433 JavadocCommentsParser.ParameterTypeListContext ctx) {
434 return buildImaginaryNode(JavadocCommentsTokenTypes.PARAMETER_TYPE_LIST, ctx);
435 }
436
437 @Override
438 public JavadocNodeImpl visitDescription(JavadocCommentsParser.DescriptionContext ctx) {
439 return buildImaginaryNode(JavadocCommentsTokenTypes.DESCRIPTION, ctx);
440 }
441
442 @Override
443 public JavadocNodeImpl visitSnippetAttribute(
444 JavadocCommentsParser.SnippetAttributeContext ctx) {
445 return buildImaginaryNode(JavadocCommentsTokenTypes.SNIPPET_ATTRIBUTE, ctx);
446 }
447
448 @Override
449 public JavadocNodeImpl visitSnippetBody(JavadocCommentsParser.SnippetBodyContext ctx) {
450 return buildImaginaryNode(JavadocCommentsTokenTypes.SNIPPET_BODY, ctx);
451 }
452
453 @Override
454 public JavadocNodeImpl visitHtmlElement(JavadocCommentsParser.HtmlElementContext ctx) {
455 return buildImaginaryNode(JavadocCommentsTokenTypes.HTML_ELEMENT, ctx);
456 }
457
458 @Override
459 public JavadocNodeImpl visitVoidElement(JavadocCommentsParser.VoidElementContext ctx) {
460 return buildImaginaryNode(JavadocCommentsTokenTypes.VOID_ELEMENT, ctx);
461 }
462
463 @Override
464 public JavadocNodeImpl visitTightElement(JavadocCommentsParser.TightElementContext ctx) {
465 return flattenedTree(ctx);
466 }
467
468 @Override
469 public JavadocNodeImpl visitNonTightElement(JavadocCommentsParser.NonTightElementContext ctx) {
470 if (firstNonTightHtmlTag == null) {
471 final ParseTree htmlTagStart = ctx.getChild(0);
472 final ParseTree tagNameToken = htmlTagStart.getChild(1);
473 firstNonTightHtmlTag = create((Token) tagNameToken.getPayload());
474 }
475 return flattenedTree(ctx);
476 }
477
478 @Override
479 public JavadocNodeImpl visitSelfClosingElement(
480 JavadocCommentsParser.SelfClosingElementContext ctx) {
481 final JavadocNodeImpl javadocNode =
482 createImaginary(JavadocCommentsTokenTypes.VOID_ELEMENT);
483 javadocNode.addChild(create((Token) ctx.TAG_OPEN().getPayload()));
484 javadocNode.addChild(create((Token) ctx.TAG_NAME().getPayload()));
485 if (!ctx.htmlAttributes.isEmpty()) {
486 final JavadocNodeImpl htmlAttributes =
487 createImaginary(JavadocCommentsTokenTypes.HTML_ATTRIBUTES);
488 ctx.htmlAttributes.forEach(htmlAttributeContext -> {
489 final JavadocNodeImpl htmlAttribute = visit(htmlAttributeContext);
490 htmlAttributes.addChild(htmlAttribute);
491 });
492 javadocNode.addChild(htmlAttributes);
493 }
494
495 javadocNode.addChild(create((Token) ctx.TAG_SLASH_CLOSE().getPayload()));
496 return javadocNode;
497 }
498
499 @Override
500 public JavadocNodeImpl visitHtmlTagStart(JavadocCommentsParser.HtmlTagStartContext ctx) {
501 final JavadocNodeImpl javadocNode =
502 createImaginary(JavadocCommentsTokenTypes.HTML_TAG_START);
503 javadocNode.addChild(create((Token) ctx.TAG_OPEN().getPayload()));
504 javadocNode.addChild(create((Token) ctx.TAG_NAME().getPayload()));
505 if (!ctx.htmlAttributes.isEmpty()) {
506 final JavadocNodeImpl htmlAttributes =
507 createImaginary(JavadocCommentsTokenTypes.HTML_ATTRIBUTES);
508 ctx.htmlAttributes.forEach(htmlAttributeContext -> {
509 final JavadocNodeImpl htmlAttribute = visit(htmlAttributeContext);
510 htmlAttributes.addChild(htmlAttribute);
511 });
512 javadocNode.addChild(htmlAttributes);
513 }
514
515 final Token tagClose = (Token) ctx.TAG_CLOSE().getPayload();
516 addHiddenTokensToTheLeft(tagClose, javadocNode);
517 javadocNode.addChild(create(tagClose));
518 return javadocNode;
519 }
520
521 @Override
522 public JavadocNodeImpl visitHtmlTagEnd(JavadocCommentsParser.HtmlTagEndContext ctx) {
523 return buildImaginaryNode(JavadocCommentsTokenTypes.HTML_TAG_END, ctx);
524 }
525
526 @Override
527 public JavadocNodeImpl visitHtmlAttribute(JavadocCommentsParser.HtmlAttributeContext ctx) {
528 return buildImaginaryNode(JavadocCommentsTokenTypes.HTML_ATTRIBUTE, ctx);
529 }
530
531 @Override
532 public JavadocNodeImpl visitHtmlContent(JavadocCommentsParser.HtmlContentContext ctx) {
533 return buildImaginaryNode(JavadocCommentsTokenTypes.HTML_CONTENT, ctx);
534 }
535
536 @Override
537 public JavadocNodeImpl visitNonTightHtmlContent(
538 JavadocCommentsParser.NonTightHtmlContentContext ctx) {
539 return buildImaginaryNode(JavadocCommentsTokenTypes.HTML_CONTENT, ctx);
540 }
541
542 @Override
543 public JavadocNodeImpl visitHtmlComment(JavadocCommentsParser.HtmlCommentContext ctx) {
544 return buildImaginaryNode(JavadocCommentsTokenTypes.HTML_COMMENT, ctx);
545 }
546
547 @Override
548 public JavadocNodeImpl visitHtmlCommentContent(
549 JavadocCommentsParser.HtmlCommentContentContext ctx) {
550 return buildImaginaryNode(JavadocCommentsTokenTypes.HTML_COMMENT_CONTENT, ctx);
551 }
552
553
554
555
556
557
558
559
560
561 private JavadocNodeImpl buildImaginaryNode(int tokenType, ParserRuleContext ctx) {
562 final JavadocNodeImpl javadocNode = createImaginary(tokenType);
563 processChildren(javadocNode, ctx.children);
564 return javadocNode;
565 }
566
567
568
569
570
571
572
573
574 private JavadocNodeImpl flattenedTree(ParserRuleContext ctx) {
575 final JavadocNodeImpl dummyNode = new JavadocNodeImpl();
576 processChildren(dummyNode, ctx.children);
577 return dummyNode.getFirstChild();
578 }
579
580
581
582
583
584
585
586
587 private void processChildren(JavadocNodeImpl parent, List<? extends ParseTree> children) {
588 for (ParseTree child : children) {
589 if (child instanceof TerminalNode terminalNode) {
590 final Token token = (Token) terminalNode.getPayload();
591
592
593 addHiddenTokensToTheLeft(token, parent);
594
595 if (isTextToken(token)) {
596 accumulator.append(token);
597 }
598 else if (token.getType() != Token.EOF) {
599 parent.addChild(create(token));
600 }
601 }
602 else {
603 accumulator.flushTo(parent);
604 final Token token = ((ParserRuleContext) child).getStart();
605 addHiddenTokensToTheLeft(token, parent);
606 parent.addChild(visit(child));
607 }
608 }
609
610 accumulator.flushTo(parent);
611 }
612
613
614
615
616
617
618
619 private static boolean isTextToken(Token token) {
620 return token.getType() == JavadocCommentsTokenTypes.TEXT;
621 }
622
623
624
625
626
627
628
629
630
631 private void addHiddenTokensToTheLeft(Token token, JavadocNodeImpl parent) {
632 final boolean alreadyProcessed = !processedTokenIndices.add(token.getTokenIndex());
633
634 if (!alreadyProcessed) {
635 final int tokenIndex = token.getTokenIndex();
636 final List<Token> hiddenTokens = tokens.getHiddenTokensToLeft(tokenIndex);
637 if (hiddenTokens != null) {
638 accumulator.flushTo(parent);
639 for (Token hiddenToken : hiddenTokens) {
640 parent.addChild(create(hiddenToken));
641 }
642 }
643 }
644 }
645
646
647
648
649
650
651
652 private JavadocNodeImpl create(Token token) {
653 final JavadocNodeImpl node = new JavadocNodeImpl();
654 node.initialize(token);
655
656
657 node.setLineNumber(node.getLineNumber() + blockCommentLineNumber);
658
659
660 if (node.getLineNumber() == blockCommentLineNumber) {
661 node.setColumnNumber(node.getColumnNumber() + javadocColumnNumber);
662 }
663
664 if (isJavadocTag(token.getType())) {
665 node.setType(JavadocCommentsTokenTypes.TAG_NAME);
666 }
667
668 if (token.getType() == JavadocCommentsLexer.WS) {
669 node.setType(JavadocCommentsTokenTypes.TEXT);
670 }
671
672 return node;
673 }
674
675
676
677
678
679
680
681 private static boolean isJavadocTag(int type) {
682 return JAVADOC_TAG_TYPES.contains(type);
683 }
684
685
686
687
688
689
690
691
692
693 private JavadocNodeImpl createImaginary(int tokenType) {
694 final JavadocNodeImpl node = new JavadocNodeImpl();
695 node.setType(tokenType);
696 node.setText(JavadocUtil.getTokenName(tokenType));
697 node.setLineNumber(blockCommentLineNumber);
698 node.setColumnNumber(javadocColumnNumber);
699 return node;
700 }
701
702
703
704
705
706
707 public DetailNode getFirstNonTightHtmlTag() {
708 return firstNonTightHtmlTag;
709 }
710
711
712
713
714
715 private final class TextAccumulator {
716
717
718
719
720
721
722 private final StringBuilder buffer = new StringBuilder(256);
723
724
725
726
727 private Token startToken;
728
729
730
731
732
733
734 void append(Token token) {
735 if (buffer.isEmpty()) {
736 startToken = token;
737 }
738 buffer.append(token.getText());
739 }
740
741
742
743
744
745
746
747 void flushTo(JavadocNodeImpl parent) {
748 if (!buffer.isEmpty()) {
749 final JavadocNodeImpl startNode = create(startToken);
750 startNode.setText(buffer.toString());
751 parent.addChild(startNode);
752 buffer.setLength(0);
753 }
754 }
755 }
756 }