Coverage Report - com.puppycrawl.tools.checkstyle.checks.coding.ParameterAssignmentCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
ParameterAssignmentCheck
100%
51/51
100%
21/21
4.75
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2017 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.coding;
 21  
 
 22  
 import java.util.ArrayDeque;
 23  
 import java.util.Collections;
 24  
 import java.util.Deque;
 25  
 import java.util.HashSet;
 26  
 import java.util.Set;
 27  
 
 28  
 import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
 29  
 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
 30  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 31  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 32  
 import com.puppycrawl.tools.checkstyle.utils.CheckUtils;
 33  
 
 34  
 /**
 35  
  * <p>
 36  
  * Disallow assignment of parameters.
 37  
  * </p>
 38  
  * <p>
 39  
  * Rationale:
 40  
  * Parameter assignment is often considered poor
 41  
  * programming practice. Forcing developers to declare
 42  
  * parameters as final is often onerous. Having a check
 43  
  * ensure that parameters are never assigned would give
 44  
  * the best of both worlds.
 45  
  * </p>
 46  
  * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a>
 47  
  */
 48  
 @FileStatefulCheck
 49  12
 public final class ParameterAssignmentCheck extends AbstractCheck {
 50  
 
 51  
     /**
 52  
      * A key is pointing to the warning message text in "messages.properties"
 53  
      * file.
 54  
      */
 55  
     public static final String MSG_KEY = "parameter.assignment";
 56  
 
 57  
     /** Stack of methods' parameters. */
 58  12
     private final Deque<Set<String>> parameterNamesStack = new ArrayDeque<>();
 59  
     /** Current set of parameters. */
 60  
     private Set<String> parameterNames;
 61  
 
 62  
     @Override
 63  
     public int[] getDefaultTokens() {
 64  13
         return getRequiredTokens();
 65  
     }
 66  
 
 67  
     @Override
 68  
     public int[] getRequiredTokens() {
 69  31
         return new int[] {
 70  
             TokenTypes.CTOR_DEF,
 71  
             TokenTypes.METHOD_DEF,
 72  
             TokenTypes.ASSIGN,
 73  
             TokenTypes.PLUS_ASSIGN,
 74  
             TokenTypes.MINUS_ASSIGN,
 75  
             TokenTypes.STAR_ASSIGN,
 76  
             TokenTypes.DIV_ASSIGN,
 77  
             TokenTypes.MOD_ASSIGN,
 78  
             TokenTypes.SR_ASSIGN,
 79  
             TokenTypes.BSR_ASSIGN,
 80  
             TokenTypes.SL_ASSIGN,
 81  
             TokenTypes.BAND_ASSIGN,
 82  
             TokenTypes.BXOR_ASSIGN,
 83  
             TokenTypes.BOR_ASSIGN,
 84  
             TokenTypes.INC,
 85  
             TokenTypes.POST_INC,
 86  
             TokenTypes.DEC,
 87  
             TokenTypes.POST_DEC,
 88  
         };
 89  
     }
 90  
 
 91  
     @Override
 92  
     public int[] getAcceptableTokens() {
 93  5
         return getRequiredTokens();
 94  
     }
 95  
 
 96  
     @Override
 97  
     public void beginTree(DetailAST rootAST) {
 98  
         // clear data
 99  5
         parameterNamesStack.clear();
 100  5
         parameterNames = Collections.emptySet();
 101  5
     }
 102  
 
 103  
     @Override
 104  
     public void visitToken(DetailAST ast) {
 105  23
         switch (ast.getType()) {
 106  
             case TokenTypes.CTOR_DEF:
 107  
             case TokenTypes.METHOD_DEF:
 108  9
                 visitMethodDef(ast);
 109  9
                 break;
 110  
             case TokenTypes.ASSIGN:
 111  
             case TokenTypes.PLUS_ASSIGN:
 112  
             case TokenTypes.MINUS_ASSIGN:
 113  
             case TokenTypes.STAR_ASSIGN:
 114  
             case TokenTypes.DIV_ASSIGN:
 115  
             case TokenTypes.MOD_ASSIGN:
 116  
             case TokenTypes.SR_ASSIGN:
 117  
             case TokenTypes.BSR_ASSIGN:
 118  
             case TokenTypes.SL_ASSIGN:
 119  
             case TokenTypes.BAND_ASSIGN:
 120  
             case TokenTypes.BXOR_ASSIGN:
 121  
             case TokenTypes.BOR_ASSIGN:
 122  10
                 visitAssign(ast);
 123  10
                 break;
 124  
             case TokenTypes.INC:
 125  
             case TokenTypes.POST_INC:
 126  
             case TokenTypes.DEC:
 127  
             case TokenTypes.POST_DEC:
 128  3
                 visitIncDec(ast);
 129  3
                 break;
 130  
             default:
 131  1
                 throw new IllegalStateException(ast.toString());
 132  
         }
 133  22
     }
 134  
 
 135  
     @Override
 136  
     public void leaveToken(DetailAST ast) {
 137  22
         switch (ast.getType()) {
 138  
             case TokenTypes.CTOR_DEF:
 139  
             case TokenTypes.METHOD_DEF:
 140  8
                 leaveMethodDef();
 141  8
                 break;
 142  
             case TokenTypes.ASSIGN:
 143  
             case TokenTypes.PLUS_ASSIGN:
 144  
             case TokenTypes.MINUS_ASSIGN:
 145  
             case TokenTypes.STAR_ASSIGN:
 146  
             case TokenTypes.DIV_ASSIGN:
 147  
             case TokenTypes.MOD_ASSIGN:
 148  
             case TokenTypes.SR_ASSIGN:
 149  
             case TokenTypes.BSR_ASSIGN:
 150  
             case TokenTypes.SL_ASSIGN:
 151  
             case TokenTypes.BAND_ASSIGN:
 152  
             case TokenTypes.BXOR_ASSIGN:
 153  
             case TokenTypes.BOR_ASSIGN:
 154  
             case TokenTypes.INC:
 155  
             case TokenTypes.POST_INC:
 156  
             case TokenTypes.DEC:
 157  
             case TokenTypes.POST_DEC:
 158  
                 // Do nothing
 159  13
                 break;
 160  
             default:
 161  1
                 throw new IllegalStateException(ast.toString());
 162  
         }
 163  21
     }
 164  
 
 165  
     /**
 166  
      * Checks if this is assignments of parameter.
 167  
      * @param ast assignment to check.
 168  
      */
 169  
     private void visitAssign(DetailAST ast) {
 170  10
         checkIdent(ast);
 171  10
     }
 172  
 
 173  
     /**
 174  
      * Checks if this is increment/decrement of parameter.
 175  
      * @param ast dec/inc to check.
 176  
      */
 177  
     private void visitIncDec(DetailAST ast) {
 178  3
         checkIdent(ast);
 179  3
     }
 180  
 
 181  
     /**
 182  
      * Check if ident is parameter.
 183  
      * @param ast ident to check.
 184  
      */
 185  
     private void checkIdent(DetailAST ast) {
 186  13
         if (!parameterNames.isEmpty()) {
 187  10
             final DetailAST identAST = ast.getFirstChild();
 188  
 
 189  10
             if (identAST != null
 190  9
                 && identAST.getType() == TokenTypes.IDENT
 191  5
                 && parameterNames.contains(identAST.getText())) {
 192  8
                 log(ast.getLineNo(), ast.getColumnNo(),
 193  4
                     MSG_KEY, identAST.getText());
 194  
             }
 195  
         }
 196  13
     }
 197  
 
 198  
     /**
 199  
      * Creates new set of parameters and store old one in stack.
 200  
      * @param ast a method to process.
 201  
      */
 202  
     private void visitMethodDef(DetailAST ast) {
 203  9
         parameterNamesStack.push(parameterNames);
 204  9
         parameterNames = new HashSet<>();
 205  
 
 206  9
         visitMethodParameters(ast.findFirstToken(TokenTypes.PARAMETERS));
 207  9
     }
 208  
 
 209  
     /** Restores old set of parameters. */
 210  
     private void leaveMethodDef() {
 211  8
         parameterNames = parameterNamesStack.pop();
 212  8
     }
 213  
 
 214  
     /**
 215  
      * Creates new parameter set for given method.
 216  
      * @param ast a method for process.
 217  
      */
 218  
     private void visitMethodParameters(DetailAST ast) {
 219  9
         DetailAST parameterDefAST =
 220  9
             ast.findFirstToken(TokenTypes.PARAMETER_DEF);
 221  
 
 222  18
         while (parameterDefAST != null) {
 223  9
             if (parameterDefAST.getType() == TokenTypes.PARAMETER_DEF
 224  8
                     && !CheckUtils.isReceiverParameter(parameterDefAST)) {
 225  5
                 final DetailAST param =
 226  5
                     parameterDefAST.findFirstToken(TokenTypes.IDENT);
 227  5
                 parameterNames.add(param.getText());
 228  
             }
 229  9
             parameterDefAST = parameterDefAST.getNextSibling();
 230  
         }
 231  9
     }
 232  
 }