Repository: checkstyle/checkstyle

Problem statement:
TrailingComment report violation on comment at the begining of line
detected at https://github.com/checkstyle/checkstyle/pull/8711

detected problem:
```
     /*package*/ void setAutoflush(boolean autoflush) {
         this.autoflush = autoflush;
     }
```
There should be no violation on this code 


We need to avoid usage of following code
https://github.com/checkstyle/checkstyle/blob/41769cee1881c8c92cc59762b90b83529406208a/src/main/java/com/puppycrawl/tools/checkstyle/checks/TrailingCommentCheck.java#L191-L195

and use only AST based code, as all content of comments is present in tree.


Hints:
I am on it
I am on it.

Patch:
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/TrailingCommentCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/TrailingCommentCheck.java
--- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/TrailingCommentCheck.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/TrailingCommentCheck.java
@@ -19,19 +19,14 @@
 
 package com.puppycrawl.tools.checkstyle.checks;
 
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
 import java.util.regex.Pattern;
 
 import com.puppycrawl.tools.checkstyle.StatelessCheck;
 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
-import com.puppycrawl.tools.checkstyle.api.TextBlock;
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
+import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
 
 /**
  * <p>
@@ -139,11 +134,8 @@ public class TrailingCommentCheck extends AbstractCheck {
      */
     public static final String MSG_KEY = "trailing.comments";
 
-    /**
-     * A Map contains illegal lines, the key is lineNo, the value is
-     * ColumnNo.
-     */
-    private final Map<Integer, Integer> illegalLines = new HashMap<>();
+    /** Specify pattern for strings to be formatted without comment specifiers. */
+    private static final Pattern FORMAT_LINE = Pattern.compile("/");
 
     /**
      * Define pattern for text allowed in trailing comments.
@@ -200,76 +192,96 @@ public int[] getRequiredTokens() {
 
     @Override
     public void visitToken(DetailAST ast) {
+        if (ast.getType() == TokenTypes.SINGLE_LINE_COMMENT) {
+            checkSingleLineComment(ast);
+        }
+        else {
+            checkBlockComment(ast);
+        }
+    }
+
+    /**
+     * Checks if single line comment is legal.
+     *
+     * @param ast Detail ast element to be checked.
+     */
+    private void checkSingleLineComment(DetailAST ast) {
         final int lineNo = ast.getLineNo();
-        if (illegalLines.get(lineNo) != null
-                && illegalLines.get(lineNo).equals(ast.getColumnNo())) {
+        final String comment = ast.getFirstChild().getText();
+        final String line = getLines()[lineNo - 1];
+        final String lineBefore = line.substring(0, ast.getColumnNo());
+
+        if (!format.matcher(lineBefore).find()
+                && !isLegalSingleLineComment(comment)) {
             log(ast, MSG_KEY);
         }
     }
 
-    @Override
-    public void beginTree(DetailAST rootAST) {
-        final Map<Integer, TextBlock> cppComments = getFileContents()
-                .getSingleLineComments();
-        final Map<Integer, List<TextBlock>> cComments = getFileContents()
-                .getBlockComments();
-        final Set<Integer> lines = new HashSet<>();
-        lines.addAll(cppComments.keySet());
-        lines.addAll(cComments.keySet());
+    /**
+     * Method to check if block comment is in correct format.
+     *
+     * @param ast Detail ast element to be checked.
+     */
+    private void checkBlockComment(DetailAST ast) {
+        final int lineNo = ast.getLineNo();
+        final String comment = ast.getFirstChild().getText();
+        String line = getLines()[lineNo - 1];
+
+        if (line.length() > ast.getLastChild().getColumnNo() + 1) {
+            line = line.substring(ast.getLastChild().getColumnNo() + 2);
+        }
+
+        line = FORMAT_LINE.matcher(line).replaceAll("");
 
-        for (Integer lineNo : lines) {
-            final String line = getLines()[lineNo - 1];
-            final String lineBefore;
-            final TextBlock comment;
-            if (cppComments.containsKey(lineNo)) {
-                comment = cppComments.get(lineNo);
-                lineBefore = line.substring(0, comment.getStartColNo());
-            }
-            else {
-                final List<TextBlock> commentList = cComments.get(lineNo);
-                comment = commentList.get(commentList.size() - 1);
-                lineBefore = line.substring(0, comment.getStartColNo());
+        final String lineBefore = getLines()[lineNo - 1].substring(0, ast.getColumnNo());
 
-                // do not check comment which doesn't end line
-                if (comment.getText().length == 1
-                        && !CommonUtil.isBlank(line
-                            .substring(comment.getEndColNo() + 1))) {
-                    continue;
-                }
-            }
-            if (!format.matcher(lineBefore).find()
-                && !isLegalComment(comment)) {
-                illegalLines.put(lineNo, comment.getStartColNo());
-            }
+        // do not check comment which doesn't end line
+        if ((ast.getLineNo() != ast.getLastChild().getLineNo() || CommonUtil.isBlank(line))
+                && !format.matcher(lineBefore).find()
+                && !isLegalBlockComment(ast, comment)) {
+            log(ast, MSG_KEY);
         }
     }
 
     /**
-     * Checks if given comment is legal (single-line and matches to the
-     * pattern).
+     * Checks if block comment is legal and matches to the pattern.
      *
+     * @param ast Detail ast element to be checked.
      * @param comment comment to check.
      * @return true if the comment if legal.
      */
-    private boolean isLegalComment(final TextBlock comment) {
+    private boolean isLegalBlockComment(DetailAST ast, String comment) {
         final boolean legal;
 
         // multi-line comment can not be legal
-        if (legalComment == null || comment.getStartLineNo() != comment.getEndLineNo()) {
+        if (legalComment == null
+                || !TokenUtil.areOnSameLine(ast.getFirstChild(), ast.getLastChild())) {
             legal = false;
         }
         else {
-            String commentText = comment.getText()[0];
-            // remove chars which start comment
-            commentText = commentText.substring(2);
-            // if this is a C-style comment we need to remove its end
-            if (commentText.endsWith("*/")) {
-                commentText = commentText.substring(0, commentText.length() - 2);
-            }
-            commentText = commentText.trim();
+            final String commentText = comment.trim();
             legal = legalComment.matcher(commentText).find();
         }
         return legal;
     }
 
+    /**
+     * Checks if given single line comment is legal (single-line and matches to the
+     * pattern).
+     *
+     * @param comment comment to check.
+     * @return true if the comment if legal.
+     */
+    private boolean isLegalSingleLineComment(String comment) {
+        final boolean legal;
+        if (legalComment == null) {
+            legal = false;
+        }
+        else {
+            // remove chars which start comment
+            final String commentText = comment.substring(1).trim();
+            legal = legalComment.matcher(commentText).find();
+        }
+        return legal;
+    }
 }


Test patch:
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/TrailingCommentCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/TrailingCommentCheckTest.java
--- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/TrailingCommentCheckTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/TrailingCommentCheckTest.java
@@ -103,8 +103,10 @@ public void testFormat() throws Exception {
             "29:50: " + getCheckMessage(MSG_KEY),
             "30:51: " + getCheckMessage(MSG_KEY),
             "31:31: " + getCheckMessage(MSG_KEY),
+            "34:9: " + getCheckMessage(MSG_KEY),
+            "35:9: " + getCheckMessage(MSG_KEY),
+            "43:5: " + getCheckMessage(MSG_KEY),
         };
         verify(checkConfig, getPath("InputTrailingComment.java"), expected);
     }
-
 }
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/trailingcomment/InputTrailingComment.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/trailingcomment/InputTrailingComment.java
--- a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/trailingcomment/InputTrailingComment.java
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/trailingcomment/InputTrailingComment.java
@@ -18,16 +18,31 @@ public void run() {
     /* c-style */ // cpp-style
     /* c-style 1 */ /*c-style 2 */
 
-    void method2(long ms /* we should ignore this */) {
+    /* package */ void method2(long ms /* we should ignore this */) {
         /* comment before text */int z;
         /* int y */int y/**/;
     }
 
     /**
-     * comment with trailing space
+     * comment with trailing space.
      */
     final static public String NAME="Some Name"; // NOI18N
     final static public String NAME2="Some Name"; /*NOI18N*/
     String NAME3="Some Name"; /*NOI18N
 */
+    /* package */ void method3() {
+        /* violation on this block */
+        // violation here for format NOT FOUND
+    }
+
+    private static class TimerEntry {
+        /* ok */ final String operation = null;
+        /* ok */ final long start = 0L;
+    }
+
+    /**
+     * violation above this line.
+     **/
+    /* package */ void addError() {
+    }
 }