View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.qulice.checkstyle;
6   
7   import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
8   import com.puppycrawl.tools.checkstyle.api.DetailAST;
9   import com.puppycrawl.tools.checkstyle.api.TokenTypes;
10  import java.util.regex.Matcher;
11  import java.util.regex.Pattern;
12  
13  /**
14   * C++ style inline comment is not allowed.
15   * Use //-style comment instead.
16   * @since 0.18
17   */
18  public final class SingleLineCommentCheck extends AbstractCheck {
19  
20      /**
21       * Pattern that matches an empty string only.
22       */
23      private static final Pattern EMPTY = Pattern.compile("^$");
24  
25      /**
26       * Pattern for check.
27       * It is not final as it is initialized from the configuration.
28       */
29      private Pattern format;
30  
31      /**
32       * The message to report for a match.
33       * It is not final as it is initialized from the configuration.
34       */
35      private String message;
36  
37      /**
38       * Comment line.
39       * It is not final because the visitToken method is called many times
40       * during the class under test and the field is reinitialized with a new object.
41       */
42      @SuppressWarnings("PMD.AvoidStringBufferField")
43      private final StringBuilder line;
44  
45      /**
46       * When inside a block comment, holds begin line number.
47       */
48      private int begin;
49  
50      /**
51       * Default constructor.
52       */
53      public SingleLineCommentCheck() {
54          this.format = SingleLineCommentCheck.EMPTY;
55          this.message = "";
56          this.line = new StringBuilder();
57      }
58  
59      @Override
60      public boolean isCommentNodesRequired() {
61          return true;
62      }
63  
64      @Override
65      public int[] getDefaultTokens() {
66          return new int[]{
67              TokenTypes.BLOCK_COMMENT_BEGIN,
68              TokenTypes.COMMENT_CONTENT,
69              TokenTypes.BLOCK_COMMENT_END,
70          };
71      }
72  
73      @Override
74      public int[] getAcceptableTokens() {
75          return this.getDefaultTokens();
76      }
77  
78      @Override
79      public int[] getRequiredTokens() {
80          return this.getDefaultTokens();
81      }
82  
83      @Override
84      public void visitToken(final DetailAST ast) {
85          if (ast.getType() == TokenTypes.BLOCK_COMMENT_BEGIN) {
86              this.line.setLength(0);
87              this.line.append(ast.getText());
88              this.begin = ast.getLineNo();
89          } else if (ast.getType() == TokenTypes.COMMENT_CONTENT) {
90              this.line.append(ast.getText());
91          } else {
92              this.line.append(ast.getText());
93              final Matcher matcher = this.format.matcher(this.line.toString());
94              if (matcher.matches() && this.singleLineCStyleComment(ast)) {
95                  this.log(ast, this.message);
96              }
97          }
98      }
99  
100     /**
101      * The method is called from checkstyle to configure this class.
102      * The parameter is set from the checks.xml file
103      * {@code <module name="com.qulice.checkstyle.SingleLineCommentCheck"/>} and
104      * {@code <property name="format" value=" this regexp "/>} property
105      * @param fmt Validatig regexp
106      */
107     public void setFormat(final String fmt) {
108         this.format = Pattern.compile(fmt);
109     }
110 
111     /**
112      * The method is called from checkstyle to configure this class.
113      * The parameter is set from the checks.xml file
114      * {@code <module name="com.qulice.checkstyle.SingleLineCommentCheck"/>} and
115      * {@code <property name="message" value="This comment is not allowed."/>}
116      * property
117      * @param msg Error message
118      */
119     public void setMessage(final String msg) {
120         this.message = msg;
121     }
122 
123     /**
124      * Checks for the end of a comment line.
125      * @param ast Checkstyle's AST nodes
126      * @return True if this is the end of the comment
127      *  and the starting line number is equal to the ending line number
128      */
129     private boolean singleLineCStyleComment(final DetailAST ast) {
130         return ast.getType() == TokenTypes.BLOCK_COMMENT_END && this.begin == ast.getLineNo();
131     }
132 }