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.regexp; 021 022import java.io.File; 023import java.util.regex.Pattern; 024 025import com.puppycrawl.tools.checkstyle.PropertyType; 026import com.puppycrawl.tools.checkstyle.StatelessCheck; 027import com.puppycrawl.tools.checkstyle.XdocsPropertyType; 028import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; 029import com.puppycrawl.tools.checkstyle.api.FileText; 030 031/** 032 * <div> 033 * Checks that a specified pattern matches across multiple lines in any file type. 034 * </div> 035 * 036 * <p> 037 * Rationale: This check can be used to when the regular expression can be span multiple lines. 038 * </p> 039 * 040 * @since 5.0 041 */ 042@StatelessCheck 043public class RegexpMultilineCheck extends AbstractFileSetCheck { 044 045 /** A key is pointing to the warning message text in "messages.properties" file. */ 046 public static final String MSG_REGEXP_EXCEEDED = "regexp.exceeded"; 047 048 /** A key is pointing to the warning message text in "messages.properties" file. */ 049 public static final String MSG_REGEXP_MINIMUM = "regexp.minimum"; 050 051 /** A key is pointing to the warning message text in "messages.properties" file. */ 052 public static final String MSG_EMPTY = "regexp.empty"; 053 054 /** A key is pointing to the warning message text in "messages.properties" file. */ 055 public static final String MSG_STACKOVERFLOW = "regexp.StackOverflowError"; 056 057 /** Specify the format of the regular expression to match. */ 058 @XdocsPropertyType(PropertyType.PATTERN) 059 private String format = "$."; 060 /** 061 * Specify the message which is used to notify about violations, 062 * if empty then default (hard-coded) message is used. 063 */ 064 private String message; 065 /** Specify the minimum number of matches required in each file. */ 066 private int minimum; 067 /** Specify the maximum number of matches required in each file. */ 068 private int maximum; 069 /** Control whether to ignore case when searching. */ 070 private boolean ignoreCase; 071 /** Control whether to match expressions across multiple lines. */ 072 private boolean matchAcrossLines; 073 074 /** The detector to use. */ 075 private MultilineDetector detector; 076 077 /** 078 * Creates a new {@code RegexpMultilineCheck} instance. 079 */ 080 public RegexpMultilineCheck() { 081 // no code by default 082 } 083 084 @Override 085 public void beginProcessing(String charset) { 086 final DetectorOptions options = DetectorOptions.newBuilder() 087 .reporter(this) 088 .compileFlags(getRegexCompileFlags()) 089 .format(format) 090 .message(message) 091 .minimum(minimum) 092 .maximum(maximum) 093 .ignoreCase(ignoreCase) 094 .build(); 095 detector = new MultilineDetector(options, 096 MSG_REGEXP_EXCEEDED, MSG_REGEXP_MINIMUM, 097 MSG_EMPTY, MSG_STACKOVERFLOW); 098 } 099 100 @Override 101 protected void processFiltered(File file, FileText fileText) { 102 detector.processLines(fileText); 103 } 104 105 /** 106 * Retrieves the compile-flags for the regular expression being built based 107 * on {@code matchAcrossLines}. 108 * 109 * @return The compile-flags. 110 */ 111 private int getRegexCompileFlags() { 112 final int result; 113 114 if (matchAcrossLines) { 115 result = Pattern.DOTALL; 116 } 117 else { 118 result = Pattern.MULTILINE; 119 } 120 121 return result; 122 } 123 124 /** 125 * Setter to specify the format of the regular expression to match. 126 * 127 * @param format the format of the regular expression to match. 128 * @since 5.0 129 */ 130 public void setFormat(String format) { 131 this.format = format; 132 } 133 134 /** 135 * Setter to specify the message which is used to notify about violations, 136 * if empty then default (hard-coded) message is used. 137 * 138 * @param message the message to report for a match. 139 * @since 5.0 140 */ 141 public void setMessage(String message) { 142 this.message = message; 143 } 144 145 /** 146 * Setter to specify the minimum number of matches required in each file. 147 * 148 * @param minimum the minimum number of matches required in each file. 149 * @since 5.0 150 */ 151 public void setMinimum(int minimum) { 152 this.minimum = minimum; 153 } 154 155 /** 156 * Setter to specify the maximum number of matches required in each file. 157 * 158 * @param maximum the maximum number of matches required in each file. 159 * @since 5.0 160 */ 161 public void setMaximum(int maximum) { 162 this.maximum = maximum; 163 } 164 165 /** 166 * Setter to control whether to ignore case when searching. 167 * 168 * @param ignoreCase whether to ignore case when searching. 169 * @since 5.0 170 */ 171 public void setIgnoreCase(boolean ignoreCase) { 172 this.ignoreCase = ignoreCase; 173 } 174 175 /** 176 * Setter to control whether to match expressions across multiple lines. 177 * 178 * @param matchAcrossLines whether to match expressions across multiple lines. 179 * @since 8.25 180 */ 181 public void setMatchAcrossLines(boolean matchAcrossLines) { 182 this.matchAcrossLines = matchAcrossLines; 183 } 184 185}