001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2015 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.regex.Pattern; 023 024import org.apache.commons.lang3.ArrayUtils; 025 026import com.puppycrawl.tools.checkstyle.api.Check; 027import com.puppycrawl.tools.checkstyle.api.DetailAST; 028import com.puppycrawl.tools.checkstyle.utils.CommonUtils; 029import com.puppycrawl.tools.checkstyle.utils.TokenUtils; 030 031/** 032 * <p> 033 * Checks for illegal token text. 034 * </p> 035 * <p> An example of how to configure the check to forbid String literals 036 * containing {@code "a href"} is: 037 * </p> 038 * <pre> 039 * <module name="IllegalTokenText"> 040 * <property name="tokens" value="STRING_LITERAL"/> 041 * <property name="format" value="a href"/> 042 * </module> 043 * </pre> 044 * <p> An example of how to configure the check to forbid leading zeros in an 045 * integer literal, other than zero and a hex literal is: 046 * </p> 047 * <pre> 048 * <module name="IllegalTokenText"> 049 * <property name="tokens" value="NUM_INT,NUM_LONG"/> 050 * <property name="format" value="^0[^lx]"/> 051 * <property name="ignoreCase" value="true"/> 052 * </module> 053 * </pre> 054 * @author Rick Giles 055 */ 056public class IllegalTokenTextCheck 057 extends Check { 058 059 /** 060 * A key is pointing to the warning message text in "messages.properties" 061 * file. 062 */ 063 public static final String MSG_KEY = "illegal.token.text"; 064 065 /** 066 * Custom message for report if illegal regexp found 067 * ignored if empty. 068 */ 069 private String message = ""; 070 071 /** The format string of the regexp. */ 072 private String format = "$^"; 073 074 /** The regexp to match against. */ 075 private Pattern regexp = Pattern.compile(format); 076 077 /** The flags to use with the regexp. */ 078 private int compileFlags; 079 080 @Override 081 public int[] getDefaultTokens() { 082 return ArrayUtils.EMPTY_INT_ARRAY; 083 } 084 085 @Override 086 public int[] getAcceptableTokens() { 087 return TokenUtils.getAllTokenIds(); 088 } 089 090 @Override 091 public int[] getRequiredTokens() { 092 return ArrayUtils.EMPTY_INT_ARRAY; 093 } 094 095 @Override 096 public void visitToken(DetailAST ast) { 097 final String text = ast.getText(); 098 if (regexp.matcher(text).find()) { 099 String customMessage = message; 100 if (customMessage.isEmpty()) { 101 customMessage = MSG_KEY; 102 } 103 log( 104 ast.getLineNo(), 105 ast.getColumnNo(), 106 customMessage, 107 format); 108 } 109 } 110 111 /** 112 * Setter for message property. 113 * @param message custom message which should be used 114 * to report about violations. 115 */ 116 public void setMessage(String message) { 117 if (message == null) { 118 this.message = ""; 119 } 120 else { 121 this.message = message; 122 } 123 } 124 125 /** 126 * Set the format to the specified regular expression. 127 * @param format a {@code String} value 128 * @throws org.apache.commons.beanutils.ConversionException unable to parse format 129 */ 130 public void setFormat(String format) { 131 this.format = format; 132 updateRegexp(); 133 } 134 135 /** 136 * Set whether or not the match is case sensitive. 137 * @param caseInsensitive true if the match is case insensitive. 138 */ 139 public void setIgnoreCase(boolean caseInsensitive) { 140 if (caseInsensitive) { 141 compileFlags = Pattern.CASE_INSENSITIVE; 142 } 143 else { 144 compileFlags = 0; 145 } 146 147 updateRegexp(); 148 } 149 150 /** 151 * Updates the {@link #regexp} based on the values from {@link #format} and 152 * {@link #compileFlags}. 153 */ 154 private void updateRegexp() { 155 regexp = CommonUtils.createPattern(format, compileFlags); 156 } 157}