View Javadoc
1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2018 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 com.puppycrawl.tools.checkstyle.StatelessCheck;
23  import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
24  import com.puppycrawl.tools.checkstyle.api.DetailAST;
25  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
26  import com.puppycrawl.tools.checkstyle.utils.AnnotationUtility;
27  import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
28  
29  /**
30   * <p>
31   * Checks the number of parameters that a method or constructor has.
32   * The default allowable number of parameters is 7.
33   * To change the number of allowable parameters, set property max.
34   * Allows to ignore number of parameters for methods with
35   * &#064;{@link Override} annotation.
36   * </p>
37   * <p>
38   * An example of how to configure the check is:
39   * </p>
40   * <pre>
41   * &lt;module name="ParameterNumber"/&gt;
42   * </pre>
43   * <p>
44   * An example of how to configure the check to allow 10 parameters
45   * and ignoring parameters for methods with &#064;{@link Override}
46   * annotation is:
47   * </p>
48   * <pre>
49   * &lt;module name="ParameterNumber"&gt;
50   *    &lt;property name="max" value="10"/&gt;
51   *    &lt;property name="ignoreOverriddenMethods" value="true"/&gt;
52   * &lt;/module&gt;
53   * </pre>
54   * Java code that will be ignored:
55   * <pre>
56   * {@code
57   *
58   *  &#064;Override
59   *  public void needsLotsOfParameters(int a,
60   *      int b, int c, int d, int e, int f, int g, int h) {
61   *      ...
62   *  }
63   * }
64   * </pre>
65   * @author Oliver Burn
66   */
67  @StatelessCheck
68  public class ParameterNumberCheck
69      extends AbstractCheck {
70  
71      /**
72       * A key is pointing to the warning message text in "messages.properties"
73       * file.
74       */
75      public static final String MSG_KEY = "maxParam";
76  
77      /** {@link Override Override} annotation name. */
78      private static final String OVERRIDE = "Override";
79  
80      /** Canonical {@link Override Override} annotation name. */
81      private static final String CANONICAL_OVERRIDE = "java.lang." + OVERRIDE;
82  
83      /** Default maximum number of allowed parameters. */
84      private static final int DEFAULT_MAX_PARAMETERS = 7;
85  
86      /** The maximum number of allowed parameters. */
87      private int max = DEFAULT_MAX_PARAMETERS;
88  
89      /** Ignore overridden methods. */
90      private boolean ignoreOverriddenMethods;
91  
92      /**
93       * Sets the maximum number of allowed parameters.
94       * @param max the max allowed parameters
95       */
96      public void setMax(int max) {
97          this.max = max;
98      }
99  
100     /**
101      * Ignore number of parameters for methods with
102      * &#064;{@link Override} annotation.
103      * @param ignoreOverriddenMethods set ignore overridden methods
104      */
105     public void setIgnoreOverriddenMethods(boolean ignoreOverriddenMethods) {
106         this.ignoreOverriddenMethods = ignoreOverriddenMethods;
107     }
108 
109     @Override
110     public int[] getDefaultTokens() {
111         return getAcceptableTokens();
112     }
113 
114     @Override
115     public int[] getAcceptableTokens() {
116         return new int[] {TokenTypes.METHOD_DEF, TokenTypes.CTOR_DEF};
117     }
118 
119     @Override
120     public int[] getRequiredTokens() {
121         return CommonUtils.EMPTY_INT_ARRAY;
122     }
123 
124     @Override
125     public void visitToken(DetailAST ast) {
126         final DetailAST params = ast.findFirstToken(TokenTypes.PARAMETERS);
127         final int count = params.getChildCount(TokenTypes.PARAMETER_DEF);
128         if (count > max && !shouldIgnoreNumberOfParameters(ast)) {
129             final DetailAST name = ast.findFirstToken(TokenTypes.IDENT);
130             log(name.getLineNo(), name.getColumnNo(), MSG_KEY, max, count);
131         }
132     }
133 
134     /** Determine whether to ignore number of parameters for the method.
135      *
136      * @param ast the token to process
137      * @return true if this is overridden method and number of parameters should be ignored
138      *         false otherwise
139      */
140     private boolean shouldIgnoreNumberOfParameters(DetailAST ast) {
141         //if you override a method, you have no power over the number of parameters
142         return ignoreOverriddenMethods
143                 && (AnnotationUtility.containsAnnotation(ast, OVERRIDE)
144                 || AnnotationUtility.containsAnnotation(ast, CANONICAL_OVERRIDE));
145     }
146 
147 }