Coverage Report - com.puppycrawl.tools.checkstyle.checks.indentation.IndentationCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
IndentationCheck
95%
39/41
100%
8/8
1.438
 
 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.indentation;
 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  
 
 27  
 // TODO: allow preset indentation styles (IE... GNU style, Sun style, etc...)?
 28  
 
 29  
 // TODO: optionally make imports (and other?) statements required to start
 30  
 //   line? -- but maybe this should be a different check
 31  
 
 32  
 // TODO: optionally allow array children, throws clause, etc...
 33  
 //   to be of any indentation > required, for emacs-style indentation
 34  
 
 35  
 // TODO: this is not illegal, but probably should be:
 36  
 //        myfunc3(11, 11, Integer.
 37  
 //            getInteger("mytest").intValue(),  // this should be in 4 more
 38  
 //            11);
 39  
 
 40  
 // TODO: any dot-based indentation doesn't work (at least not yet...) the
 41  
 //  problem is that we don't know which way an expression tree will be built
 42  
 //  and with dot trees, they are built backwards.  This means code like
 43  
 //
 44  
 //  org.blah.mystuff
 45  
 //      .myclass.getFactoryObject()
 46  
 //          .objFunc().otherMethod();
 47  
 // and
 48  
 //  return ((MethodCallHandler) parent)
 49  
 //      .findContainingMethodCall(this);
 50  
 //  is all checked at the level of the first line.  Simple dots are actually
 51  
 // checked but the method call handler will have to be changed drastically
 52  
 // to fix the above...
 53  
 
 54  
 
 55  
 /**
 56  
  * Checks correct indentation of Java Code.
 57  
  *
 58  
  * <p>
 59  
  * The basic idea behind this is that while
 60  
  * pretty printers are sometimes convenient for bulk reformats of
 61  
  * legacy code, they often either aren't configurable enough or
 62  
  * just can't anticipate how format should be done.  Sometimes this is
 63  
  * personal preference, other times it is practical experience.  In any
 64  
  * case, this check should just ensure that a minimal set of indentation
 65  
  * rules are followed.
 66  
  * </p>
 67  
  *
 68  
  * <p>
 69  
  * Implementation --
 70  
  *  Basically, this check requests visitation for all handled token
 71  
  *  types (those tokens registered in the HandlerFactory).  When visitToken
 72  
  *  is called, a new ExpressionHandler is created for the AST and pushed
 73  
  *  onto the mHandlers stack.  The new handler then checks the indentation
 74  
  *  for the currently visiting AST.  When leaveToken is called, the
 75  
  *  ExpressionHandler is popped from the stack.
 76  
  * </p>
 77  
  *
 78  
  * <p>
 79  
  *  While on the stack the ExpressionHandler can be queried for the
 80  
  *  indentation level it suggests for children as well as for other
 81  
  *  values.
 82  
  * </p>
 83  
  *
 84  
  * <p>
 85  
  *  While an ExpressionHandler checks the indentation level of its own
 86  
  *  AST, it typically also checks surrounding ASTs.  For instance, a
 87  
  *  while loop handler checks the while loop as well as the braces
 88  
  *  and immediate children.
 89  
  * </p>
 90  
  * <pre>
 91  
  *   - handler class -to-> ID mapping kept in Map
 92  
  *   - parent passed in during construction
 93  
  *   - suggest child indent level
 94  
  *   - allows for some tokens to be on same line (ie inner classes OBJBLOCK)
 95  
  *     and not increase indentation level
 96  
  *   - looked at using double dispatch for suggestedChildLevel(), but it
 97  
  *     doesn't seem worthwhile, at least now
 98  
  *   - both tabs and spaces are considered whitespace in front of the line...
 99  
  *     tabs are converted to spaces
 100  
  *   - block parents with parens -- for, while, if, etc... -- are checked that
 101  
  *     they match the level of the parent
 102  
  * </pre>
 103  
  *
 104  
  * @author jrichard
 105  
  * @author o_sukhodolsky
 106  
  * @author Maikel Steneker
 107  
  */
 108  
 public class IndentationCheck extends Check
 109  
 {
 110  
     /** Default indentation amount - based on Sun */
 111  
     private static final int DEFAULT_INDENTATION = 4;
 112  
 
 113  
     /** how many tabs or spaces to use */
 114  33
     private int mBasicOffset = DEFAULT_INDENTATION;
 115  
 
 116  
     /** how much to indent a case label */
 117  33
     private int mCaseIndentationAmount = DEFAULT_INDENTATION;
 118  
 
 119  
     /** how far brace should be indented when on next line */
 120  
     private int mBraceAdjustment;
 121  
 
 122  
     /** how far throws should be indented when on next line */
 123  33
     private int mThrowsIndentationAmount = DEFAULT_INDENTATION;
 124  
 
 125  
     /** handlers currently in use */
 126  33
     private final FastStack<ExpressionHandler> mHandlers =
 127  
         FastStack.newInstance();
 128  
 
 129  
     /** factory from which handlers are distributed */
 130  33
     private final HandlerFactory mHandlerFactory = new HandlerFactory();
 131  
 
 132  
     /** Creates a new instance of IndentationCheck. */
 133  
     public IndentationCheck()
 134  33
     {
 135  33
     }
 136  
 
 137  
     /**
 138  
      * Set the basic offset.
 139  
      *
 140  
      * @param aBasicOffset   the number of tabs or spaces to indent
 141  
      */
 142  
     public void setBasicOffset(int aBasicOffset)
 143  
     {
 144  2
         mBasicOffset = aBasicOffset;
 145  2
     }
 146  
 
 147  
     /**
 148  
      * Get the basic offset.
 149  
      *
 150  
      * @return the number of tabs or spaces to indent
 151  
      */
 152  
     public int getBasicOffset()
 153  
     {
 154  2653
         return mBasicOffset;
 155  
     }
 156  
 
 157  
     /**
 158  
      * Adjusts brace indentation (positive offset).
 159  
      *
 160  
      * @param aAdjustmentAmount   the brace offset
 161  
      */
 162  
     public void setBraceAdjustment(int aAdjustmentAmount)
 163  
     {
 164  1
         mBraceAdjustment = aAdjustmentAmount;
 165  1
     }
 166  
 
 167  
     /**
 168  
      * Get the brace adjustment amount.
 169  
      *
 170  
      * @return the positive offset to adjust braces
 171  
      */
 172  
     public int getBraceAdjustement()
 173  
     {
 174  1195
         return mBraceAdjustment;
 175  
     }
 176  
 
 177  
     /**
 178  
      * Set the case indentation level.
 179  
      *
 180  
      * @param aAmount   the case indentation level
 181  
      */
 182  
     public void setCaseIndent(int aAmount)
 183  
     {
 184  1
         mCaseIndentationAmount = aAmount;
 185  1
     }
 186  
 
 187  
     /**
 188  
      * Get the case indentation level.
 189  
      *
 190  
      * @return the case indentation level
 191  
      */
 192  
     public int getCaseIndent()
 193  
     {
 194  25
         return mCaseIndentationAmount;
 195  
     }
 196  
 
 197  
     /**
 198  
      * Set the throws indentation level.
 199  
      *
 200  
      * @param aThrowsIndent the throws indentation level
 201  
      */
 202  
     public void setThrowsIndent(int aThrowsIndent)
 203  
     {
 204  1
         mThrowsIndentationAmount = aThrowsIndent;
 205  1
     }
 206  
 
 207  
     /**
 208  
      * Get the throws indentation level.
 209  
      *
 210  
      * @return the throws indentation level
 211  
      */
 212  
     public int getThrowsIndent()
 213  
     {
 214  5
         return this.mThrowsIndentationAmount;
 215  
     }
 216  
 
 217  
     /**
 218  
      * Log an error message.
 219  
      *
 220  
      * @param aLine the line number where the error was found
 221  
      * @param aKey the message that describes the error
 222  
      * @param aArgs the details of the message
 223  
      *
 224  
      * @see java.text.MessageFormat
 225  
      */
 226  
     public void indentationLog(int aLine, String aKey, Object... aArgs)
 227  
     {
 228  347
         super.log(aLine, aKey, aArgs);
 229  347
     }
 230  
 
 231  
     /**
 232  
      * Get the width of a tab.
 233  
      *
 234  
      * @return the width of a tab
 235  
      */
 236  
     public int getIndentationTabWidth()
 237  
     {
 238  16921
         return getTabWidth();
 239  
     }
 240  
 
 241  
     @Override
 242  
     public int[] getDefaultTokens()
 243  
     {
 244  33
         return mHandlerFactory.getHandledTypes();
 245  
     }
 246  
 
 247  
     @Override
 248  
     public void beginTree(DetailAST aAst)
 249  
     {
 250  33
         mHandlerFactory.clearCreatedHandlers();
 251  33
         mHandlers.clear();
 252  33
         mHandlers.push(new PrimordialHandler(this));
 253  33
     }
 254  
 
 255  
     @Override
 256  
     public void visitToken(DetailAST aAST)
 257  
     {
 258  1902
         if ((aAST.getType() == TokenTypes.VARIABLE_DEF)
 259  
             && ScopeUtils.isLocalVariableDef(aAST))
 260  
         {
 261  
             // we have handler only for members
 262  126
             return;
 263  
         }
 264  
 
 265  1776
         final ExpressionHandler handler = mHandlerFactory.getHandler(this, aAST,
 266  
             mHandlers.peek());
 267  1776
         mHandlers.push(handler);
 268  
         try {
 269  1776
             handler.checkIndentation();
 270  
         }
 271  0
         catch (final NullPointerException npe) {
 272  0
             npe.printStackTrace();
 273  1776
         }
 274  1776
     }
 275  
 
 276  
     @Override
 277  
     public void leaveToken(DetailAST aAST)
 278  
     {
 279  1902
         if ((aAST.getType() == TokenTypes.VARIABLE_DEF)
 280  
             && ScopeUtils.isLocalVariableDef(aAST))
 281  
         {
 282  
             // we have handler only for members
 283  126
             return;
 284  
         }
 285  1776
         mHandlers.pop();
 286  1776
     }
 287  
 
 288  
     /**
 289  
      * Accessor for the handler factory.
 290  
      *
 291  
      * @return the handler factory
 292  
      */
 293  
     final HandlerFactory getHandlerFactory()
 294  
     {
 295  6254
         return mHandlerFactory;
 296  
     }
 297  
 }