Coverage Report - com.puppycrawl.tools.checkstyle.checks.indentation.BlockParentHandler
 
Classes in this File Line Coverage Branch Coverage Complexity
BlockParentHandler
100%
69/69
100%
44/44
1.909
 
 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 com.puppycrawl.tools.checkstyle.api.DetailAST;
 23  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 24  
 
 25  
 /**
 26  
  * Handler for parents of blocks ('if', 'else', 'while', etc).
 27  
  * <P>
 28  
  * The "block" handler classes use a common superclass BlockParentHandler,
 29  
  * employing the Template Method pattern.
 30  
  * </P>
 31  
  *
 32  
  * <UL>
 33  
  *   <LI>template method to get the lcurly</LI>
 34  
  *   <LI>template method to get the rcurly</LI>
 35  
  *   <LI>if curlies aren't present, then template method to get expressions
 36  
  *       is called</LI>
 37  
  *   <LI>now all the repetitious code which checks for BOL, if curlies are on
 38  
  *       same line, etc. can be collapsed into the superclass</LI>
 39  
  * </UL>
 40  
  *
 41  
  *
 42  
  * @author jrichard
 43  
  */
 44  
 public class BlockParentHandler extends AbstractExpressionHandler {
 45  
     /**
 46  
      * Children checked by parent handlers.
 47  
      */
 48  2
     private static final int[] CHECKED_CHILDREN = {
 49  
         TokenTypes.VARIABLE_DEF,
 50  
         TokenTypes.EXPR,
 51  
         TokenTypes.OBJBLOCK,
 52  
         TokenTypes.LITERAL_BREAK,
 53  
         TokenTypes.LITERAL_RETURN,
 54  
         TokenTypes.LITERAL_THROW,
 55  
         TokenTypes.LITERAL_CONTINUE,
 56  
     };
 57  
 
 58  
     /**
 59  
      * Construct an instance of this handler with the given indentation check,
 60  
      * name, abstract syntax tree, and parent handler.
 61  
      *
 62  
      * @param indentCheck   the indentation check
 63  
      * @param name          the name of the handler
 64  
      * @param ast           the abstract syntax tree
 65  
      * @param parent        the parent handler
 66  
      * @noinspection WeakerAccess
 67  
      */
 68  
     public BlockParentHandler(IndentationCheck indentCheck,
 69  
         String name, DetailAST ast, AbstractExpressionHandler parent) {
 70  2253
         super(indentCheck, name, ast, parent);
 71  2253
     }
 72  
 
 73  
     /**
 74  
      * Returns array of token types which should be checked among children.
 75  
      * @return array of token types to check.
 76  
      */
 77  
     protected int[] getCheckedChildren() {
 78  830
         return CHECKED_CHILDREN.clone();
 79  
     }
 80  
 
 81  
     /**
 82  
      * Get the top level expression being managed by this handler.
 83  
      *
 84  
      * @return the top level expression
 85  
      */
 86  
     protected DetailAST getTopLevelAst() {
 87  507
         return getMainAst();
 88  
     }
 89  
 
 90  
     /**
 91  
      * Check the indent of the top level token.
 92  
      */
 93  
     protected void checkTopLevelToken() {
 94  1194
         final DetailAST topLevel = getTopLevelAst();
 95  
 
 96  1194
         if (topLevel != null
 97  393
                 && !getIndent().isAcceptable(expandedTabsColumnNo(topLevel))
 98  103
                 && !hasLabelBefore()
 99  93
                 && (shouldTopLevelStartLine() || isOnStartOfLine(topLevel))) {
 100  53
             logError(topLevel, "", expandedTabsColumnNo(topLevel));
 101  
         }
 102  1194
     }
 103  
 
 104  
     /**
 105  
      * Check if the top level token has label before.
 106  
      * @return true if the top level token has label before.
 107  
      */
 108  
     private boolean hasLabelBefore() {
 109  103
         final DetailAST parent = getTopLevelAst().getParent();
 110  206
         return parent.getType() == TokenTypes.LABELED_STAT
 111  11
             && parent.getLineNo() == getTopLevelAst().getLineNo();
 112  
     }
 113  
 
 114  
     /**
 115  
      * Determines if the top level token must start the line.
 116  
      *
 117  
      * @return true
 118  
      */
 119  
     protected boolean shouldTopLevelStartLine() {
 120  47
         return true;
 121  
     }
 122  
 
 123  
     /**
 124  
      * Determines if this block expression has curly braces.
 125  
      *
 126  
      * @return true if curly braces are present, false otherwise
 127  
      */
 128  
     private boolean hasCurlies() {
 129  2576
         return getLeftCurly() != null && getRightCurly() != null;
 130  
     }
 131  
 
 132  
     /**
 133  
      * Get the left curly brace portion of the expression we are handling.
 134  
      *
 135  
      * @return the left curly brace expression
 136  
      */
 137  
     protected DetailAST getLeftCurly() {
 138  3395
         return getMainAst().findFirstToken(TokenTypes.SLIST);
 139  
     }
 140  
 
 141  
     /**
 142  
      * Get the right curly brace portion of the expression we are handling.
 143  
      *
 144  
      * @return the right curly brace expression
 145  
      */
 146  
     protected DetailAST getRightCurly() {
 147  2945
         final DetailAST slist = getMainAst().findFirstToken(TokenTypes.SLIST);
 148  2945
         return slist.findFirstToken(TokenTypes.RCURLY);
 149  
     }
 150  
 
 151  
     /**
 152  
      * Check the indentation of the left curly brace.
 153  
      */
 154  
     private void checkLeftCurly() {
 155  
         // the lcurly can either be at the correct indentation, or nested
 156  
         // with a previous expression
 157  1146
         final DetailAST lcurly = getLeftCurly();
 158  1146
         final int lcurlyPos = expandedTabsColumnNo(lcurly);
 159  
 
 160  1146
         if (!curlyIndent().isAcceptable(lcurlyPos) && isOnStartOfLine(lcurly)) {
 161  47
             logError(lcurly, "lcurly", lcurlyPos, curlyIndent());
 162  
         }
 163  1146
     }
 164  
 
 165  
     /**
 166  
      * Get the expected indentation level for the curly braces.
 167  
      *
 168  
      * @return the curly brace indentation level
 169  
      */
 170  
     protected IndentLevel curlyIndent() {
 171  2362
         return new IndentLevel(getIndent(), getBraceAdjustment());
 172  
     }
 173  
 
 174  
     /**
 175  
      * Determines if child elements within the expression may be nested.
 176  
      *
 177  
      * @return false
 178  
      */
 179  
     protected boolean canChildrenBeNested() {
 180  988
         return false;
 181  
     }
 182  
 
 183  
     /**
 184  
      * Check the indentation of the right curly brace.
 185  
      */
 186  
     private void checkRightCurly() {
 187  1146
         final DetailAST rcurly = getRightCurly();
 188  1146
         final int rcurlyPos = expandedTabsColumnNo(rcurly);
 189  
 
 190  1146
         if (!curlyIndent().isAcceptable(rcurlyPos)
 191  237
                 && isOnStartOfLine(rcurly)) {
 192  95
             logError(rcurly, "rcurly", rcurlyPos, curlyIndent());
 193  
         }
 194  1146
     }
 195  
 
 196  
     /**
 197  
      * Get the child element that is not a list of statements.
 198  
      *
 199  
      * @return the non-list child element
 200  
      */
 201  
     protected DetailAST getNonListChild() {
 202  32
         return getMainAst().findFirstToken(TokenTypes.RPAREN).getNextSibling();
 203  
     }
 204  
 
 205  
     /**
 206  
      * Check the indentation level of a child that is not a list of statements.
 207  
      */
 208  
     private void checkNonListChild() {
 209  71
         final DetailAST nonList = getNonListChild();
 210  71
         if (nonList != null) {
 211  56
             final IndentLevel expected = new IndentLevel(getIndent(), getBasicOffset());
 212  56
             checkExpressionSubtree(nonList, expected, false, false);
 213  
         }
 214  71
     }
 215  
 
 216  
     /**
 217  
      * Get the child element representing the list of statements.
 218  
      *
 219  
      * @return the statement list child
 220  
      */
 221  
     protected DetailAST getListChild() {
 222  751
         return getMainAst().findFirstToken(TokenTypes.SLIST);
 223  
     }
 224  
 
 225  
     /**
 226  
      * Get the right parenthesis portion of the expression we are handling.
 227  
      *
 228  
      * @return the right parenthesis expression
 229  
      */
 230  
     private DetailAST getRightParen() {
 231  1239
         return getMainAst().findFirstToken(TokenTypes.RPAREN);
 232  
     }
 233  
 
 234  
     /**
 235  
      * Get the left parenthesis portion of the expression we are handling.
 236  
      *
 237  
      * @return the left parenthesis expression
 238  
      */
 239  
     private DetailAST getLeftParen() {
 240  2478
         return getMainAst().findFirstToken(TokenTypes.LPAREN);
 241  
     }
 242  
 
 243  
     @Override
 244  
     public void checkIndentation() {
 245  1239
         checkTopLevelToken();
 246  
         // separate to allow for eventual configuration
 247  1239
         checkLeftParen(getLeftParen());
 248  1239
         checkRightParen(getLeftParen(), getRightParen());
 249  1239
         if (hasCurlies()) {
 250  1146
             checkLeftCurly();
 251  1146
             checkRightCurly();
 252  
         }
 253  1239
         final DetailAST listChild = getListChild();
 254  1239
         if (listChild == null) {
 255  71
             checkNonListChild();
 256  
         }
 257  
         else {
 258  
             // NOTE: switch statements usually don't have curlies
 259  1168
             if (!hasCurlies() || !areOnSameLine(getLeftCurly(), getRightCurly())) {
 260  2078
                 checkChildren(listChild,
 261  1039
                         getCheckedChildren(),
 262  1039
                         getChildrenExpectedIndent(),
 263  
                         true,
 264  1039
                         canChildrenBeNested());
 265  
             }
 266  
         }
 267  1239
     }
 268  
 
 269  
     /**
 270  
      * Gets indentation level expected for children.
 271  
      * @return indentation level expected for children
 272  
      */
 273  
     protected IndentLevel getChildrenExpectedIndent() {
 274  2399
         IndentLevel indentLevel = new IndentLevel(getIndent(), getBasicOffset());
 275  
         // if we have multileveled expected level then we should
 276  
         // try to suggest single level to children using curlies'
 277  
         // levels.
 278  2399
         if (getIndent().isMultiLevel() && hasCurlies()) {
 279  168
             if (isOnStartOfLine(getLeftCurly())) {
 280  28
                 indentLevel = new IndentLevel(expandedTabsColumnNo(getLeftCurly())
 281  28
                         + getBasicOffset());
 282  
             }
 283  140
             else if (isOnStartOfLine(getRightCurly())) {
 284  136
                 final IndentLevel level = new IndentLevel(curlyIndent(), getBasicOffset());
 285  136
                 level.addAcceptedIndent(level.getFirstIndentLevel() + getLineWrappingIndent());
 286  136
                 indentLevel = level;
 287  
             }
 288  
         }
 289  2399
         return indentLevel;
 290  
     }
 291  
 
 292  
     @Override
 293  
     public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) {
 294  1423
         return getChildrenExpectedIndent();
 295  
     }
 296  
 
 297  
     /**
 298  
      * A shortcut for {@code IndentationCheck} property.
 299  
      * @return value of lineWrappingIndentation property
 300  
      *         of {@code IndentationCheck}
 301  
      */
 302  
     private int getLineWrappingIndent() {
 303  136
         return getIndentCheck().getLineWrappingIndentation();
 304  
     }
 305  
 }