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