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; 025 026/** 027 * A detector that matches individual lines. 028 */ 029public class SinglelineDetector { 030 031 /** The detection options to use. */ 032 private final DetectorOptions options; 033 /** The message key for exceeded matches. */ 034 private final String exceededMessage; 035 /** The message key for minimum matches not met. */ 036 private final String minimumMessage; 037 /** Tracks the number of matches. */ 038 private int currentMatches; 039 040 /** 041 * Creates an instance. 042 * 043 * @param options the options to use. 044 * @param exceededMessage the message key for exceeded matches. 045 * @param minimumMessage the message key for minimum matches not met. 046 */ 047 /* package */ SinglelineDetector(DetectorOptions options, 048 String exceededMessage, String minimumMessage) { 049 this.options = options; 050 this.exceededMessage = exceededMessage; 051 this.minimumMessage = minimumMessage; 052 } 053 054 /** 055 * Processes a set of lines looking for matches. 056 * 057 * @param fileText {@link FileText} object contains the lines to process. 058 */ 059 public void processLines(FileText fileText) { 060 currentMatches = 0; 061 int lineNo = 0; 062 for (int index = 0; index < fileText.size(); index++) { 063 final String line = fileText.get(index); 064 lineNo++; 065 checkLine(lineNo, options.getPattern().matcher(line)); 066 } 067 finish(); 068 } 069 070 /** 071 * Perform processing at the end of a set of lines. 072 */ 073 private void finish() { 074 if (currentMatches < options.getMinimum()) { 075 if (options.getMessage().isEmpty()) { 076 options.getReporter().log(1, minimumMessage, 077 options.getMinimum(), options.getFormat()); 078 } 079 else { 080 options.getReporter().log(1, options.getMessage()); 081 } 082 } 083 } 084 085 /** 086 * Check a line for matches. 087 * 088 * @param lineNo the line number of the line to check 089 * @param matcher the matcher to use 090 */ 091 private void checkLine(int lineNo, Matcher matcher) { 092 int startPosition = 0; 093 while (matcher.find(startPosition)) { 094 // match is found, check for intersection with comment 095 final int startCol = matcher.start(0); 096 final int endCol = matcher.end(0); 097 // Note that Matcher.end(int) returns the offset AFTER the 098 // last matched character, but shouldSuppress() 099 // needs column number of the last character. 100 // So we need to use (endCol - 1) here. 101 102 if (options.getSuppressor() 103 .shouldSuppress(lineNo, startCol, lineNo, endCol - 1)) { 104 startPosition = endCol; 105 } 106 else { 107 currentMatches++; 108 if (currentMatches > options.getMaximum()) { 109 if (options.getMessage().isEmpty()) { 110 options.getReporter().log(lineNo, exceededMessage, 111 matcher.pattern().toString()); 112 } 113 else { 114 options.getReporter().log(lineNo, options.getMessage()); 115 } 116 } 117 break; 118 } 119 } 120 } 121 122}