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}