Coverage Report - com.puppycrawl.tools.checkstyle.checks.indentation.IndentationCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
IndentationCheck
100%
54/54
100%
2/2
1.042
 
 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.indentation;
 21  
 
 22  
 import java.util.ArrayDeque;
 23  
 import java.util.Deque;
 24  
 import java.util.HashSet;
 25  
 import java.util.Set;
 26  
 
 27  
 import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
 28  
 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
 29  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 30  
 
 31  
 /**
 32  
  * Checks correct indentation of Java Code.
 33  
  *
 34  
  * <p>
 35  
  * The basic idea behind this is that while
 36  
  * pretty printers are sometimes convenient for reformatting of
 37  
  * legacy code, they often either aren't configurable enough or
 38  
  * just can't anticipate how format should be done.  Sometimes this is
 39  
  * personal preference, other times it is practical experience.  In any
 40  
  * case, this check should just ensure that a minimal set of indentation
 41  
  * rules are followed.
 42  
  * </p>
 43  
  *
 44  
  * <p>
 45  
  * Implementation --
 46  
  *  Basically, this check requests visitation for all handled token
 47  
  *  types (those tokens registered in the HandlerFactory).  When visitToken
 48  
  *  is called, a new ExpressionHandler is created for the AST and pushed
 49  
  *  onto the handlers stack.  The new handler then checks the indentation
 50  
  *  for the currently visiting AST.  When leaveToken is called, the
 51  
  *  ExpressionHandler is popped from the stack.
 52  
  * </p>
 53  
  *
 54  
  * <p>
 55  
  *  While on the stack the ExpressionHandler can be queried for the
 56  
  *  indentation level it suggests for children as well as for other
 57  
  *  values.
 58  
  * </p>
 59  
  *
 60  
  * <p>
 61  
  *  While an ExpressionHandler checks the indentation level of its own
 62  
  *  AST, it typically also checks surrounding ASTs.  For instance, a
 63  
  *  while loop handler checks the while loop as well as the braces
 64  
  *  and immediate children.
 65  
  * </p>
 66  
  * <pre>
 67  
  *   - handler class -to-&gt; ID mapping kept in Map
 68  
  *   - parent passed in during construction
 69  
  *   - suggest child indent level
 70  
  *   - allows for some tokens to be on same line (ie inner classes OBJBLOCK)
 71  
  *     and not increase indentation level
 72  
  *   - looked at using double dispatch for getSuggestedChildIndent(), but it
 73  
  *     doesn't seem worthwhile, at least now
 74  
  *   - both tabs and spaces are considered whitespace in front of the line...
 75  
  *     tabs are converted to spaces
 76  
  *   - block parents with parens -- for, while, if, etc... -- are checked that
 77  
  *     they match the level of the parent
 78  
  * </pre>
 79  
  *
 80  
  * @author jrichard
 81  
  * @author o_sukhodolsky
 82  
  * @author Maikel Steneker
 83  
  * @author maxvetrenko
 84  
  * @noinspection ThisEscapedInObjectConstruction
 85  
  */
 86  
 @FileStatefulCheck
 87  89
 public class IndentationCheck extends AbstractCheck {
 88  
     /**
 89  
      * A key is pointing to the warning message text in "messages.properties"
 90  
      * file.
 91  
      */
 92  
     public static final String MSG_ERROR = "indentation.error";
 93  
 
 94  
     /**
 95  
      * A key is pointing to the warning message text in "messages.properties"
 96  
      * file.
 97  
      */
 98  
     public static final String MSG_ERROR_MULTI = "indentation.error.multi";
 99  
 
 100  
     /**
 101  
      * A key is pointing to the warning message text in "messages.properties"
 102  
      * file.
 103  
      */
 104  
     public static final String MSG_CHILD_ERROR = "indentation.child.error";
 105  
 
 106  
     /**
 107  
      * A key is pointing to the warning message text in "messages.properties"
 108  
      * file.
 109  
      */
 110  
     public static final String MSG_CHILD_ERROR_MULTI = "indentation.child.error.multi";
 111  
 
 112  
     /** Default indentation amount - based on Sun. */
 113  
     private static final int DEFAULT_INDENTATION = 4;
 114  
 
 115  
     /** Handlers currently in use. */
 116  89
     private final Deque<AbstractExpressionHandler> handlers = new ArrayDeque<>();
 117  
 
 118  
     /** Instance of line wrapping handler to use. */
 119  89
     private final LineWrappingHandler lineWrappingHandler = new LineWrappingHandler(this);
 120  
 
 121  
     /** Factory from which handlers are distributed. */
 122  89
     private final HandlerFactory handlerFactory = new HandlerFactory();
 123  
 
 124  
     /** Lines logged as having incorrect indentation. */
 125  
     private Set<Integer> incorrectIndentationLines;
 126  
 
 127  
     /** How many tabs or spaces to use. */
 128  89
     private int basicOffset = DEFAULT_INDENTATION;
 129  
 
 130  
     /** How much to indent a case label. */
 131  89
     private int caseIndent = DEFAULT_INDENTATION;
 132  
 
 133  
     /** How far brace should be indented when on next line. */
 134  
     private int braceAdjustment;
 135  
 
 136  
     /** How far throws should be indented when on next line. */
 137  89
     private int throwsIndent = DEFAULT_INDENTATION;
 138  
 
 139  
     /** How much to indent an array initialization when on next line. */
 140  89
     private int arrayInitIndent = DEFAULT_INDENTATION;
 141  
 
 142  
     /** How far continuation line should be indented when line-wrapping is present. */
 143  89
     private int lineWrappingIndentation = DEFAULT_INDENTATION;
 144  
 
 145  
     /**
 146  
      * Force strict condition in line wrapping case. If value is true, line wrap indent
 147  
      * have to be same as lineWrappingIndentation parameter, if value is false, line wrap indent
 148  
      * have to be not less than lineWrappingIndentation parameter.
 149  
      */
 150  
     private boolean forceStrictCondition;
 151  
 
 152  
     /**
 153  
      * Get forcing strict condition.
 154  
      * @return forceStrictCondition value.
 155  
      */
 156  
     public boolean isForceStrictCondition() {
 157  761
         return forceStrictCondition;
 158  
     }
 159  
 
 160  
     /**
 161  
      * Set forcing strict condition.
 162  
      * @param value user's value of forceStrictCondition.
 163  
      */
 164  
     public void setForceStrictCondition(boolean value) {
 165  61
         forceStrictCondition = value;
 166  61
     }
 167  
 
 168  
     /**
 169  
      * Set the basic offset.
 170  
      *
 171  
      * @param basicOffset   the number of tabs or spaces to indent
 172  
      */
 173  
     public void setBasicOffset(int basicOffset) {
 174  67
         this.basicOffset = basicOffset;
 175  67
     }
 176  
 
 177  
     /**
 178  
      * Get the basic offset.
 179  
      *
 180  
      * @return the number of tabs or spaces to indent
 181  
      */
 182  
     public int getBasicOffset() {
 183  4212
         return basicOffset;
 184  
     }
 185  
 
 186  
     /**
 187  
      * Adjusts brace indentation (positive offset).
 188  
      *
 189  
      * @param adjustmentAmount   the brace offset
 190  
      */
 191  
     public void setBraceAdjustment(int adjustmentAmount) {
 192  60
         braceAdjustment = adjustmentAmount;
 193  60
     }
 194  
 
 195  
     /**
 196  
      * Get the brace adjustment amount.
 197  
      *
 198  
      * @return the positive offset to adjust braces
 199  
      */
 200  
     public int getBraceAdjustment() {
 201  2570
         return braceAdjustment;
 202  
     }
 203  
 
 204  
     /**
 205  
      * Set the case indentation level.
 206  
      *
 207  
      * @param amount   the case indentation level
 208  
      */
 209  
     public void setCaseIndent(int amount) {
 210  58
         caseIndent = amount;
 211  58
     }
 212  
 
 213  
     /**
 214  
      * Get the case indentation level.
 215  
      *
 216  
      * @return the case indentation level
 217  
      */
 218  
     public int getCaseIndent() {
 219  33
         return caseIndent;
 220  
     }
 221  
 
 222  
     /**
 223  
      * Set the throws indentation level.
 224  
      *
 225  
      * @param throwsIndent the throws indentation level
 226  
      */
 227  
     public void setThrowsIndent(int throwsIndent) {
 228  59
         this.throwsIndent = throwsIndent;
 229  59
     }
 230  
 
 231  
     /**
 232  
      * Get the throws indentation level.
 233  
      *
 234  
      * @return the throws indentation level
 235  
      */
 236  
     public int getThrowsIndent() {
 237  19
         return throwsIndent;
 238  
     }
 239  
 
 240  
     /**
 241  
      * Set the array initialisation indentation level.
 242  
      *
 243  
      * @param arrayInitIndent the array initialisation indentation level
 244  
      */
 245  
     public void setArrayInitIndent(int arrayInitIndent) {
 246  58
         this.arrayInitIndent = arrayInitIndent;
 247  58
     }
 248  
 
 249  
     /**
 250  
      * Get the line-wrapping indentation level.
 251  
      *
 252  
      * @return the initialisation indentation level
 253  
      */
 254  
     public int getArrayInitIndent() {
 255  70
         return arrayInitIndent;
 256  
     }
 257  
 
 258  
     /**
 259  
      * Get the array line-wrapping indentation level.
 260  
      *
 261  
      * @return the line-wrapping indentation level
 262  
      */
 263  
     public int getLineWrappingIndentation() {
 264  1980
         return lineWrappingIndentation;
 265  
     }
 266  
 
 267  
     /**
 268  
      * Set the line-wrapping indentation level.
 269  
      *
 270  
      * @param lineWrappingIndentation the line-wrapping indentation level
 271  
      */
 272  
     public void setLineWrappingIndentation(int lineWrappingIndentation) {
 273  63
         this.lineWrappingIndentation = lineWrappingIndentation;
 274  63
     }
 275  
 
 276  
     /**
 277  
      * Log an error message.
 278  
      *
 279  
      * @param line the line number where the error was found
 280  
      * @param key the message that describes the error
 281  
      * @param args the details of the message
 282  
      *
 283  
      * @see java.text.MessageFormat
 284  
      */
 285  
     public void indentationLog(int line, String key, Object... args) {
 286  535
         if (!incorrectIndentationLines.contains(line)) {
 287  479
             incorrectIndentationLines.add(line);
 288  479
             log(line, key, args);
 289  
         }
 290  535
     }
 291  
 
 292  
     /**
 293  
      * Get the width of a tab.
 294  
      *
 295  
      * @return the width of a tab
 296  
      */
 297  
     public int getIndentationTabWidth() {
 298  58893
         return getTabWidth();
 299  
     }
 300  
 
 301  
     @Override
 302  
     public int[] getDefaultTokens() {
 303  165
         return getRequiredTokens();
 304  
     }
 305  
 
 306  
     @Override
 307  
     public int[] getAcceptableTokens() {
 308  6
         return getRequiredTokens();
 309  
     }
 310  
 
 311  
     @Override
 312  
     public int[] getRequiredTokens() {
 313  337
         return handlerFactory.getHandledTypes();
 314  
     }
 315  
 
 316  
     @Override
 317  
     public void beginTree(DetailAST ast) {
 318  77
         handlerFactory.clearCreatedHandlers();
 319  77
         handlers.clear();
 320  77
         final PrimordialHandler primordialHandler = new PrimordialHandler(this);
 321  77
         handlers.push(primordialHandler);
 322  77
         primordialHandler.checkIndentation();
 323  77
         incorrectIndentationLines = new HashSet<>();
 324  77
     }
 325  
 
 326  
     @Override
 327  
     public void visitToken(DetailAST ast) {
 328  7318
         final AbstractExpressionHandler handler = handlerFactory.getHandler(this, ast,
 329  3659
             handlers.peek());
 330  3659
         handlers.push(handler);
 331  3659
         handler.checkIndentation();
 332  3659
     }
 333  
 
 334  
     @Override
 335  
     public void leaveToken(DetailAST ast) {
 336  3659
         handlers.pop();
 337  3659
     }
 338  
 
 339  
     /**
 340  
      * Accessor for the line wrapping handler.
 341  
      *
 342  
      * @return the line wrapping handler
 343  
      */
 344  
     public LineWrappingHandler getLineWrappingHandler() {
 345  1316
         return lineWrappingHandler;
 346  
     }
 347  
 
 348  
     /**
 349  
      * Accessor for the handler factory.
 350  
      *
 351  
      * @return the handler factory
 352  
      */
 353  
     public final HandlerFactory getHandlerFactory() {
 354  6003
         return handlerFactory;
 355  
     }
 356  
 }