001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2024 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018/////////////////////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.checks.coding; 021 022import java.util.Objects; 023import java.util.regex.Pattern; 024 025import com.puppycrawl.tools.checkstyle.StatelessCheck; 026import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 027import com.puppycrawl.tools.checkstyle.api.DetailAST; 028import com.puppycrawl.tools.checkstyle.api.TokenTypes; 029import com.puppycrawl.tools.checkstyle.utils.CommonUtil; 030 031/** 032 * <p> 033 * Checks specified tokens text for matching an illegal pattern. 034 * By default, no tokens are specified. 035 * </p> 036 * <ul> 037 * <li> 038 * Property {@code format} - Define the RegExp for illegal pattern. 039 * Type is {@code java.util.regex.Pattern}. 040 * Default value is {@code "^$"}. 041 * </li> 042 * <li> 043 * Property {@code ignoreCase} - Control whether to ignore case when matching. 044 * Type is {@code boolean}. 045 * Default value is {@code false}. 046 * </li> 047 * <li> 048 * Property {@code message} - Define the message which is used to notify about violations; 049 * if empty then the default message is used. 050 * Type is {@code java.lang.String}. 051 * Default value is {@code ""}. 052 * </li> 053 * <li> 054 * Property {@code tokens} - tokens to check 055 * Type is {@code java.lang.String[]}. 056 * Validation type is {@code tokenSet}. 057 * Default value is: {@code ""}. 058 * </li> 059 * </ul> 060 * <p> 061 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 062 * </p> 063 * <p> 064 * Violation Message Keys: 065 * </p> 066 * <ul> 067 * <li> 068 * {@code illegal.token.text} 069 * </li> 070 * </ul> 071 * 072 * @since 3.2 073 */ 074@StatelessCheck 075public class IllegalTokenTextCheck 076 extends AbstractCheck { 077 078 /** 079 * A key is pointing to the warning message text in "messages.properties" 080 * file. 081 */ 082 public static final String MSG_KEY = "illegal.token.text"; 083 084 /** 085 * Define the message which is used to notify about violations; 086 * if empty then the default message is used. 087 */ 088 private String message = ""; 089 090 /** The format string of the regexp. */ 091 private String formatString = "^$"; 092 093 /** Define the RegExp for illegal pattern. */ 094 private Pattern format = Pattern.compile(formatString); 095 096 /** Control whether to ignore case when matching. */ 097 private boolean ignoreCase; 098 099 @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 TokenTypes.STRING_TEMPLATE_CONTENT, 117 }; 118 } 119 120 @Override 121 public int[] getRequiredTokens() { 122 return CommonUtil.EMPTY_INT_ARRAY; 123 } 124 125 @Override 126 public boolean isCommentNodesRequired() { 127 return true; 128 } 129 130 @Override 131 public void visitToken(DetailAST ast) { 132 final String text = ast.getText(); 133 if (format.matcher(text).find()) { 134 String customMessage = message; 135 if (customMessage.isEmpty()) { 136 customMessage = MSG_KEY; 137 } 138 log( 139 ast, 140 customMessage, 141 formatString); 142 } 143 } 144 145 /** 146 * Setter to define the message which is used to notify about violations; 147 * if empty then the default message is used. 148 * 149 * @param message custom message which should be used 150 * to report about violations. 151 * @since 3.2 152 */ 153 public void setMessage(String message) { 154 this.message = Objects.requireNonNullElse(message, ""); 155 } 156 157 /** 158 * Setter to define the RegExp for illegal pattern. 159 * 160 * @param format a {@code String} value 161 * @since 3.2 162 */ 163 public void setFormat(String format) { 164 formatString = format; 165 updateRegexp(); 166 } 167 168 /** 169 * Setter to control whether to ignore case when matching. 170 * 171 * @param caseInsensitive true if the match is case-insensitive. 172 * @since 3.2 173 */ 174 public void setIgnoreCase(boolean caseInsensitive) { 175 ignoreCase = caseInsensitive; 176 updateRegexp(); 177 } 178 179 /** 180 * Updates the {@link #format} based on the values from {@link #formatString} and 181 * {@link #ignoreCase}. 182 */ 183 private void updateRegexp() { 184 final int compileFlags; 185 if (ignoreCase) { 186 compileFlags = Pattern.CASE_INSENSITIVE; 187 } 188 else { 189 compileFlags = 0; 190 } 191 format = CommonUtil.createPattern(formatString, compileFlags); 192 } 193 194}