View Javadoc
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.naming;
21  
22  import java.util.Arrays;
23  import java.util.Optional;
24  
25  import com.puppycrawl.tools.checkstyle.api.DetailAST;
26  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
27  import com.puppycrawl.tools.checkstyle.utils.CheckUtil;
28  
29  /**
30   * <div>
31   * Checks that method parameter names conform to a specified pattern.
32   * By using {@code accessModifiers} property it is possible
33   * to specify different formats for methods at different visibility levels.
34   * </div>
35   *
36   * <p>
37   * To validate {@code catch} parameters please use
38   * <a href="https://checkstyle.org/checks/naming/catchparametername.html">
39   * CatchParameterName</a>.
40   * </p>
41   *
42   * <p>
43   * To validate lambda parameters please use
44   * <a href="https://checkstyle.org/checks/naming/lambdaparametername.html">
45   * LambdaParameterName</a>.
46   * </p>
47   *
48   * @since 3.0
49   */
50  public class ParameterNameCheck extends AbstractNameCheck {
51  
52      /**
53       * Allows to skip methods with Override annotation from validation.
54       */
55      private boolean ignoreOverridden;
56  
57      /** Access modifiers of methods where parameters are checked. */
58      private AccessModifierOption[] accessModifiers = {
59          AccessModifierOption.PUBLIC,
60          AccessModifierOption.PROTECTED,
61          AccessModifierOption.PACKAGE,
62          AccessModifierOption.PRIVATE,
63      };
64  
65      /**
66       * Creates a new {@code ParameterNameCheck} instance.
67       */
68      public ParameterNameCheck() {
69          super("^[a-z][a-zA-Z0-9]*$");
70      }
71  
72      /**
73       * Setter to allows to skip methods with Override annotation from validation.
74       *
75       * @param ignoreOverridden Flag for skipping methods with Override annotation.
76       * @since 6.12.1
77       */
78      public void setIgnoreOverridden(boolean ignoreOverridden) {
79          this.ignoreOverridden = ignoreOverridden;
80      }
81  
82      /**
83       * Setter to access modifiers of methods where parameters are checked.
84       *
85       * @param accessModifiers access modifiers of methods which should be checked.
86       * @since 7.5
87       */
88      public void setAccessModifiers(AccessModifierOption... accessModifiers) {
89          this.accessModifiers =
90              Arrays.copyOf(accessModifiers, accessModifiers.length);
91      }
92  
93      @Override
94      public int[] getDefaultTokens() {
95          return getRequiredTokens();
96      }
97  
98      @Override
99      public int[] getAcceptableTokens() {
100         return getRequiredTokens();
101     }
102 
103     @Override
104     public int[] getRequiredTokens() {
105         return new int[] {TokenTypes.PARAMETER_DEF};
106     }
107 
108     @Override
109     protected boolean mustCheckName(DetailAST ast) {
110         boolean checkName = true;
111         final DetailAST parent = ast.getParent();
112         if (ignoreOverridden && isOverriddenMethod(ast)
113                 || parent.getType() == TokenTypes.LITERAL_CATCH
114                 || parent.getParent().getType() == TokenTypes.LAMBDA
115                 || CheckUtil.isReceiverParameter(ast)
116                 || !matchAccessModifiers(
117                         CheckUtil.getAccessModifierFromModifiersToken(parent.getParent()))) {
118             checkName = false;
119         }
120         return checkName;
121     }
122 
123     /**
124      * Checks whether a method has the correct access modifier to be checked.
125      *
126      * @param accessModifier the access modifier of the method.
127      * @return whether the method matches the expected access modifier.
128      */
129     private boolean matchAccessModifiers(final AccessModifierOption accessModifier) {
130         return Arrays.stream(accessModifiers)
131                 .anyMatch(modifier -> modifier == accessModifier);
132     }
133 
134     /**
135      * Checks whether a method is annotated with Override annotation.
136      *
137      * @param ast method parameter definition token.
138      * @return true if a method is annotated with Override annotation.
139      */
140     private static boolean isOverriddenMethod(DetailAST ast) {
141         boolean overridden = false;
142 
143         final DetailAST parent = ast.getParent().getParent();
144         final Optional<DetailAST> annotation =
145             Optional.ofNullable(parent.getFirstChild().getFirstChild());
146 
147         if (annotation.isPresent()) {
148             final Optional<DetailAST> overrideToken =
149                 Optional.ofNullable(annotation.orElseThrow().findFirstToken(TokenTypes.IDENT));
150             if (overrideToken.isPresent()
151                 && "Override".equals(overrideToken.orElseThrow().getText())) {
152                 overridden = true;
153             }
154         }
155         return overridden;
156     }
157 
158 }