001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2020 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.naming; 021 022import com.puppycrawl.tools.checkstyle.api.DetailAST; 023import com.puppycrawl.tools.checkstyle.api.TokenTypes; 024import com.puppycrawl.tools.checkstyle.utils.ScopeUtil; 025 026/** 027 * <p> 028 * Checks that local, non-{@code final} variable names conform to a specified pattern. 029 * A catch parameter is considered to be 030 * a local variable. 031 * </p> 032 * <ul> 033 * <li> 034 * Property {@code format} - Specifies valid identifiers. 035 * Type is {@code java.util.regex.Pattern}. 036 * Default value is {@code "^[a-z][a-zA-Z0-9]*$"}. 037 * </li> 038 * <li> 039 * Property {@code allowOneCharVarInForLoop} - Allow one character variable name in 040 * <a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html"> 041 * initialization expressions</a> 042 * in FOR loop if one char variable name is prohibited by {@code format} regexp. 043 * Type is {@code boolean}. 044 * Default value is {@code false}. 045 * </li> 046 * </ul> 047 * <p> 048 * To configure the check: 049 * </p> 050 * <pre> 051 * <module name="LocalVariableName"/> 052 * </pre> 053 * <p>Code Example:</p> 054 * <pre> 055 * class MyClass { 056 * void MyMethod() { 057 * for (int var = 1; var < 10; var++) {} // OK 058 * for (int VAR = 1; VAR < 10; VAR++) {} // violation, name 'VAR' must match 059 * // pattern '^[a-z][a-zA-Z0-9]*$' 060 * for (int i = 1; i < 10; i++) {} // OK 061 * for (int var_1 = 0; var_1 < 10; var_1++) {} // violation, name 'var_1' must match 062 * // pattern '^[a-z][a-zA-Z0-9]*$' 063 * } 064 * } 065 * </pre> 066 * <p> 067 * An example of how to configure the check for names that begin with a lower 068 * case letter, followed by letters, digits, and underscores is: 069 * </p> 070 * <pre> 071 * <module name="LocalVariableName"> 072 * <property name="format" value="^[a-z](_?[a-zA-Z0-9]+)*$"/> 073 * </module> 074 * </pre> 075 * <p>Code Example:</p> 076 * <pre> 077 * class MyClass { 078 * void MyMethod() { 079 * for (int var = 1; var < 10; var++) {} // OK 080 * for (int VAR = 1; VAR < 10; VAR++) {} // violation, name 'VAR' must match 081 * // pattern '^[a-z](_?[a-zA-Z0-9]+)*$' 082 * for (int i = 1; i < 10; i++) {} // OK 083 * for (int var_1 = 0; var_1 < 10; var_1++) {} // OK 084 * } 085 * } 086 * </pre> 087 * <p> 088 * An example of one character variable name in 089 * initialization expression(like "i") in FOR loop: 090 * </p> 091 * <pre> 092 * for(int i = 1; i < 10; i++) {} 093 * for(int K = 1; K < 10; K++) {} 094 * List list = new ArrayList(); 095 * for (Object o : list) {} 096 * for (Object O : list) {} 097 * </pre> 098 * <p> 099 * An example of how to configure the check to allow one character variable name in 100 * <a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html"> 101 * initialization expressions</a> in FOR loop, where regexp allows 2 or more chars: 102 * </p> 103 * <pre> 104 * <module name="LocalVariableName"> 105 * <property name="format" value="^[a-z][_a-zA-Z0-9]+$"/> 106 * <property name="allowOneCharVarInForLoop" value="true"/> 107 * </module> 108 * </pre> 109 * <p>Code Example:</p> 110 * <pre> 111 * class MyClass { 112 * void MyMethod() { 113 * int good = 1; 114 * int g = 0; // violation 115 * for (int v = 1; v < 10; v++) { // OK 116 * int a = 1; // violation 117 * } 118 * for (int V = 1; V < 10; V++) { // OK 119 * int I = 1; // violation 120 * } 121 * List list = new ArrayList(); 122 * for (Object o : list) { // OK 123 * String a = ""; // violation 124 * } 125 * for (Object O : list) { // OK 126 * String A = ""; // violation 127 * } 128 * } 129 * } 130 * </pre> 131 * <p> 132 * An example of how to configure the check to that all variables have 3 or more chars in name: 133 * </p> 134 * <pre> 135 * <module name="LocalVariableName"> 136 * <property name="format" value="^[a-z][_a-zA-Z0-9]{2,}$"/> 137 * </module> 138 * </pre> 139 * <p>Code Example:</p> 140 * <pre> 141 * class MyClass { 142 * void MyMethod() { 143 * int goodName = 0; 144 * int i = 1; // violation 145 * for (int var = 1; var < 10; var++) { //OK 146 * int j = 1; // violation 147 * } 148 * } 149 * } 150 * </pre> 151 * <p> 152 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 153 * </p> 154 * <p> 155 * Violation Message Keys: 156 * </p> 157 * <ul> 158 * <li> 159 * {@code name.invalidPattern} 160 * </li> 161 * </ul> 162 * 163 * @since 3.0 164 */ 165public class LocalVariableNameCheck 166 extends AbstractNameCheck { 167 168 /** 169 * Allow one character variable name in 170 * <a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html"> 171 * initialization expressions</a> 172 * in FOR loop if one char variable name is prohibited by {@code format} regexp. 173 */ 174 private boolean allowOneCharVarInForLoop; 175 176 /** Creates a new {@code LocalVariableNameCheck} instance. */ 177 public LocalVariableNameCheck() { 178 super("^[a-z][a-zA-Z0-9]*$"); 179 } 180 181 /** 182 * Setter to allow one character variable name in 183 * <a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html"> 184 * initialization expressions</a> 185 * in FOR loop if one char variable name is prohibited by {@code format} regexp. 186 * 187 * @param allow Flag for allowing or not one character name in FOR loop. 188 */ 189 public final void setAllowOneCharVarInForLoop(boolean allow) { 190 allowOneCharVarInForLoop = allow; 191 } 192 193 @Override 194 public int[] getDefaultTokens() { 195 return getRequiredTokens(); 196 } 197 198 @Override 199 public int[] getAcceptableTokens() { 200 return getRequiredTokens(); 201 } 202 203 @Override 204 public int[] getRequiredTokens() { 205 return new int[] { 206 TokenTypes.VARIABLE_DEF, 207 }; 208 } 209 210 @Override 211 protected final boolean mustCheckName(DetailAST ast) { 212 final boolean result; 213 if (allowOneCharVarInForLoop && isForLoopVariable(ast)) { 214 final String variableName = ast.findFirstToken(TokenTypes.IDENT).getText(); 215 result = variableName.length() != 1; 216 } 217 else { 218 final DetailAST modifiersAST = ast.findFirstToken(TokenTypes.MODIFIERS); 219 final boolean isFinal = modifiersAST.findFirstToken(TokenTypes.FINAL) != null; 220 result = !isFinal && ScopeUtil.isLocalVariableDef(ast); 221 } 222 return result; 223 } 224 225 /** 226 * Checks if a variable is the loop's one. 227 * 228 * @param variableDef variable definition. 229 * @return true if a variable is the loop's one. 230 */ 231 private static boolean isForLoopVariable(DetailAST variableDef) { 232 final int parentType = variableDef.getParent().getType(); 233 return parentType == TokenTypes.FOR_INIT 234 || parentType == TokenTypes.FOR_EACH_CLAUSE; 235 } 236 237}