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.whitespace; 21 22 import java.io.File; 23 24 import com.puppycrawl.tools.checkstyle.StatelessCheck; 25 import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; 26 import com.puppycrawl.tools.checkstyle.api.FileText; 27 28 /** 29 * <div> 30 * Checks that there are no tab characters ({@code '\t'}) in the source code. 31 * </div> 32 * 33 * <p> 34 * Rationale: 35 * </p> 36 * <ul> 37 * <li> 38 * Developers should not need to configure the tab width of their text editors in order 39 * to be able to read source code. 40 * </li> 41 * <li> 42 * From the Apache jakarta coding standards: In a distributed development environment, 43 * when the commit messages get sent to a mailing list, they are almost impossible to 44 * read if you use tabs. 45 * </li> 46 * </ul> 47 * 48 * <p> 49 * Notes: 50 * When the {@code FileTabCharacter} check is used with the default configuration, 51 * only the first instance of a tab character is reported. 52 * </p> 53 * 54 * <ul> 55 * <li> 56 * Property {@code eachLine} - Control whether to report on each line containing a tab, 57 * or just the first instance. 58 * Type is {@code boolean}. 59 * Default value is {@code false}. 60 * </li> 61 * <li> 62 * Property {@code fileExtensions} - Specify the file extensions of the files to process. 63 * Type is {@code java.lang.String[]}. 64 * Default value is {@code ""}. 65 * </li> 66 * </ul> 67 * 68 * <p> 69 * Parent is {@code com.puppycrawl.tools.checkstyle.Checker} 70 * </p> 71 * 72 * <p> 73 * Violation Message Keys: 74 * </p> 75 * <ul> 76 * <li> 77 * {@code containsTab} 78 * </li> 79 * <li> 80 * {@code file.containsTab} 81 * </li> 82 * </ul> 83 * 84 * @since 5.0 85 */ 86 @StatelessCheck 87 public class FileTabCharacterCheck extends AbstractFileSetCheck { 88 89 /** 90 * A key is pointing to the warning message text in "messages.properties" 91 * file. 92 */ 93 public static final String MSG_CONTAINS_TAB = "containsTab"; 94 95 /** 96 * A key is pointing to the warning message text in "messages.properties" 97 * file. 98 */ 99 public static final String MSG_FILE_CONTAINS_TAB = "file.containsTab"; 100 101 /** Control whether to report on each line containing a tab, or just the first instance. */ 102 private boolean eachLine; 103 104 @Override 105 protected void processFiltered(File file, FileText fileText) { 106 int lineNum = 0; 107 for (int index = 0; index < fileText.size(); index++) { 108 final String line = fileText.get(index); 109 lineNum++; 110 final int tabPosition = line.indexOf('\t'); 111 if (tabPosition != -1) { 112 if (eachLine) { 113 log(lineNum, tabPosition, MSG_CONTAINS_TAB); 114 } 115 else { 116 log(lineNum, tabPosition, MSG_FILE_CONTAINS_TAB); 117 break; 118 } 119 } 120 } 121 } 122 123 /** 124 * Setter to control whether to report on each line containing a tab, or just the first 125 * instance. 126 * 127 * @param eachLine Whether report on each line containing a tab. 128 * @since 5.0 129 */ 130 public void setEachLine(boolean eachLine) { 131 this.eachLine = eachLine; 132 } 133 134 }