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