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 }