Coverage Report - com.puppycrawl.tools.checkstyle.checks.design.MutableExceptionCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
MutableExceptionCheck
92%
25/27
84%
11/13
1.889
 
 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.design;
 20  
 
 21  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 22  
 import com.puppycrawl.tools.checkstyle.api.FastStack;
 23  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 24  
 import com.puppycrawl.tools.checkstyle.checks.AbstractFormatCheck;
 25  
 
 26  
 /**
 27  
  * <p> Ensures that exceptions (defined as any class name conforming
 28  
  * to some regular expression) are immutable. That is, have only final
 29  
  * fields.</p>
 30  
  * <p> Rationale: Exception instances should represent an error
 31  
  * condition. Having non final fields not only allows the state to be
 32  
  * modified by accident and therefore mask the original condition but
 33  
  * also allows developers to accidentally forget to initialise state
 34  
  * thereby leading to code catching the exception to draw incorrect
 35  
  * conclusions based on the state.</p>
 36  
  *
 37  
  * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a>
 38  
  */
 39  
 public final class MutableExceptionCheck extends AbstractFormatCheck
 40  
 {
 41  
     /** Default value for format property. */
 42  
     private static final String DEFAULT_FORMAT = "^.*Exception$|^.*Error$";
 43  
     /** Stack of checking information for classes. */
 44  1
     private final FastStack<Boolean> mCheckingStack = FastStack.newInstance();
 45  
     /** Should we check current class or not. */
 46  
     private boolean mChecking;
 47  
 
 48  
     /** Creates new instance of the check. */
 49  
     public MutableExceptionCheck()
 50  
     {
 51  1
         super(DEFAULT_FORMAT);
 52  1
     }
 53  
 
 54  
     @Override
 55  
     public int[] getDefaultTokens()
 56  
     {
 57  1
         return new int[] {TokenTypes.CLASS_DEF, TokenTypes.VARIABLE_DEF};
 58  
     }
 59  
 
 60  
     @Override
 61  
     public int[] getRequiredTokens()
 62  
     {
 63  0
         return getDefaultTokens();
 64  
     }
 65  
 
 66  
     @Override
 67  
     public void visitToken(DetailAST aAST)
 68  
     {
 69  9
         switch (aAST.getType()) {
 70  
         case TokenTypes.CLASS_DEF:
 71  4
             visitClassDef(aAST);
 72  4
             break;
 73  
         case TokenTypes.VARIABLE_DEF:
 74  5
             visitVariableDef(aAST);
 75  5
             break;
 76  
         default:
 77  0
             throw new IllegalStateException(aAST.toString());
 78  
         }
 79  9
     }
 80  
 
 81  
     @Override
 82  
     public void leaveToken(DetailAST aAST)
 83  
     {
 84  9
         switch (aAST.getType()) {
 85  
         case TokenTypes.CLASS_DEF:
 86  4
             leaveClassDef();
 87  4
             break;
 88  
         default:
 89  
             // Do nothing
 90  
         }
 91  9
     }
 92  
 
 93  
     /**
 94  
      * Called when we start processing class definition.
 95  
      * @param aAST class definition node
 96  
      */
 97  
     private void visitClassDef(DetailAST aAST)
 98  
     {
 99  4
         mCheckingStack.push(mChecking ? Boolean.TRUE : Boolean.FALSE);
 100  4
         mChecking =
 101  
             isExceptionClass(aAST.findFirstToken(TokenTypes.IDENT).getText());
 102  4
     }
 103  
 
 104  
     /** Called when we leave class definition. */
 105  
     private void leaveClassDef()
 106  
     {
 107  4
         mChecking = (mCheckingStack.pop()).booleanValue();
 108  4
     }
 109  
 
 110  
     /**
 111  
      * Checks variable definition.
 112  
      * @param aAST variable def node for check.
 113  
      */
 114  
     private void visitVariableDef(DetailAST aAST)
 115  
     {
 116  5
         if (mChecking && (aAST.getParent().getType() == TokenTypes.OBJBLOCK)) {
 117  3
             final DetailAST modifiersAST =
 118  
                 aAST.findFirstToken(TokenTypes.MODIFIERS);
 119  
 
 120  3
             if (!(modifiersAST.findFirstToken(TokenTypes.FINAL) != null)) {
 121  2
                 log(aAST.getLineNo(),  aAST.getColumnNo(), "mutable.exception",
 122  
                         aAST.findFirstToken(TokenTypes.IDENT).getText());
 123  
             }
 124  
         }
 125  5
     }
 126  
 
 127  
     /**
 128  
      * @param aClassName class name to check
 129  
      * @return true if a given class name confirms specified format
 130  
      */
 131  
     private boolean isExceptionClass(String aClassName)
 132  
     {
 133  4
         return getRegexp().matcher(aClassName).find();
 134  
     }
 135  
 }