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.checks.indentation;
21
22 import java.util.ArrayDeque;
23 import java.util.Deque;
24 import java.util.Locale;
25
26 import com.puppycrawl.tools.checkstyle.StatelessCheck;
27 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
28 import com.puppycrawl.tools.checkstyle.api.DetailAST;
29 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
30 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 @StatelessCheck
70 public class CommentsIndentationCheck extends AbstractCheck {
71
72
73
74
75 public static final String MSG_KEY_SINGLE = "comments.indentation.single";
76
77
78
79
80 public static final String MSG_KEY_BLOCK = "comments.indentation.block";
81
82 @Override
83 public int[] getDefaultTokens() {
84 return new int[] {
85 TokenTypes.SINGLE_LINE_COMMENT,
86 TokenTypes.BLOCK_COMMENT_BEGIN,
87 };
88 }
89
90 @Override
91 public int[] getAcceptableTokens() {
92 return new int[] {
93 TokenTypes.SINGLE_LINE_COMMENT,
94 TokenTypes.BLOCK_COMMENT_BEGIN,
95 };
96 }
97
98 @Override
99 public int[] getRequiredTokens() {
100 return CommonUtil.EMPTY_INT_ARRAY;
101 }
102
103 @Override
104 public boolean isCommentNodesRequired() {
105 return true;
106 }
107
108 @Override
109 public void visitToken(DetailAST commentAst) {
110 switch (commentAst.getType()) {
111 case TokenTypes.SINGLE_LINE_COMMENT:
112 case TokenTypes.BLOCK_COMMENT_BEGIN:
113 visitComment(commentAst);
114 break;
115 default:
116 final String exceptionMsg = "Unexpected token type: " + commentAst.getText();
117 throw new IllegalArgumentException(exceptionMsg);
118 }
119 }
120
121
122
123
124
125
126
127
128
129
130
131
132
133 private void visitComment(DetailAST comment) {
134 if (!isTrailingComment(comment)) {
135 final DetailAST prevStmt = getPreviousStatement(comment);
136 final DetailAST nextStmt = getNextStmt(comment);
137
138 if (isInEmptyCaseBlock(prevStmt, nextStmt)) {
139 handleCommentInEmptyCaseBlock(prevStmt, comment, nextStmt);
140 }
141 else if (isFallThroughComment(prevStmt, nextStmt)) {
142 handleFallThroughComment(prevStmt, comment, nextStmt);
143 }
144 else if (isInEmptyCodeBlock(prevStmt, nextStmt)) {
145 handleCommentInEmptyCodeBlock(comment, nextStmt);
146 }
147 else if (isCommentAtTheEndOfTheCodeBlock(nextStmt)) {
148 handleCommentAtTheEndOfTheCodeBlock(prevStmt, comment, nextStmt);
149 }
150 else if (nextStmt != null && !areSameLevelIndented(comment, nextStmt, nextStmt)) {
151 log(comment.getLineNo(), getMessageKey(comment), nextStmt.getLineNo(),
152 comment.getColumnNo(), nextStmt.getColumnNo());
153 }
154 }
155 }
156
157
158
159
160
161
162 private static DetailAST getNextStmt(DetailAST comment) {
163 DetailAST nextStmt = comment.getNextSibling();
164 while (nextStmt != null
165 && isComment(nextStmt)
166 && comment.getColumnNo() != nextStmt.getColumnNo()) {
167 nextStmt = nextStmt.getNextSibling();
168 }
169 return nextStmt;
170 }
171
172
173
174
175
176
177 private DetailAST getPreviousStatement(DetailAST comment) {
178 final DetailAST prevStatement;
179 if (isDistributedPreviousStatement(comment)) {
180 prevStatement = getDistributedPreviousStatement(comment);
181 }
182 else {
183 prevStatement = getOneLinePreviousStatement(comment);
184 }
185 return prevStatement;
186 }
187
188
189
190
191
192
193 private boolean isDistributedPreviousStatement(DetailAST comment) {
194 final DetailAST previousSibling = comment.getPreviousSibling();
195 return isDistributedExpression(comment)
196 || isDistributedReturnStatement(previousSibling)
197 || isDistributedThrowStatement(previousSibling);
198 }
199
200
201
202
203
204
205
206 private boolean isDistributedExpression(DetailAST comment) {
207 DetailAST previousSibling = comment.getPreviousSibling();
208 while (previousSibling != null && isComment(previousSibling)) {
209 previousSibling = previousSibling.getPreviousSibling();
210 }
211 boolean isDistributed = false;
212 if (previousSibling != null) {
213 if (previousSibling.getType() == TokenTypes.SEMI
214 && isOnPreviousLineIgnoringComments(comment, previousSibling)) {
215 DetailAST currentToken = previousSibling.getPreviousSibling();
216 while (currentToken.getFirstChild() != null) {
217 currentToken = currentToken.getFirstChild();
218 }
219 if (currentToken.getType() == TokenTypes.COMMENT_CONTENT) {
220 currentToken = currentToken.getParent();
221 while (isComment(currentToken)) {
222 currentToken = currentToken.getNextSibling();
223 }
224 }
225 if (previousSibling.getLineNo() != currentToken.getLineNo()) {
226 isDistributed = true;
227 }
228 }
229 else {
230 isDistributed = isStatementWithPossibleCurlies(previousSibling);
231 }
232 }
233 return isDistributed;
234 }
235
236
237
238
239
240
241 private static boolean isStatementWithPossibleCurlies(DetailAST previousSibling) {
242 return previousSibling.getType() == TokenTypes.LITERAL_IF
243 || previousSibling.getType() == TokenTypes.LITERAL_TRY
244 || previousSibling.getType() == TokenTypes.LITERAL_FOR
245 || previousSibling.getType() == TokenTypes.LITERAL_DO
246 || previousSibling.getType() == TokenTypes.LITERAL_WHILE
247 || previousSibling.getType() == TokenTypes.LITERAL_SWITCH
248 || isDefinition(previousSibling);
249 }
250
251
252
253
254
255
256 private static boolean isDefinition(DetailAST previousSibling) {
257 return previousSibling.getType() == TokenTypes.METHOD_DEF
258 || previousSibling.getType() == TokenTypes.CLASS_DEF
259 || previousSibling.getType() == TokenTypes.INTERFACE_DEF
260 || previousSibling.getType() == TokenTypes.ENUM_DEF
261 || previousSibling.getType() == TokenTypes.ANNOTATION_DEF;
262 }
263
264
265
266
267
268
269 private static boolean isDistributedReturnStatement(DetailAST commentPreviousSibling) {
270 boolean isDistributed = false;
271 if (commentPreviousSibling != null
272 && commentPreviousSibling.getType() == TokenTypes.LITERAL_RETURN) {
273 final DetailAST firstChild = commentPreviousSibling.getFirstChild();
274 final DetailAST nextSibling = firstChild.getNextSibling();
275 if (nextSibling != null) {
276 isDistributed = true;
277 }
278 }
279 return isDistributed;
280 }
281
282
283
284
285
286
287 private static boolean isDistributedThrowStatement(DetailAST commentPreviousSibling) {
288 boolean isDistributed = false;
289 if (commentPreviousSibling != null
290 && commentPreviousSibling.getType() == TokenTypes.LITERAL_THROW) {
291 final DetailAST firstChild = commentPreviousSibling.getFirstChild();
292 final DetailAST nextSibling = firstChild.getNextSibling();
293 if (nextSibling.getLineNo() != commentPreviousSibling.getLineNo()) {
294 isDistributed = true;
295 }
296 }
297 return isDistributed;
298 }
299
300
301
302
303
304
305 private static DetailAST getDistributedPreviousStatement(DetailAST comment) {
306 DetailAST currentToken = comment.getPreviousSibling();
307 while (isComment(currentToken)) {
308 currentToken = currentToken.getPreviousSibling();
309 }
310 final DetailAST previousStatement;
311 if (currentToken.getType() == TokenTypes.SEMI) {
312 currentToken = currentToken.getPreviousSibling();
313 while (currentToken.getFirstChild() != null) {
314 currentToken = currentToken.getFirstChild();
315 }
316 previousStatement = currentToken;
317 }
318 else {
319 previousStatement = currentToken;
320 }
321 return previousStatement;
322 }
323
324
325
326
327
328
329
330 private static boolean isInEmptyCaseBlock(DetailAST prevStmt, DetailAST nextStmt) {
331 return prevStmt != null
332 && nextStmt != null
333 && (prevStmt.getType() == TokenTypes.LITERAL_CASE
334 || prevStmt.getType() == TokenTypes.CASE_GROUP)
335 && (nextStmt.getType() == TokenTypes.LITERAL_CASE
336 || nextStmt.getType() == TokenTypes.LITERAL_DEFAULT);
337 }
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358 private static boolean isFallThroughComment(DetailAST prevStmt, DetailAST nextStmt) {
359 return prevStmt != null
360 && nextStmt != null
361 && prevStmt.getType() != TokenTypes.LITERAL_CASE
362 && (nextStmt.getType() == TokenTypes.LITERAL_CASE
363 || nextStmt.getType() == TokenTypes.LITERAL_DEFAULT);
364 }
365
366
367
368
369
370
371 private static boolean isCommentAtTheEndOfTheCodeBlock(DetailAST nextStmt) {
372 return nextStmt != null
373 && nextStmt.getType() == TokenTypes.RCURLY;
374 }
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391 private static boolean isInEmptyCodeBlock(DetailAST prevStmt, DetailAST nextStmt) {
392 return prevStmt != null
393 && nextStmt != null
394 && (prevStmt.getType() == TokenTypes.SLIST
395 || prevStmt.getType() == TokenTypes.LCURLY
396 || prevStmt.getType() == TokenTypes.ARRAY_INIT
397 || prevStmt.getType() == TokenTypes.OBJBLOCK)
398 && nextStmt.getType() == TokenTypes.RCURLY;
399 }
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421 private void handleCommentInEmptyCaseBlock(DetailAST prevStmt, DetailAST comment,
422 DetailAST nextStmt) {
423 if (comment.getColumnNo() < prevStmt.getColumnNo()
424 || comment.getColumnNo() < nextStmt.getColumnNo()) {
425 logMultilineIndentation(prevStmt, comment, nextStmt);
426 }
427 }
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462 private void handleFallThroughComment(DetailAST prevStmt, DetailAST comment,
463 DetailAST nextStmt) {
464 if (!areSameLevelIndented(comment, prevStmt, nextStmt)) {
465 logMultilineIndentation(prevStmt, comment, nextStmt);
466 }
467 }
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485 private void handleCommentAtTheEndOfTheCodeBlock(DetailAST prevStmt, DetailAST comment,
486 DetailAST nextStmt) {
487 if (prevStmt != null) {
488 if (prevStmt.getType() == TokenTypes.LITERAL_CASE
489 || prevStmt.getType() == TokenTypes.CASE_GROUP
490 || prevStmt.getType() == TokenTypes.LITERAL_DEFAULT) {
491 if (comment.getColumnNo() < nextStmt.getColumnNo()) {
492 log(comment.getLineNo(), getMessageKey(comment), nextStmt.getLineNo(),
493 comment.getColumnNo(), nextStmt.getColumnNo());
494 }
495 }
496 else if (isCommentForMultiblock(nextStmt)) {
497 if (!areSameLevelIndented(comment, prevStmt, nextStmt)) {
498 logMultilineIndentation(prevStmt, comment, nextStmt);
499 }
500 }
501 else if (!areSameLevelIndented(comment, prevStmt, prevStmt)) {
502 final int prevStmtLineNo = prevStmt.getLineNo();
503 log(comment.getLineNo(), getMessageKey(comment), prevStmtLineNo,
504 comment.getColumnNo(), getLineStart(prevStmtLineNo));
505 }
506 }
507 }
508
509
510
511
512
513
514
515 private static boolean isCommentForMultiblock(DetailAST endBlockStmt) {
516 final DetailAST nextBlock = endBlockStmt.getParent().getNextSibling();
517 final int endBlockLineNo = endBlockStmt.getLineNo();
518 final DetailAST catchAst = endBlockStmt.getParent().getParent();
519 final DetailAST finallyAst = catchAst.getNextSibling();
520 return nextBlock != null && nextBlock.getLineNo() == endBlockLineNo
521 || finallyAst != null
522 && catchAst.getType() == TokenTypes.LITERAL_CATCH
523 && finallyAst.getLineNo() == endBlockLineNo;
524 }
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544 private void handleCommentInEmptyCodeBlock(DetailAST comment, DetailAST nextStmt) {
545 if (comment.getColumnNo() < nextStmt.getColumnNo()) {
546 log(comment.getLineNo(), getMessageKey(comment), nextStmt.getLineNo(),
547 comment.getColumnNo(), nextStmt.getColumnNo());
548 }
549 }
550
551
552
553
554
555
556
557
558
559 private DetailAST getOneLinePreviousStatement(DetailAST comment) {
560 DetailAST root = comment.getParent();
561 while (root != null && !isBlockStart(root)) {
562 root = root.getParent();
563 }
564
565 final Deque<DetailAST> stack = new ArrayDeque<>();
566 DetailAST previousStatement = null;
567 while (root != null || !stack.isEmpty()) {
568 if (!stack.isEmpty()) {
569 root = stack.pop();
570 }
571 while (root != null) {
572 previousStatement = findPreviousStatement(comment, root);
573 if (previousStatement != null) {
574 root = null;
575 stack.clear();
576 break;
577 }
578 if (root.getNextSibling() != null) {
579 stack.push(root.getNextSibling());
580 }
581 root = root.getFirstChild();
582 }
583 }
584 return previousStatement;
585 }
586
587
588
589
590
591
592 private static boolean isComment(DetailAST ast) {
593 final int astType = ast.getType();
594 return astType == TokenTypes.SINGLE_LINE_COMMENT
595 || astType == TokenTypes.BLOCK_COMMENT_BEGIN
596 || astType == TokenTypes.COMMENT_CONTENT
597 || astType == TokenTypes.BLOCK_COMMENT_END;
598 }
599
600
601
602
603
604
605 private static boolean isBlockStart(DetailAST root) {
606 return root.getType() == TokenTypes.SLIST
607 || root.getType() == TokenTypes.OBJBLOCK
608 || root.getType() == TokenTypes.ARRAY_INIT
609 || root.getType() == TokenTypes.CASE_GROUP;
610 }
611
612
613
614
615
616
617
618
619 private DetailAST findPreviousStatement(DetailAST comment, DetailAST root) {
620 DetailAST previousStatement = null;
621 if (root.getLineNo() >= comment.getLineNo()) {
622
623
624 previousStatement = getPrevStatementFromSwitchBlock(comment);
625 }
626 final DetailAST tokenWhichBeginsTheLine;
627 if (root.getType() == TokenTypes.EXPR
628 && root.getFirstChild().getFirstChild() != null) {
629 if (root.getFirstChild().getType() == TokenTypes.LITERAL_NEW) {
630 tokenWhichBeginsTheLine = root.getFirstChild();
631 }
632 else {
633 tokenWhichBeginsTheLine = findTokenWhichBeginsTheLine(root);
634 }
635 }
636 else if (root.getType() == TokenTypes.PLUS) {
637 tokenWhichBeginsTheLine = root.getFirstChild();
638 }
639 else {
640 tokenWhichBeginsTheLine = root;
641 }
642 if (tokenWhichBeginsTheLine != null
643 && !isComment(tokenWhichBeginsTheLine)
644 && isOnPreviousLineIgnoringComments(comment, tokenWhichBeginsTheLine)) {
645 previousStatement = tokenWhichBeginsTheLine;
646 }
647 return previousStatement;
648 }
649
650
651
652
653
654
655 private static DetailAST findTokenWhichBeginsTheLine(DetailAST root) {
656 final DetailAST tokenWhichBeginsTheLine;
657 if (isUsingOfObjectReferenceToInvokeMethod(root)) {
658 tokenWhichBeginsTheLine = findStartTokenOfMethodCallChain(root);
659 }
660 else {
661 tokenWhichBeginsTheLine = root.getFirstChild().findFirstToken(TokenTypes.IDENT);
662 }
663 return tokenWhichBeginsTheLine;
664 }
665
666
667
668
669
670
671 private static boolean isUsingOfObjectReferenceToInvokeMethod(DetailAST root) {
672 return root.getFirstChild().getFirstChild().getFirstChild() != null
673 && root.getFirstChild().getFirstChild().getFirstChild().getNextSibling() != null;
674 }
675
676
677
678
679
680
681 private static DetailAST findStartTokenOfMethodCallChain(DetailAST root) {
682 DetailAST startOfMethodCallChain = root;
683 while (startOfMethodCallChain.getFirstChild() != null
684 && startOfMethodCallChain.getFirstChild().getLineNo() == root.getLineNo()) {
685 startOfMethodCallChain = startOfMethodCallChain.getFirstChild();
686 }
687 if (startOfMethodCallChain.getFirstChild() != null) {
688 startOfMethodCallChain = startOfMethodCallChain.getFirstChild().getNextSibling();
689 }
690 return startOfMethodCallChain;
691 }
692
693
694
695
696
697
698
699
700
701 private boolean isOnPreviousLineIgnoringComments(DetailAST currentStatement,
702 DetailAST checkedStatement) {
703 DetailAST nextToken = getNextToken(checkedStatement);
704 int distanceAim = 1;
705 if (nextToken != null && isComment(nextToken)) {
706 distanceAim += countEmptyLines(checkedStatement, currentStatement);
707 }
708
709 while (nextToken != null && nextToken != currentStatement && isComment(nextToken)) {
710 if (nextToken.getType() == TokenTypes.BLOCK_COMMENT_BEGIN) {
711 distanceAim += nextToken.getLastChild().getLineNo() - nextToken.getLineNo();
712 }
713 distanceAim++;
714 nextToken = nextToken.getNextSibling();
715 }
716 return currentStatement.getLineNo() - checkedStatement.getLineNo() == distanceAim;
717 }
718
719
720
721
722
723
724 private DetailAST getNextToken(DetailAST checkedStatement) {
725 DetailAST nextToken;
726 if (checkedStatement.getType() == TokenTypes.SLIST
727 || checkedStatement.getType() == TokenTypes.ARRAY_INIT
728 || checkedStatement.getType() == TokenTypes.CASE_GROUP) {
729 nextToken = checkedStatement.getFirstChild();
730 }
731 else {
732 nextToken = checkedStatement.getNextSibling();
733 }
734 if (nextToken != null && isComment(nextToken) && isTrailingComment(nextToken)) {
735 nextToken = nextToken.getNextSibling();
736 }
737 return nextToken;
738 }
739
740
741
742
743
744
745
746 private int countEmptyLines(DetailAST startStatement, DetailAST endStatement) {
747 int emptyLinesNumber = 0;
748 final String[] lines = getLines();
749 final int endLineNo = endStatement.getLineNo();
750 for (int lineNo = startStatement.getLineNo(); lineNo < endLineNo; lineNo++) {
751 if (CommonUtil.isBlank(lines[lineNo])) {
752 emptyLinesNumber++;
753 }
754 }
755 return emptyLinesNumber;
756 }
757
758
759
760
761
762
763
764 private void logMultilineIndentation(DetailAST prevStmt, DetailAST comment,
765 DetailAST nextStmt) {
766 final String multilineNoTemplate = "%d, %d";
767 log(comment.getLineNo(), getMessageKey(comment),
768 String.format(Locale.getDefault(), multilineNoTemplate, prevStmt.getLineNo(),
769 nextStmt.getLineNo()), comment.getColumnNo(),
770 String.format(Locale.getDefault(), multilineNoTemplate,
771 getLineStart(prevStmt.getLineNo()), getLineStart(nextStmt.getLineNo())));
772 }
773
774
775
776
777
778
779 private static String getMessageKey(DetailAST comment) {
780 final String msgKey;
781 if (comment.getType() == TokenTypes.SINGLE_LINE_COMMENT) {
782 msgKey = MSG_KEY_SINGLE;
783 }
784 else {
785 msgKey = MSG_KEY_BLOCK;
786 }
787 return msgKey;
788 }
789
790
791
792
793
794
795 private static DetailAST getPrevStatementFromSwitchBlock(DetailAST comment) {
796 final DetailAST prevStmt;
797 final DetailAST parentStatement = comment.getParent();
798 if (parentStatement.getType() == TokenTypes.CASE_GROUP) {
799 prevStmt = getPrevStatementWhenCommentIsUnderCase(parentStatement);
800 }
801 else {
802 prevStmt = getPrevCaseToken(parentStatement);
803 }
804 return prevStmt;
805 }
806
807
808
809
810
811
812 private static DetailAST getPrevStatementWhenCommentIsUnderCase(DetailAST parentStatement) {
813 DetailAST prevStmt = null;
814 final DetailAST prevBlock = parentStatement.getPreviousSibling();
815 if (prevBlock.getLastChild() != null) {
816 DetailAST blockBody = prevBlock.getLastChild().getLastChild();
817 if (blockBody.getType() == TokenTypes.SEMI) {
818 blockBody = blockBody.getPreviousSibling();
819 }
820 if (blockBody.getType() == TokenTypes.EXPR) {
821 if (isUsingOfObjectReferenceToInvokeMethod(blockBody)) {
822 prevStmt = findStartTokenOfMethodCallChain(blockBody);
823 }
824 else {
825 prevStmt = blockBody.getFirstChild().getFirstChild();
826 }
827 }
828 else {
829 if (blockBody.getType() == TokenTypes.SLIST) {
830 prevStmt = blockBody.getParent().getParent();
831 }
832 else {
833 prevStmt = blockBody;
834 }
835 }
836 if (isComment(prevStmt)) {
837 prevStmt = prevStmt.getNextSibling();
838 }
839 }
840 return prevStmt;
841 }
842
843
844
845
846
847
848 private static DetailAST getPrevCaseToken(DetailAST parentStatement) {
849 final DetailAST prevCaseToken;
850 final DetailAST parentBlock = parentStatement.getParent();
851 if (parentBlock.getParent() != null
852 && parentBlock.getParent().getPreviousSibling() != null
853 && parentBlock.getParent().getPreviousSibling().getType()
854 == TokenTypes.LITERAL_CASE) {
855 prevCaseToken = parentBlock.getParent().getPreviousSibling();
856 }
857 else {
858 prevCaseToken = null;
859 }
860 return prevCaseToken;
861 }
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886 private boolean areSameLevelIndented(DetailAST comment, DetailAST prevStmt,
887 DetailAST nextStmt) {
888 return comment.getColumnNo() == getLineStart(nextStmt.getLineNo())
889 || comment.getColumnNo() == getLineStart(prevStmt.getLineNo());
890 }
891
892
893
894
895
896
897 private int getLineStart(int lineNo) {
898 final char[] line = getLines()[lineNo - 1].toCharArray();
899 int lineStart = 0;
900 while (Character.isWhitespace(line[lineStart])) {
901 lineStart++;
902 }
903 return lineStart;
904 }
905
906
907
908
909
910
911 private boolean isTrailingComment(DetailAST comment) {
912 final boolean isTrailingComment;
913 if (comment.getType() == TokenTypes.SINGLE_LINE_COMMENT) {
914 isTrailingComment = isTrailingSingleLineComment(comment);
915 }
916 else {
917 isTrailingComment = isTrailingBlockComment(comment);
918 }
919 return isTrailingComment;
920 }
921
922
923
924
925
926
927
928
929
930
931
932 private boolean isTrailingSingleLineComment(DetailAST singleLineComment) {
933 final String targetSourceLine = getLine(singleLineComment.getLineNo() - 1);
934 final int commentColumnNo = singleLineComment.getColumnNo();
935 return !CommonUtil.hasWhitespaceBefore(commentColumnNo, targetSourceLine);
936 }
937
938
939
940
941
942
943
944
945
946
947
948
949 private boolean isTrailingBlockComment(DetailAST blockComment) {
950 final String commentLine = getLine(blockComment.getLineNo() - 1);
951 final int commentColumnNo = blockComment.getColumnNo();
952 final DetailAST nextSibling = blockComment.getNextSibling();
953 return !CommonUtil.hasWhitespaceBefore(commentColumnNo, commentLine)
954 || nextSibling != null && nextSibling.getLineNo() == blockComment.getLineNo();
955 }
956
957 }