View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ///////////////////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.checks.coding;
21  
22  import java.util.Objects;
23  import java.util.regex.Pattern;
24  
25  import com.puppycrawl.tools.checkstyle.StatelessCheck;
26  import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
27  import com.puppycrawl.tools.checkstyle.api.DetailAST;
28  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
29  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
30  
31  /**
32   * <p>
33   * Checks specified tokens text for matching an illegal pattern.
34   * By default, no tokens are specified.
35   * </p>
36   * <ul>
37   * <li>
38   * Property {@code format} - Define the RegExp for illegal pattern.
39   * Type is {@code java.util.regex.Pattern}.
40   * Default value is {@code "^$"}.
41   * </li>
42   * <li>
43   * Property {@code ignoreCase} - Control whether to ignore case when matching.
44   * Type is {@code boolean}.
45   * Default value is {@code false}.
46   * </li>
47   * <li>
48   * Property {@code message} - Define the message which is used to notify about violations;
49   * if empty then the default message is used.
50   * Type is {@code java.lang.String}.
51   * Default value is {@code ""}.
52   * </li>
53   * <li>
54   * Property {@code tokens} - tokens to check
55   * Type is {@code java.lang.String[]}.
56   * Validation type is {@code tokenSet}.
57   * Default value is: {@code ""}.
58   * </li>
59   * </ul>
60   * <p>
61   * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
62   * </p>
63   * <p>
64   * Violation Message Keys:
65   * </p>
66   * <ul>
67   * <li>
68   * {@code illegal.token.text}
69   * </li>
70   * </ul>
71   *
72   * @since 3.2
73   */
74  @StatelessCheck
75  public class IllegalTokenTextCheck
76      extends AbstractCheck {
77  
78      /**
79       * A key is pointing to the warning message text in "messages.properties"
80       * file.
81       */
82      public static final String MSG_KEY = "illegal.token.text";
83  
84      /**
85       * Define the message which is used to notify about violations;
86       * if empty then the default message is used.
87       */
88      private String message = "";
89  
90      /** The format string of the regexp. */
91      private String formatString = "^$";
92  
93      /** Define the RegExp for illegal pattern. */
94      private Pattern format = Pattern.compile(formatString);
95  
96      /** Control whether to ignore case when matching. */
97      private boolean ignoreCase;
98  
99      @Override
100     public int[] getDefaultTokens() {
101         return CommonUtil.EMPTY_INT_ARRAY;
102     }
103 
104     @Override
105     public int[] getAcceptableTokens() {
106         return new int[] {
107             TokenTypes.NUM_DOUBLE,
108             TokenTypes.NUM_FLOAT,
109             TokenTypes.NUM_INT,
110             TokenTypes.NUM_LONG,
111             TokenTypes.IDENT,
112             TokenTypes.COMMENT_CONTENT,
113             TokenTypes.STRING_LITERAL,
114             TokenTypes.CHAR_LITERAL,
115             TokenTypes.TEXT_BLOCK_CONTENT,
116         };
117     }
118 
119     @Override
120     public int[] getRequiredTokens() {
121         return CommonUtil.EMPTY_INT_ARRAY;
122     }
123 
124     @Override
125     public boolean isCommentNodesRequired() {
126         return true;
127     }
128 
129     @Override
130     public void visitToken(DetailAST ast) {
131         final String text = ast.getText();
132         if (format.matcher(text).find()) {
133             String customMessage = message;
134             if (customMessage.isEmpty()) {
135                 customMessage = MSG_KEY;
136             }
137             log(
138                 ast,
139                 customMessage,
140                 formatString);
141         }
142     }
143 
144     /**
145      * Setter to define the message which is used to notify about violations;
146      * if empty then the default message is used.
147      *
148      * @param message custom message which should be used
149      *                 to report about violations.
150      * @since 3.2
151      */
152     public void setMessage(String message) {
153         this.message = Objects.requireNonNullElse(message, "");
154     }
155 
156     /**
157      * Setter to define the RegExp for illegal pattern.
158      *
159      * @param format a {@code String} value
160      * @since 3.2
161      */
162     public void setFormat(String format) {
163         formatString = format;
164         updateRegexp();
165     }
166 
167     /**
168      * Setter to control whether to ignore case when matching.
169      *
170      * @param caseInsensitive true if the match is case-insensitive.
171      * @since 3.2
172      */
173     public void setIgnoreCase(boolean caseInsensitive) {
174         ignoreCase = caseInsensitive;
175         updateRegexp();
176     }
177 
178     /**
179      * Updates the {@link #format} based on the values from {@link #formatString} and
180      * {@link #ignoreCase}.
181      */
182     private void updateRegexp() {
183         final int compileFlags;
184         if (ignoreCase) {
185             compileFlags = Pattern.CASE_INSENSITIVE;
186         }
187         else {
188             compileFlags = 0;
189         }
190         format = CommonUtil.createPattern(formatString, compileFlags);
191     }
192 
193 }