Coverage Report - com.puppycrawl.tools.checkstyle.checks.coding.FinalLocalVariableCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
FinalLocalVariableCheck
97%
41/42
63%
46/73
6.625
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2014  Oliver Burn
 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  
 package com.puppycrawl.tools.checkstyle.checks.coding;
 20  
 
 21  
 import com.puppycrawl.tools.checkstyle.api.Check;
 22  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 23  
 import com.puppycrawl.tools.checkstyle.api.FastStack;
 24  
 import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
 25  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 26  
 import java.util.HashMap;
 27  
 import java.util.Map;
 28  
 
 29  
 /**
 30  
  * <p>
 31  
  * Ensures that local variables that never get their values changed,
 32  
  * must be declared final.
 33  
  * </p>
 34  
  * <p>
 35  
  * An example of how to configure the check is:
 36  
  * </p>
 37  
  * <pre>
 38  
  * &lt;module name="FinalLocalVariable"&gt;
 39  
  *     &lt;property name="token" value="VARIABLE_DEF"/&gt;
 40  
  * &lt;/module&gt;
 41  
  * </pre>
 42  
  * @author k_gibbs, r_auckenthaler
 43  
  */
 44  2
 public class FinalLocalVariableCheck extends Check
 45  
 {
 46  
     /** Scope Stack */
 47  2
     private final FastStack<Map<String, DetailAST>> mScopeStack =
 48  
         FastStack.newInstance();
 49  
 
 50  
     @Override
 51  
     public int[] getDefaultTokens()
 52  
     {
 53  1
         return new int[] {
 54  
             TokenTypes.IDENT,
 55  
             TokenTypes.CTOR_DEF,
 56  
             TokenTypes.METHOD_DEF,
 57  
             TokenTypes.VARIABLE_DEF,
 58  
             TokenTypes.INSTANCE_INIT,
 59  
             TokenTypes.STATIC_INIT,
 60  
             TokenTypes.LITERAL_FOR,
 61  
             TokenTypes.SLIST,
 62  
             TokenTypes.OBJBLOCK,
 63  
         };
 64  
     }
 65  
 
 66  
     @Override
 67  
     public int[] getAcceptableTokens()
 68  
     {
 69  1
         return new int[] {
 70  
             TokenTypes.VARIABLE_DEF,
 71  
             TokenTypes.PARAMETER_DEF,
 72  
         };
 73  
     }
 74  
 
 75  
     @Override
 76  
     public int[] getRequiredTokens()
 77  
     {
 78  1
         return new int[] {
 79  
             TokenTypes.IDENT,
 80  
             TokenTypes.CTOR_DEF,
 81  
             TokenTypes.METHOD_DEF,
 82  
             TokenTypes.INSTANCE_INIT,
 83  
             TokenTypes.STATIC_INIT,
 84  
             TokenTypes.LITERAL_FOR,
 85  
             TokenTypes.SLIST,
 86  
             TokenTypes.OBJBLOCK,
 87  
         };
 88  
     }
 89  
 
 90  
     @Override
 91  
     public void visitToken(DetailAST aAST)
 92  
     {
 93  346
         switch(aAST.getType()) {
 94  
         case TokenTypes.OBJBLOCK:
 95  
         case TokenTypes.SLIST:
 96  
         case TokenTypes.LITERAL_FOR:
 97  
         case TokenTypes.METHOD_DEF:
 98  
         case TokenTypes.CTOR_DEF:
 99  
         case TokenTypes.STATIC_INIT:
 100  
         case TokenTypes.INSTANCE_INIT:
 101  88
             mScopeStack.push(new HashMap<String, DetailAST>());
 102  88
             break;
 103  
 
 104  
         case TokenTypes.PARAMETER_DEF:
 105  7
             if (ScopeUtils.inInterfaceBlock(aAST)
 106  
                 || inAbstractMethod(aAST))
 107  
             {
 108  1
                 break;
 109  
             }
 110  
         case TokenTypes.VARIABLE_DEF:
 111  40
             if ((aAST.getParent().getType() != TokenTypes.OBJBLOCK)
 112  
                 && (aAST.getParent().getType() != TokenTypes.FOR_EACH_CLAUSE))
 113  
             {
 114  35
                 insertVariable(aAST);
 115  
             }
 116  
             break;
 117  
 
 118  
         case TokenTypes.IDENT:
 119  216
             final int parentType = aAST.getParent().getType();
 120  216
             if ((TokenTypes.POST_DEC        == parentType)
 121  
                 || (TokenTypes.DEC          == parentType)
 122  
                 || (TokenTypes.POST_INC     == parentType)
 123  
                 || (TokenTypes.INC          == parentType)
 124  
                 || (TokenTypes.ASSIGN       == parentType)
 125  
                 || (TokenTypes.PLUS_ASSIGN  == parentType)
 126  
                 || (TokenTypes.MINUS_ASSIGN == parentType)
 127  
                 || (TokenTypes.DIV_ASSIGN   == parentType)
 128  
                 || (TokenTypes.STAR_ASSIGN  == parentType)
 129  
                 || (TokenTypes.MOD_ASSIGN   == parentType)
 130  
                 || (TokenTypes.SR_ASSIGN    == parentType)
 131  
                 || (TokenTypes.BSR_ASSIGN   == parentType)
 132  
                 || (TokenTypes.SL_ASSIGN    == parentType)
 133  
                 || (TokenTypes.BXOR_ASSIGN  == parentType)
 134  
                 || (TokenTypes.BOR_ASSIGN   == parentType)
 135  
                 || (TokenTypes.BAND_ASSIGN  == parentType))
 136  
             {
 137  
                 // TODO: is there better way to check is aAST
 138  
                 // in left part of assignment?
 139  24
                 if (aAST.getParent().getFirstChild() == aAST) {
 140  22
                     removeVariable(aAST);
 141  
                 }
 142  
             }
 143  
             break;
 144  
 
 145  
         default:
 146  
         }
 147  346
     }
 148  
 
 149  
     /**
 150  
      * Determines whether an AST is a descentant of an abstract method.
 151  
      * @param aAST the AST to check.
 152  
      * @return true if aAST is a descentant of an abstract method.
 153  
      */
 154  
     private boolean inAbstractMethod(DetailAST aAST)
 155  
     {
 156  6
         DetailAST parent = aAST.getParent();
 157  12
         while (parent != null) {
 158  12
             if (parent.getType() == TokenTypes.METHOD_DEF) {
 159  6
                 final DetailAST modifiers =
 160  
                     parent.findFirstToken(TokenTypes.MODIFIERS);
 161  6
                 return modifiers.branchContains(TokenTypes.ABSTRACT);
 162  
             }
 163  6
             parent = parent.getParent();
 164  
         }
 165  0
         return false;
 166  
     }
 167  
 
 168  
     /**
 169  
      * Inserts a variable at the topmost scope stack
 170  
      * @param aAST the variable to insert
 171  
      */
 172  
     private void insertVariable(DetailAST aAST)
 173  
     {
 174  35
         if (!aAST.branchContains(TokenTypes.FINAL)) {
 175  31
             final Map<String, DetailAST> state = mScopeStack.peek();
 176  31
             final DetailAST ast = aAST.findFirstToken(TokenTypes.IDENT);
 177  31
             state.put(ast.getText(), ast);
 178  
         }
 179  35
     }
 180  
 
 181  
     /**
 182  
      * Removes the variable from the Stacks
 183  
      * @param aAST Variable to remove
 184  
      */
 185  
     private void removeVariable(DetailAST aAST)
 186  
     {
 187  74
         for (int i = mScopeStack.size() - 1; i >= 0; i--) {
 188  61
             final Map<String, DetailAST> state = mScopeStack.peek(i);
 189  61
             final Object obj = state.remove(aAST.getText());
 190  61
             if (obj != null) {
 191  9
                 break;
 192  
             }
 193  
         }
 194  22
     }
 195  
 
 196  
     @Override
 197  
     public void leaveToken(DetailAST aAST)
 198  
     {
 199  346
         super.leaveToken(aAST);
 200  
 
 201  346
         switch(aAST.getType()) {
 202  
         case TokenTypes.OBJBLOCK:
 203  
         case TokenTypes.SLIST:
 204  
         case TokenTypes.LITERAL_FOR:
 205  
         case TokenTypes.CTOR_DEF:
 206  
         case TokenTypes.STATIC_INIT:
 207  
         case TokenTypes.INSTANCE_INIT:
 208  
         case TokenTypes.METHOD_DEF:
 209  88
             final Map<String, DetailAST> state = mScopeStack.pop();
 210  88
             for (DetailAST var : state.values()) {
 211  22
                 log(var.getLineNo(), var.getColumnNo(), "final.variable", var
 212  
                         .getText());
 213  
             }
 214  88
             break;
 215  
 
 216  
         default:
 217  
         }
 218  346
     }
 219  
 }