View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2025 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ///////////////////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.checks.regexp;
21  
22  import java.io.File;
23  import java.util.regex.Pattern;
24  
25  import com.puppycrawl.tools.checkstyle.PropertyType;
26  import com.puppycrawl.tools.checkstyle.StatelessCheck;
27  import com.puppycrawl.tools.checkstyle.XdocsPropertyType;
28  import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
29  import com.puppycrawl.tools.checkstyle.api.FileText;
30  
31  /**
32   * <div>
33   * Checks that a specified pattern matches across multiple lines in any file type.
34   * </div>
35   *
36   * <p>
37   * Rationale: This check can be used to when the regular expression can be span multiple lines.
38   * </p>
39   *
40   * @since 5.0
41   */
42  @StatelessCheck
43  public class RegexpMultilineCheck extends AbstractFileSetCheck {
44  
45      /** Specify the format of the regular expression to match. */
46      @XdocsPropertyType(PropertyType.PATTERN)
47      private String format = "$.";
48      /**
49       * Specify the message which is used to notify about violations,
50       * if empty then default (hard-coded) message is used.
51       */
52      private String message;
53      /** Specify the minimum number of matches required in each file. */
54      private int minimum;
55      /** Specify the maximum number of matches required in each file. */
56      private int maximum;
57      /** Control whether to ignore case when searching. */
58      private boolean ignoreCase;
59      /** Control whether to match expressions across multiple lines. */
60      private boolean matchAcrossLines;
61  
62      /** The detector to use. */
63      private MultilineDetector detector;
64  
65      @Override
66      public void beginProcessing(String charset) {
67          final DetectorOptions options = DetectorOptions.newBuilder()
68              .reporter(this)
69              .compileFlags(getRegexCompileFlags())
70              .format(format)
71              .message(message)
72              .minimum(minimum)
73              .maximum(maximum)
74              .ignoreCase(ignoreCase)
75              .build();
76          detector = new MultilineDetector(options);
77      }
78  
79      @Override
80      protected void processFiltered(File file, FileText fileText) {
81          detector.processLines(fileText);
82      }
83  
84      /**
85       * Retrieves the compile-flags for the regular expression being built based
86       * on {@code matchAcrossLines}.
87       *
88       * @return The compile-flags.
89       */
90      private int getRegexCompileFlags() {
91          final int result;
92  
93          if (matchAcrossLines) {
94              result = Pattern.DOTALL;
95          }
96          else {
97              result = Pattern.MULTILINE;
98          }
99  
100         return result;
101     }
102 
103     /**
104      * Setter to specify the format of the regular expression to match.
105      *
106      * @param format the format of the regular expression to match.
107      * @since 5.0
108      */
109     public void setFormat(String format) {
110         this.format = format;
111     }
112 
113     /**
114      * Setter to specify the message which is used to notify about violations,
115      * if empty then default (hard-coded) message is used.
116      *
117      * @param message the message to report for a match.
118      * @since 5.0
119      */
120     public void setMessage(String message) {
121         this.message = message;
122     }
123 
124     /**
125      * Setter to specify the minimum number of matches required in each file.
126      *
127      * @param minimum the minimum number of matches required in each file.
128      * @since 5.0
129      */
130     public void setMinimum(int minimum) {
131         this.minimum = minimum;
132     }
133 
134     /**
135      * Setter to specify the maximum number of matches required in each file.
136      *
137      * @param maximum the maximum number of matches required in each file.
138      * @since 5.0
139      */
140     public void setMaximum(int maximum) {
141         this.maximum = maximum;
142     }
143 
144     /**
145      * Setter to control whether to ignore case when searching.
146      *
147      * @param ignoreCase whether to ignore case when searching.
148      * @since 5.0
149      */
150     public void setIgnoreCase(boolean ignoreCase) {
151         this.ignoreCase = ignoreCase;
152     }
153 
154     /**
155      * Setter to control whether to match expressions across multiple lines.
156      *
157      * @param matchAcrossLines whether to match expressions across multiple lines.
158      * @since 8.25
159      */
160     public void setMatchAcrossLines(boolean matchAcrossLines) {
161         this.matchAcrossLines = matchAcrossLines;
162     }
163 
164 }