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