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