001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2024 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 allowOneCharVarInForLoop} - Allow one character variable name in 035 * <a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html"> 036 * initialization expressions</a> 037 * in FOR loop if one char variable name is prohibited by {@code format} regexp. 038 * Type is {@code boolean}. 039 * Default value is {@code false}. 040 * </li> 041 * <li> 042 * Property {@code format} - Sets the pattern to match valid identifiers. 043 * Type is {@code java.util.regex.Pattern}. 044 * Default value is {@code "^[a-z][a-zA-Z0-9]*$"}. 045 * </li> 046 * </ul> 047 * <p> 048 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 049 * </p> 050 * <p> 051 * Violation Message Keys: 052 * </p> 053 * <ul> 054 * <li> 055 * {@code name.invalidPattern} 056 * </li> 057 * </ul> 058 * 059 * @since 3.0 060 */ 061public class LocalVariableNameCheck 062 extends AbstractNameCheck { 063 064 /** 065 * Allow one character variable name in 066 * <a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html"> 067 * initialization expressions</a> 068 * in FOR loop if one char variable name is prohibited by {@code format} regexp. 069 */ 070 private boolean allowOneCharVarInForLoop; 071 072 /** Creates a new {@code LocalVariableNameCheck} instance. */ 073 public LocalVariableNameCheck() { 074 super("^[a-z][a-zA-Z0-9]*$"); 075 } 076 077 /** 078 * Setter to allow one character variable name in 079 * <a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html"> 080 * initialization expressions</a> 081 * in FOR loop if one char variable name is prohibited by {@code format} regexp. 082 * 083 * @param allow Flag for allowing or not one character name in FOR loop. 084 * @since 5.8 085 */ 086 public final void setAllowOneCharVarInForLoop(boolean allow) { 087 allowOneCharVarInForLoop = allow; 088 } 089 090 @Override 091 public int[] getDefaultTokens() { 092 return getRequiredTokens(); 093 } 094 095 @Override 096 public int[] getAcceptableTokens() { 097 return getRequiredTokens(); 098 } 099 100 @Override 101 public int[] getRequiredTokens() { 102 return new int[] { 103 TokenTypes.VARIABLE_DEF, 104 }; 105 } 106 107 @Override 108 protected final boolean mustCheckName(DetailAST ast) { 109 final boolean result; 110 if (allowOneCharVarInForLoop && isForLoopVariable(ast)) { 111 final String variableName = ast.findFirstToken(TokenTypes.IDENT).getText(); 112 result = variableName.length() != 1; 113 } 114 else { 115 final DetailAST modifiersAST = ast.findFirstToken(TokenTypes.MODIFIERS); 116 final boolean isFinal = modifiersAST.findFirstToken(TokenTypes.FINAL) != null; 117 result = !isFinal && ScopeUtil.isLocalVariableDef(ast); 118 } 119 return result; 120 } 121 122 /** 123 * Checks if a variable is the loop's one. 124 * 125 * @param variableDef variable definition. 126 * @return true if a variable is the loop's one. 127 */ 128 private static boolean isForLoopVariable(DetailAST variableDef) { 129 final int parentType = variableDef.getParent().getType(); 130 return parentType == TokenTypes.FOR_INIT 131 || parentType == TokenTypes.FOR_EACH_CLAUSE; 132 } 133 134}