001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2023 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.regexp; 021 022import java.io.File; 023 024import com.puppycrawl.tools.checkstyle.PropertyType; 025import com.puppycrawl.tools.checkstyle.StatelessCheck; 026import com.puppycrawl.tools.checkstyle.XdocsPropertyType; 027import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; 028import com.puppycrawl.tools.checkstyle.api.FileText; 029 030/** 031 * <p> 032 * Checks that a specified pattern matches a single-line in any file type. 033 * </p> 034 * <p> 035 * Rationale: This check can be used to prototype checks and to find common bad 036 * practice such as calling {@code ex.printStacktrace()}, 037 * {@code System.out.println()}, {@code System.exit()}, etc. 038 * </p> 039 * <ul> 040 * <li> 041 * Property {@code format} - Specify the format of the regular expression to match. 042 * Type is {@code java.util.regex.Pattern}. 043 * Default value is {@code "$."}. 044 * </li> 045 * <li> 046 * Property {@code message} - Specify the message which is used to notify about 047 * violations, if empty then default (hard-coded) message is used. 048 * Type is {@code java.lang.String}. 049 * Default value is {@code null}. 050 * </li> 051 * <li> 052 * Property {@code ignoreCase} - Control whether to ignore case when searching. 053 * Type is {@code boolean}. 054 * Default value is {@code false}. 055 * </li> 056 * <li> 057 * Property {@code minimum} - Specify the minimum number of matches required in each file. 058 * Type is {@code int}. 059 * Default value is {@code 0}. 060 * </li> 061 * <li> 062 * Property {@code maximum} - Specify the maximum number of matches required in each file. 063 * Type is {@code int}. 064 * Default value is {@code 0}. 065 * </li> 066 * <li> 067 * Property {@code fileExtensions} - Specify the file type extension of files to process. 068 * Type is {@code java.lang.String[]}. 069 * Default value is {@code ""}. 070 * </li> 071 * </ul> 072 * <p> 073 * To configure the default check: 074 * </p> 075 * <pre> 076 * <module name="RegexpSingleline" /> 077 * </pre> 078 * <p> 079 * This configuration does not match to anything, 080 * so we do not provide any code example for it 081 * as no violation will ever be reported. 082 * </p> 083 * <p> 084 * To configure the check to find occurrences of 'System.exit(' 085 * with some <i>slack</i> of allowing only one occurrence per file: 086 * </p> 087 * <pre> 088 * <module name="RegexpSingleline"> 089 * <property name="format" value="System.exit\("/> 090 * <!-- next line not required as 0 is the default --> 091 * <property name="minimum" value="0"/> 092 * <property name="maximum" value="1"/> 093 * </module> 094 * </pre> 095 * <p>Example:</p> 096 * <pre> 097 * class MyClass { 098 * void myFunction() { 099 * try { 100 * doSomething(); 101 * } catch (Exception e) { 102 * System.exit(1); // OK, as only there is only one occurrence. 103 * } 104 * } 105 * void doSomething(){}; 106 * } 107 * </pre> 108 * <pre> 109 * class MyClass { 110 * void myFunction() { 111 * try { 112 * doSomething(); 113 * System.exit(0); 114 * } catch (Exception e) { 115 * System.exit(1); // Violation, as there are more than one occurrence. 116 * } 117 * } 118 * void doSomething(){}; 119 * } 120 * </pre> 121 * <p> 122 * An example of how to configure the check to make sure a copyright statement 123 * is included in the file: 124 * </p> 125 * <pre> 126 * <module name="RegexpSingleline"> 127 * <property name="format" value="This file is copyrighted"/> 128 * <property name="minimum" value="1"/> 129 * <!-- Need to specify a maximum, so 10 times is more than enough. --> 130 * <property name="maximum" value="10"/> 131 * </module> 132 * </pre> 133 * <p>Example:</p> 134 * <pre> 135 * /** 136 * * This file is copyrighted under CC. // Ok, as the file contains a copyright statement. 137 * */ 138 * class MyClass { 139 * 140 * } 141 * </pre> 142 * <pre> 143 * /** // violation, as the file doesn't contain a copyright statement. 144 * * MyClass as a configuration example. 145 * */ 146 * class MyClass { 147 * 148 * } 149 * </pre> 150 * <p> 151 * An example of how to configure the check to make sure sql files contains the term 'license'. 152 * </p> 153 * <pre> 154 * <module name="RegexpSingleline"> 155 * <property name="format" value="license"/> 156 * <property name="minimum" value="1"/> 157 * <property name="maximum" value="9999"/> 158 * <property name="ignoreCase" value="true"/> 159 * <!-- Configure a message to be shown on violation of the Check. --> 160 * <property name="message" 161 * value="File must contain at least one occurrence of 'license' term"/> 162* <!-- Perform the Check only on files with java extension. --> 163 * <property name="fileExtensions" value="sql"/> 164 * </module> 165 * </pre> 166 * <p>Example:</p> 167 * <pre> 168 * /* 169 * AP 2.0 License. // Ok, Check ignores the case of the term. 170 * */ 171 * CREATE DATABASE MyDB; 172 * </pre> 173 * <pre> 174 * /* // violation, file doesn't contain the term. 175 * Example sql file. 176 * */ 177 * CREATE DATABASE MyDB; 178 * </pre> 179 * <p> 180 * Parent is {@code com.puppycrawl.tools.checkstyle.Checker} 181 * </p> 182 * <p> 183 * Violation Message Keys: 184 * </p> 185 * <ul> 186 * <li> 187 * {@code regexp.exceeded} 188 * </li> 189 * <li> 190 * {@code regexp.minimum} 191 * </li> 192 * </ul> 193 * 194 * @since 5.0 195 */ 196@StatelessCheck 197public class RegexpSinglelineCheck extends AbstractFileSetCheck { 198 199 /** Specify the format of the regular expression to match. */ 200 @XdocsPropertyType(PropertyType.PATTERN) 201 private String format = "$."; 202 /** 203 * Specify the message which is used to notify about violations, 204 * if empty then default (hard-coded) message is used. 205 */ 206 private String message; 207 /** Specify the minimum number of matches required in each file. */ 208 private int minimum; 209 /** Specify the maximum number of matches required in each file. */ 210 private int maximum; 211 /** Control whether to ignore case when searching. */ 212 private boolean ignoreCase; 213 214 /** The detector to use. */ 215 private SinglelineDetector detector; 216 217 @Override 218 public void beginProcessing(String charset) { 219 final DetectorOptions options = DetectorOptions.newBuilder() 220 .reporter(this) 221 .compileFlags(0) 222 .format(format) 223 .message(message) 224 .minimum(minimum) 225 .maximum(maximum) 226 .ignoreCase(ignoreCase) 227 .build(); 228 detector = new SinglelineDetector(options); 229 } 230 231 @Override 232 protected void processFiltered(File file, FileText fileText) { 233 detector.processLines(fileText); 234 } 235 236 /** 237 * Setter to specify the format of the regular expression to match. 238 * 239 * @param format the format of the regular expression to match. 240 */ 241 public void setFormat(String format) { 242 this.format = format; 243 } 244 245 /** 246 * Setter to specify the message which is used to notify about violations, 247 * if empty then default (hard-coded) message is used. 248 * 249 * @param message the message to report for a match. 250 */ 251 public void setMessage(String message) { 252 this.message = message; 253 } 254 255 /** 256 * Setter to specify the minimum number of matches required in each file. 257 * 258 * @param minimum the minimum number of matches required in each file. 259 */ 260 public void setMinimum(int minimum) { 261 this.minimum = minimum; 262 } 263 264 /** 265 * Setter to specify the maximum number of matches required in each file. 266 * 267 * @param maximum the maximum number of matches required in each file. 268 */ 269 public void setMaximum(int maximum) { 270 this.maximum = maximum; 271 } 272 273 /** 274 * Setter to control whether to ignore case when searching. 275 * 276 * @param ignoreCase whether to ignore case when searching. 277 */ 278 public void setIgnoreCase(boolean ignoreCase) { 279 this.ignoreCase = ignoreCase; 280 } 281 282}