001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2026 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 * <div> 033 * Checks specified tokens text for matching an illegal pattern. 034 * By default, no tokens are specified. 035 * </div> 036 * 037 * @since 3.2 038 */ 039@StatelessCheck 040public class IllegalTokenTextCheck 041 extends AbstractCheck { 042 043 /** 044 * A key is pointing to the warning message text in "messages.properties" 045 * file. 046 */ 047 public static final String MSG_KEY = "illegal.token.text"; 048 049 /** 050 * Define the message which is used to notify about violations; 051 * if empty then the default message is used. 052 */ 053 private String message = ""; 054 055 /** The format string of the regexp. */ 056 private String formatString = "^$"; 057 058 /** Define the RegExp for illegal pattern. */ 059 private Pattern format = Pattern.compile(formatString); 060 061 /** Control whether to ignore case when matching. */ 062 private boolean ignoreCase; 063 064 /** 065 * Creates a new {@code IllegalTokenTextCheck} instance. 066 */ 067 public IllegalTokenTextCheck() { 068 // no code by default 069 } 070 071 @Override 072 public int[] getDefaultTokens() { 073 return CommonUtil.EMPTY_INT_ARRAY; 074 } 075 076 @Override 077 public int[] getAcceptableTokens() { 078 return new int[] { 079 TokenTypes.NUM_DOUBLE, 080 TokenTypes.NUM_FLOAT, 081 TokenTypes.NUM_INT, 082 TokenTypes.NUM_LONG, 083 TokenTypes.IDENT, 084 TokenTypes.COMMENT_CONTENT, 085 TokenTypes.STRING_LITERAL, 086 TokenTypes.CHAR_LITERAL, 087 TokenTypes.TEXT_BLOCK_CONTENT, 088 }; 089 } 090 091 @Override 092 public int[] getRequiredTokens() { 093 return CommonUtil.EMPTY_INT_ARRAY; 094 } 095 096 @Override 097 public boolean isCommentNodesRequired() { 098 return true; 099 } 100 101 @Override 102 public void visitToken(DetailAST ast) { 103 final String text = ast.getText(); 104 if (format.matcher(text).find()) { 105 String customMessage = message; 106 if (customMessage.isEmpty()) { 107 customMessage = MSG_KEY; 108 } 109 log( 110 ast, 111 customMessage, 112 formatString); 113 } 114 } 115 116 /** 117 * Setter to define the message which is used to notify about violations; 118 * if empty then the default message is used. 119 * 120 * @param message custom message which should be used 121 * to report about violations. 122 * @since 3.2 123 */ 124 public void setMessage(String message) { 125 this.message = Objects.requireNonNullElse(message, ""); 126 } 127 128 /** 129 * Setter to define the RegExp for illegal pattern. 130 * 131 * @param format a {@code String} value 132 * @since 3.2 133 */ 134 public void setFormat(String format) { 135 formatString = format; 136 updateRegexp(); 137 } 138 139 /** 140 * Setter to control whether to ignore case when matching. 141 * 142 * @param caseInsensitive true if the match is case-insensitive. 143 * @since 3.2 144 */ 145 public void setIgnoreCase(boolean caseInsensitive) { 146 ignoreCase = caseInsensitive; 147 updateRegexp(); 148 } 149 150 /** 151 * Updates the {@link #format} based on the values from {@link #formatString} and 152 * {@link #ignoreCase}. 153 */ 154 private void updateRegexp() { 155 final int compileFlags; 156 if (ignoreCase) { 157 compileFlags = Pattern.CASE_INSENSITIVE; 158 } 159 else { 160 compileFlags = 0; 161 } 162 format = CommonUtil.createPattern(formatString, compileFlags); 163 } 164 165}