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.util.regex.Matcher; 023 024import com.puppycrawl.tools.checkstyle.api.FileText; 025import com.puppycrawl.tools.checkstyle.api.LineColumn; 026 027/** 028 * A detector that matches across multiple lines. 029 */ 030public class MultilineDetector { 031 032 /** The detection options to use. */ 033 private final DetectorOptions options; 034 /** The message key for exceeded matches. */ 035 private final String exceededMessage; 036 /** The message key for minimum matches not met. */ 037 private final String minimumMessage; 038 /** The message key for empty format. */ 039 private final String emptyMessage; 040 /** The message key for StackOverflow error. */ 041 private final String stackOverflowMessage; 042 /** Tracks the number of matches. */ 043 private int currentMatches; 044 /** The matcher. */ 045 private Matcher matcher; 046 /** The file text content. */ 047 private FileText text; 048 049 /** 050 * Creates an instance. 051 * 052 * @param options the options to use. 053 * @param exceededMessage the message key for exceeded matches. 054 * @param minimumMessage the message key for minimum matches not met. 055 * @param emptyMessage the message key for empty format. 056 * @param stackOverflowMessage the message key for StackOverflow error. 057 */ 058 /* package */ MultilineDetector(DetectorOptions options, 059 String exceededMessage, String minimumMessage, 060 String emptyMessage, String stackOverflowMessage) { 061 this.options = options; 062 this.exceededMessage = exceededMessage; 063 this.minimumMessage = minimumMessage; 064 this.emptyMessage = emptyMessage; 065 this.stackOverflowMessage = stackOverflowMessage; 066 } 067 068 /** 069 * Processes an entire text file looking for matches. 070 * 071 * @param fileText the text to process 072 */ 073 public void processLines(FileText fileText) { 074 text = new FileText(fileText); 075 resetState(); 076 077 final String format = options.getFormat(); 078 if (format == null || format.isEmpty()) { 079 options.getReporter().log(1, emptyMessage); 080 } 081 else { 082 matcher = options.getPattern().matcher(fileText.getFullText()); 083 findMatch(); 084 finish(); 085 } 086 } 087 088 /** Method that finds the matches. */ 089 private void findMatch() { 090 try { 091 boolean foundMatch = matcher.find(); 092 093 while (foundMatch) { 094 currentMatches++; 095 if (currentMatches > options.getMaximum()) { 096 final LineColumn start = text.lineColumn(matcher.start()); 097 if (options.getMessage().isEmpty()) { 098 options.getReporter().log(start.getLine(), 099 exceededMessage, 100 matcher.pattern().toString()); 101 } 102 else { 103 options.getReporter() 104 .log(start.getLine(), options.getMessage()); 105 } 106 } 107 foundMatch = matcher.find(); 108 } 109 } 110 // see http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6337993 et al. 111 catch (StackOverflowError ignored) { 112 // ok http://blog.igorminar.com/2008/05/catching-stackoverflowerror-and-bug-in.html 113 // http://programmers.stackexchange.com/questions/ 114 // 209099/is-it-ever-okay-to-catch-stackoverflowerror-in-java 115 options.getReporter().log(1, stackOverflowMessage, 116 matcher.pattern().toString()); 117 } 118 } 119 120 /** Perform processing at the end of a set of lines. */ 121 private void finish() { 122 if (currentMatches < options.getMinimum()) { 123 if (options.getMessage().isEmpty()) { 124 options.getReporter().log(1, minimumMessage, 125 options.getMinimum(), options.getFormat()); 126 } 127 else { 128 options.getReporter().log(1, options.getMessage()); 129 } 130 } 131 } 132 133 /** 134 * Reset the state of the detector. 135 */ 136 private void resetState() { 137 currentMatches = 0; 138 } 139 140}