1 ///////////////////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3 // Copyright (C) 2001-2026 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.sizes;
21
22 import java.util.Set;
23
24 import com.puppycrawl.tools.checkstyle.StatelessCheck;
25 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
26 import com.puppycrawl.tools.checkstyle.api.DetailAST;
27 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
28 import com.puppycrawl.tools.checkstyle.utils.AnnotationUtil;
29 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
30
31 /**
32 * <div>
33 * Checks the number of parameters of a method or constructor.
34 * </div>
35 *
36 * @since 3.0
37 */
38 @StatelessCheck
39 public class ParameterNumberCheck
40 extends AbstractCheck {
41
42 /**
43 * A key is pointing to the warning message text in "messages.properties"
44 * file.
45 */
46 public static final String MSG_KEY = "maxParam";
47
48 /** Default maximum number of allowed parameters. */
49 private static final int DEFAULT_MAX_PARAMETERS = 7;
50
51 /** Specify the maximum number of parameters allowed. */
52 private int max = DEFAULT_MAX_PARAMETERS;
53
54 /** Ignore number of parameters for methods with {@code @Override} annotation. */
55 private boolean ignoreOverriddenMethods;
56
57 /**
58 * Ignore methods and constructors annotated with the specified annotation(s).
59 */
60 private Set<String> ignoreAnnotatedBy = Set.of();
61
62 /**
63 * Creates a new {@code ParameterNumberCheck} instance.
64 */
65 public ParameterNumberCheck() {
66 // no code by default
67 }
68
69 /**
70 * Setter to specify the maximum number of parameters allowed.
71 *
72 * @param max the max allowed parameters
73 * @since 3.0
74 */
75 public void setMax(int max) {
76 this.max = max;
77 }
78
79 /**
80 * Setter to ignore number of parameters for methods with {@code @Override} annotation.
81 *
82 * @param ignoreOverriddenMethods set ignore overridden methods
83 * @since 6.2
84 */
85 public void setIgnoreOverriddenMethods(boolean ignoreOverriddenMethods) {
86 this.ignoreOverriddenMethods = ignoreOverriddenMethods;
87 }
88
89 /**
90 * Setter to ignore methods and constructors annotated with the specified annotation(s).
91 *
92 * @param annotationNames specified annotation(s)
93 * @since 10.15.0
94 */
95 public void setIgnoreAnnotatedBy(String... annotationNames) {
96 ignoreAnnotatedBy = Set.of(annotationNames);
97 }
98
99 @Override
100 public int[] getDefaultTokens() {
101 return getAcceptableTokens();
102 }
103
104 @Override
105 public int[] getAcceptableTokens() {
106 return new int[] {TokenTypes.METHOD_DEF, TokenTypes.CTOR_DEF};
107 }
108
109 @Override
110 public int[] getRequiredTokens() {
111 return CommonUtil.EMPTY_INT_ARRAY;
112 }
113
114 @Override
115 public void visitToken(DetailAST ast) {
116 final DetailAST params = ast.findFirstToken(TokenTypes.PARAMETERS);
117 final int count = params.getChildCount(TokenTypes.PARAMETER_DEF);
118 if (count > max && !shouldIgnoreNumberOfParameters(ast)) {
119 final DetailAST name = ast.findFirstToken(TokenTypes.IDENT);
120 log(name, MSG_KEY, max, count);
121 }
122 }
123
124 /**
125 * Determine whether to ignore number of parameters.
126 *
127 * @param ast the token to process
128 * @return true if number of parameters should be ignored.
129 */
130 private boolean shouldIgnoreNumberOfParameters(DetailAST ast) {
131 return isIgnoredOverriddenMethod(ast) || isAnnotatedByIgnoredAnnotations(ast);
132 }
133
134 /**
135 * Checks if method is overridden and should be ignored.
136 *
137 * @param ast method definition to check
138 * @return true if method is overridden and should be ignored.
139 */
140 private boolean isIgnoredOverriddenMethod(DetailAST ast) {
141 return ignoreOverriddenMethods && AnnotationUtil.hasOverrideAnnotation(ast);
142 }
143
144 /**
145 * Checks if method or constructor is annotated by ignored annotation(s).
146 *
147 * @param ast method or constructor definition to check
148 * @return true if annotated by ignored annotation(s).
149 */
150 private boolean isAnnotatedByIgnoredAnnotations(DetailAST ast) {
151 return AnnotationUtil.containsAnnotation(ast, ignoreAnnotatedBy);
152 }
153
154 }