Coverage Report - com.puppycrawl.tools.checkstyle.checks.blocks.RightCurlyCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
RightCurlyCheck
100%
73/73
100%
74/74
3.192
RightCurlyCheck$Details
100%
105/105
100%
43/43
3.192
 
 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.blocks;
 21  
 
 22  
 import java.util.Locale;
 23  
 
 24  
 import com.puppycrawl.tools.checkstyle.StatelessCheck;
 25  
 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
 26  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 27  
 import com.puppycrawl.tools.checkstyle.api.Scope;
 28  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 29  
 import com.puppycrawl.tools.checkstyle.utils.CheckUtils;
 30  
 import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
 31  
 import com.puppycrawl.tools.checkstyle.utils.ScopeUtils;
 32  
 
 33  
 /**
 34  
  * <p>
 35  
  * Checks the placement of right curly braces.
 36  
  * The policy to verify is specified using the {@link RightCurlyOption} class
 37  
  * and defaults to {@link RightCurlyOption#SAME}.
 38  
  * </p>
 39  
  * <p> By default the check will check the following tokens:
 40  
  *  {@link TokenTypes#LITERAL_TRY LITERAL_TRY},
 41  
  *  {@link TokenTypes#LITERAL_CATCH LITERAL_CATCH},
 42  
  *  {@link TokenTypes#LITERAL_FINALLY LITERAL_FINALLY},
 43  
  *  {@link TokenTypes#LITERAL_IF LITERAL_IF},
 44  
  *  {@link TokenTypes#LITERAL_ELSE LITERAL_ELSE}.
 45  
  * Other acceptable tokens are:
 46  
  *  {@link TokenTypes#CLASS_DEF CLASS_DEF},
 47  
  *  {@link TokenTypes#METHOD_DEF METHOD_DEF},
 48  
  *  {@link TokenTypes#CTOR_DEF CTOR_DEF}.
 49  
  *  {@link TokenTypes#LITERAL_FOR LITERAL_FOR}.
 50  
  *  {@link TokenTypes#LITERAL_WHILE LITERAL_WHILE}.
 51  
  *  {@link TokenTypes#LITERAL_DO LITERAL_DO}.
 52  
  *  {@link TokenTypes#STATIC_INIT STATIC_INIT}.
 53  
  *  {@link TokenTypes#INSTANCE_INIT INSTANCE_INIT}.
 54  
  *  {@link TokenTypes#LAMBDA LAMBDA}.
 55  
  * </p>
 56  
  * <p>
 57  
  * <b>shouldStartLine</b> - does the check need to check
 58  
  * if right curly starts line. Default value is <b>true</b>
 59  
  * </p>
 60  
  * <p>
 61  
  * An example of how to configure the check is:
 62  
  * </p>
 63  
  * <pre>
 64  
  * &lt;module name="RightCurly"/&gt;
 65  
  * </pre>
 66  
  * <p>
 67  
  * An example of how to configure the check with policy
 68  
  * {@link RightCurlyOption#ALONE} for {@code else} and
 69  
  * {@code {@link TokenTypes#METHOD_DEF METHOD_DEF}}tokens is:
 70  
  * </p>
 71  
  * <pre>
 72  
  * &lt;module name="RightCurly"&gt;
 73  
  *     &lt;property name="tokens" value="LITERAL_ELSE"/&gt;
 74  
  *     &lt;property name="option" value="alone"/&gt;
 75  
  * &lt;/module&gt;
 76  
  * </pre>
 77  
  *
 78  
  * @author Oliver Burn
 79  
  * @author lkuehne
 80  
  * @author o_sukhodolsky
 81  
  * @author maxvetrenko
 82  
  * @author Andrei Selkin
 83  
  * @author <a href="mailto:piotr.listkiewicz@gmail.com">liscju</a>
 84  
  */
 85  
 @StatelessCheck
 86  36
 public class RightCurlyCheck extends AbstractCheck {
 87  
     /**
 88  
      * A key is pointing to the warning message text in "messages.properties"
 89  
      * file.
 90  
      */
 91  
     public static final String MSG_KEY_LINE_BREAK_BEFORE = "line.break.before";
 92  
 
 93  
     /**
 94  
      * A key is pointing to the warning message text in "messages.properties"
 95  
      * file.
 96  
      */
 97  
     public static final String MSG_KEY_LINE_ALONE = "line.alone";
 98  
 
 99  
     /**
 100  
      * A key is pointing to the warning message text in "messages.properties"
 101  
      * file.
 102  
      */
 103  
     public static final String MSG_KEY_LINE_SAME = "line.same";
 104  
 
 105  
     /**
 106  
      * A key is pointing to the warning message text in "messages.properties"
 107  
      * file.
 108  
      */
 109  
     public static final String MSG_KEY_LINE_NEW = "line.new";
 110  
 
 111  
     /** Do we need to check if right curly starts line. */
 112  36
     private boolean shouldStartLine = true;
 113  
 
 114  
     /** The policy to enforce. */
 115  36
     private RightCurlyOption option = RightCurlyOption.SAME;
 116  
 
 117  
     /**
 118  
      * Sets the option to enforce.
 119  
      * @param optionStr string to decode option from
 120  
      * @throws IllegalArgumentException if unable to decode
 121  
      */
 122  
     public void setOption(String optionStr) {
 123  
         try {
 124  22
             option = RightCurlyOption.valueOf(optionStr.trim().toUpperCase(Locale.ENGLISH));
 125  
         }
 126  1
         catch (IllegalArgumentException iae) {
 127  1
             throw new IllegalArgumentException("unable to parse " + optionStr, iae);
 128  21
         }
 129  21
     }
 130  
 
 131  
     /**
 132  
      * Does the check need to check if right curly starts line.
 133  
      * @param flag new value of this property.
 134  
      */
 135  
     public void setShouldStartLine(boolean flag) {
 136  3
         shouldStartLine = flag;
 137  3
     }
 138  
 
 139  
     @Override
 140  
     public int[] getDefaultTokens() {
 141  18
         return new int[] {
 142  
             TokenTypes.LITERAL_TRY,
 143  
             TokenTypes.LITERAL_CATCH,
 144  
             TokenTypes.LITERAL_FINALLY,
 145  
             TokenTypes.LITERAL_IF,
 146  
             TokenTypes.LITERAL_ELSE,
 147  
         };
 148  
     }
 149  
 
 150  
     @Override
 151  
     public int[] getAcceptableTokens() {
 152  19
         return new int[] {
 153  
             TokenTypes.LITERAL_TRY,
 154  
             TokenTypes.LITERAL_CATCH,
 155  
             TokenTypes.LITERAL_FINALLY,
 156  
             TokenTypes.LITERAL_IF,
 157  
             TokenTypes.LITERAL_ELSE,
 158  
             TokenTypes.CLASS_DEF,
 159  
             TokenTypes.METHOD_DEF,
 160  
             TokenTypes.CTOR_DEF,
 161  
             TokenTypes.LITERAL_FOR,
 162  
             TokenTypes.LITERAL_WHILE,
 163  
             TokenTypes.LITERAL_DO,
 164  
             TokenTypes.STATIC_INIT,
 165  
             TokenTypes.INSTANCE_INIT,
 166  
             TokenTypes.LAMBDA,
 167  
         };
 168  
     }
 169  
 
 170  
     @Override
 171  
     public int[] getRequiredTokens() {
 172  47
         return CommonUtils.EMPTY_INT_ARRAY;
 173  
     }
 174  
 
 175  
     @Override
 176  
     public void visitToken(DetailAST ast) {
 177  343
         final Details details = Details.getDetails(ast);
 178  343
         final DetailAST rcurly = details.rcurly;
 179  
 
 180  343
         if (rcurly != null) {
 181  319
             final String violation = validate(details);
 182  319
             if (!violation.isEmpty()) {
 183  133
                 log(rcurly, violation, "}", rcurly.getColumnNo() + 1);
 184  
             }
 185  
         }
 186  343
     }
 187  
 
 188  
     /**
 189  
      * Does general validation.
 190  
      * @param details for validation.
 191  
      * @return violation message or empty string
 192  
      *     if there was not violation during validation.
 193  
      */
 194  
     private String validate(Details details) {
 195  319
         String violation = "";
 196  319
         if (shouldHaveLineBreakBefore(option, details)) {
 197  7
             violation = MSG_KEY_LINE_BREAK_BEFORE;
 198  
         }
 199  312
         else if (shouldBeOnSameLine(option, details)) {
 200  15
             violation = MSG_KEY_LINE_SAME;
 201  
         }
 202  297
         else if (shouldBeAloneOnLine(option, details)) {
 203  88
             violation = MSG_KEY_LINE_ALONE;
 204  
         }
 205  209
         else if (shouldStartLine) {
 206  197
             final String targetSourceLine = getLines()[details.rcurly.getLineNo() - 1];
 207  197
             if (!isOnStartOfLine(details, targetSourceLine)) {
 208  23
                 violation = MSG_KEY_LINE_NEW;
 209  
             }
 210  
         }
 211  319
         return violation;
 212  
     }
 213  
 
 214  
     /**
 215  
      * Checks whether a right curly should have a line break before.
 216  
      * @param bracePolicy option for placing the right curly brace.
 217  
      * @param details details for validation.
 218  
      * @return true if a right curly should have a line break before.
 219  
      */
 220  
     private static boolean shouldHaveLineBreakBefore(RightCurlyOption bracePolicy,
 221  
                                                      Details details) {
 222  638
         return bracePolicy == RightCurlyOption.SAME
 223  70
                 && !hasLineBreakBefore(details.rcurly)
 224  25
                 && details.lcurly.getLineNo() != details.rcurly.getLineNo();
 225  
     }
 226  
 
 227  
     /**
 228  
      * Checks that a right curly should be on the same line as the next statement.
 229  
      * @param bracePolicy option for placing the right curly brace
 230  
      * @param details Details for validation
 231  
      * @return true if a right curly should be alone on a line.
 232  
      */
 233  
     private static boolean shouldBeOnSameLine(RightCurlyOption bracePolicy, Details details) {
 234  624
         return bracePolicy == RightCurlyOption.SAME
 235  63
                 && !details.shouldCheckLastRcurly
 236  38
                 && details.rcurly.getLineNo() != details.nextToken.getLineNo();
 237  
     }
 238  
 
 239  
     /**
 240  
      * Checks that a right curly should be alone on a line.
 241  
      * @param bracePolicy option for placing the right curly brace
 242  
      * @param details Details for validation
 243  
      * @return true if a right curly should be alone on a line.
 244  
      */
 245  
     private static boolean shouldBeAloneOnLine(RightCurlyOption bracePolicy, Details details) {
 246  594
         return bracePolicy == RightCurlyOption.ALONE
 247  154
                     && shouldBeAloneOnLineWithAloneOption(details)
 248  
                 || bracePolicy == RightCurlyOption.ALONE_OR_SINGLELINE
 249  95
                     && shouldBeAloneOnLineWithAloneOrSinglelineOption(details)
 250  213
                 || details.shouldCheckLastRcurly
 251  68
                     && details.rcurly.getLineNo() == details.nextToken.getLineNo();
 252  
     }
 253  
 
 254  
     /**
 255  
      * Whether right curly should be alone on line when ALONE option is used.
 256  
      * @param details details for validation.
 257  
      * @return true, if right curly should be alone on line when ALONE option is used.
 258  
      */
 259  
     private static boolean shouldBeAloneOnLineWithAloneOption(Details details) {
 260  308
         return !isAloneOnLine(details)
 261  82
                 && !isEmptyBody(details.lcurly);
 262  
     }
 263  
 
 264  
     /**
 265  
      * Whether right curly should be alone on line when ALONE_OR_SINGLELINE option is used.
 266  
      * @param details details for validation.
 267  
      * @return true, if right curly should be alone on line
 268  
      *         when ALONE_OR_SINGLELINE option is used.
 269  
      */
 270  
     private static boolean shouldBeAloneOnLineWithAloneOrSinglelineOption(Details details) {
 271  190
         return !isAloneOnLine(details)
 272  55
                 && !isSingleLineBlock(details)
 273  30
                 && !isAnonInnerClassInit(details.lcurly)
 274  18
                 && !isEmptyBody(details.lcurly);
 275  
     }
 276  
 
 277  
     /**
 278  
      * Whether right curly brace starts target source line.
 279  
      * @param details Details of right curly brace for validation
 280  
      * @param targetSourceLine source line to check
 281  
      * @return true if right curly brace starts target source line.
 282  
      */
 283  
     private static boolean isOnStartOfLine(Details details, String targetSourceLine) {
 284  394
         return CommonUtils.hasWhitespaceBefore(details.rcurly.getColumnNo(), targetSourceLine)
 285  90
                 || details.lcurly.getLineNo() == details.rcurly.getLineNo();
 286  
     }
 287  
 
 288  
     /**
 289  
      * Checks whether right curly is alone on a line.
 290  
      * @param details for validation.
 291  
      * @return true if right curly is alone on a line.
 292  
      */
 293  
     private static boolean isAloneOnLine(Details details) {
 294  249
         final DetailAST rcurly = details.rcurly;
 295  249
         final DetailAST lcurly = details.lcurly;
 296  249
         final DetailAST nextToken = details.nextToken;
 297  498
         return rcurly.getLineNo() != lcurly.getLineNo()
 298  143
             && rcurly.getLineNo() != nextToken.getLineNo();
 299  
     }
 300  
 
 301  
     /**
 302  
      * Checks whether block has a single-line format.
 303  
      * @param details for validation.
 304  
      * @return true if block has single-line format.
 305  
      */
 306  
     private static boolean isSingleLineBlock(Details details) {
 307  55
         final DetailAST rcurly = details.rcurly;
 308  55
         final DetailAST lcurly = details.lcurly;
 309  55
         final DetailAST nextToken = details.nextToken;
 310  110
         return rcurly.getLineNo() == lcurly.getLineNo()
 311  42
             && rcurly.getLineNo() != nextToken.getLineNo();
 312  
     }
 313  
 
 314  
     /**
 315  
      * Checks whether lcurly is in anonymous inner class initialization.
 316  
      * @param lcurly left curly token.
 317  
      * @return true if lcurly begins anonymous inner class initialization.
 318  
      */
 319  
     private static boolean isAnonInnerClassInit(DetailAST lcurly) {
 320  30
         final Scope surroundingScope = ScopeUtils.getSurroundingScope(lcurly);
 321  30
         return surroundingScope.ordinal() == Scope.ANONINNER.ordinal();
 322  
     }
 323  
 
 324  
     /**
 325  
      * Checks if definition body is empty.
 326  
      * @param lcurly left curly.
 327  
      * @return true if definition body is empty.
 328  
      */
 329  
     private static boolean isEmptyBody(DetailAST lcurly) {
 330  100
         boolean result = false;
 331  100
         if (lcurly.getParent().getType() == TokenTypes.OBJBLOCK) {
 332  6
             if (lcurly.getNextSibling().getType() == TokenTypes.RCURLY) {
 333  3
                 result = true;
 334  
             }
 335  
         }
 336  94
         else if (lcurly.getFirstChild().getType() == TokenTypes.RCURLY) {
 337  13
             result = true;
 338  
         }
 339  100
         return result;
 340  
     }
 341  
 
 342  
     /**
 343  
      * Checks if right curly has line break before.
 344  
      * @param rightCurly right curly token.
 345  
      * @return true, if right curly has line break before.
 346  
      */
 347  
     private static boolean hasLineBreakBefore(DetailAST rightCurly) {
 348  70
         final DetailAST previousToken = rightCurly.getPreviousSibling();
 349  140
         return previousToken == null
 350  57
                 || rightCurly.getLineNo() != previousToken.getLineNo();
 351  
     }
 352  
 
 353  
     /**
 354  
      * Structure that contains all details for validation.
 355  
      */
 356  2910
     private static final class Details {
 357  
 
 358  
         /** Right curly. */
 359  
         private final DetailAST rcurly;
 360  
         /** Left curly. */
 361  
         private final DetailAST lcurly;
 362  
         /** Next token. */
 363  
         private final DetailAST nextToken;
 364  
         /** Should check last right curly. */
 365  
         private final boolean shouldCheckLastRcurly;
 366  
 
 367  
         /**
 368  
          * Constructor.
 369  
          * @param lcurly the lcurly of the token whose details are being collected
 370  
          * @param rcurly the rcurly of the token whose details are being collected
 371  
          * @param nextToken the token after the token whose details are being collected
 372  
          * @param shouldCheckLastRcurly boolean value to determine if to check last rcurly
 373  
          */
 374  
         private Details(DetailAST lcurly, DetailAST rcurly,
 375  343
                         DetailAST nextToken, boolean shouldCheckLastRcurly) {
 376  343
             this.lcurly = lcurly;
 377  343
             this.rcurly = rcurly;
 378  343
             this.nextToken = nextToken;
 379  343
             this.shouldCheckLastRcurly = shouldCheckLastRcurly;
 380  343
         }
 381  
 
 382  
         /**
 383  
          * Collects validation Details.
 384  
          * @param ast a {@code DetailAST} value
 385  
          * @return object containing all details to make a validation
 386  
          */
 387  
         private static Details getDetails(DetailAST ast) {
 388  
             final Details details;
 389  343
             switch (ast.getType()) {
 390  
                 case TokenTypes.LITERAL_TRY:
 391  
                 case TokenTypes.LITERAL_CATCH:
 392  
                 case TokenTypes.LITERAL_FINALLY:
 393  68
                     details = getDetailsForTryCatchFinally(ast);
 394  68
                     break;
 395  
                 case TokenTypes.LITERAL_IF:
 396  
                 case TokenTypes.LITERAL_ELSE:
 397  65
                     details = getDetailsForIfElse(ast);
 398  65
                     break;
 399  
                 case TokenTypes.LITERAL_DO:
 400  
                 case TokenTypes.LITERAL_WHILE:
 401  
                 case TokenTypes.LITERAL_FOR:
 402  35
                     details = getDetailsForLoops(ast);
 403  35
                     break;
 404  
                 case TokenTypes.LAMBDA:
 405  47
                     details = getDetailsForLambda(ast);
 406  47
                     break;
 407  
                 default:
 408  128
                     details = getDetailsForOthers(ast);
 409  
                     break;
 410  
             }
 411  343
             return details;
 412  
         }
 413  
 
 414  
         /**
 415  
          * Collects validation details for LITERAL_TRY, LITERAL_CATCH, and LITERAL_FINALLY.
 416  
          * @param ast a {@code DetailAST} value
 417  
          * @return object containing all details to make a validation
 418  
          */
 419  
         private static Details getDetailsForTryCatchFinally(DetailAST ast) {
 420  68
             boolean shouldCheckLastRcurly = false;
 421  
             final DetailAST rcurly;
 422  
             final DetailAST lcurly;
 423  
             DetailAST nextToken;
 424  68
             final int tokenType = ast.getType();
 425  68
             if (tokenType == TokenTypes.LITERAL_TRY) {
 426  36
                 if (ast.getFirstChild().getType() == TokenTypes.RESOURCE_SPECIFICATION) {
 427  24
                     lcurly = ast.getFirstChild().getNextSibling();
 428  
                 }
 429  
                 else {
 430  12
                     lcurly = ast.getFirstChild();
 431  
                 }
 432  36
                 nextToken = lcurly.getNextSibling();
 433  36
                 rcurly = lcurly.getLastChild();
 434  
 
 435  36
                 if (nextToken == null) {
 436  12
                     shouldCheckLastRcurly = true;
 437  12
                     nextToken = getNextToken(ast);
 438  
                 }
 439  
             }
 440  32
             else if (tokenType == TokenTypes.LITERAL_CATCH) {
 441  23
                 nextToken = ast.getNextSibling();
 442  23
                 lcurly = ast.getLastChild();
 443  23
                 rcurly = lcurly.getLastChild();
 444  23
                 if (nextToken == null) {
 445  15
                     shouldCheckLastRcurly = true;
 446  15
                     nextToken = getNextToken(ast);
 447  
                 }
 448  
 
 449  
             }
 450  
             else {
 451  9
                 shouldCheckLastRcurly = true;
 452  9
                 nextToken = getNextToken(ast);
 453  9
                 lcurly = ast.getFirstChild();
 454  9
                 rcurly = lcurly.getLastChild();
 455  
             }
 456  68
             return new Details(lcurly, rcurly, nextToken, shouldCheckLastRcurly);
 457  
         }
 458  
 
 459  
         /**
 460  
          * Collects validation details for LITERAL_IF and LITERAL_ELSE.
 461  
          * @param ast a {@code DetailAST} value
 462  
          * @return object containing all details to make a validation
 463  
          */
 464  
         private static Details getDetailsForIfElse(DetailAST ast) {
 465  65
             boolean shouldCheckLastRcurly = false;
 466  65
             DetailAST rcurly = null;
 467  
             final DetailAST lcurly;
 468  
             DetailAST nextToken;
 469  65
             final int tokenType = ast.getType();
 470  65
             if (tokenType == TokenTypes.LITERAL_IF) {
 471  43
                 nextToken = ast.findFirstToken(TokenTypes.LITERAL_ELSE);
 472  43
                 if (nextToken == null) {
 473  21
                     shouldCheckLastRcurly = true;
 474  21
                     nextToken = getNextToken(ast);
 475  21
                     lcurly = ast.getLastChild();
 476  
                 }
 477  
                 else {
 478  22
                     lcurly = nextToken.getPreviousSibling();
 479  
                 }
 480  43
                 if (lcurly.getType() == TokenTypes.SLIST) {
 481  38
                     rcurly = lcurly.getLastChild();
 482  
                 }
 483  
 
 484  
             }
 485  
             else {
 486  22
                 shouldCheckLastRcurly = true;
 487  22
                 nextToken = getNextToken(ast);
 488  22
                 lcurly = ast.getFirstChild();
 489  22
                 if (lcurly.getType() == TokenTypes.SLIST) {
 490  9
                     rcurly = lcurly.getLastChild();
 491  
                 }
 492  
             }
 493  65
             return new Details(lcurly, rcurly, nextToken, shouldCheckLastRcurly);
 494  
         }
 495  
 
 496  
         /**
 497  
          * Collects validation details for CLASS_DEF, METHOD DEF, CTOR_DEF, STATIC_INIT, and
 498  
          * INSTANCE_INIT.
 499  
          * @param ast a {@code DetailAST} value
 500  
          * @return an object containing all details to make a validation
 501  
          */
 502  
         private static Details getDetailsForOthers(DetailAST ast) {
 503  128
             DetailAST rcurly = null;
 504  
             final DetailAST lcurly;
 505  
             final DetailAST nextToken;
 506  128
             final int tokenType = ast.getType();
 507  128
             if (tokenType == TokenTypes.CLASS_DEF) {
 508  21
                 final DetailAST child = ast.getLastChild();
 509  21
                 lcurly = child.getFirstChild();
 510  21
                 rcurly = child.getLastChild();
 511  21
                 nextToken = ast;
 512  21
             }
 513  107
             else if (tokenType == TokenTypes.METHOD_DEF) {
 514  78
                 lcurly = ast.findFirstToken(TokenTypes.SLIST);
 515  78
                 if (lcurly != null) {
 516  
                     // SLIST could be absent if method is abstract
 517  77
                     rcurly = lcurly.getLastChild();
 518  
                 }
 519  78
                 nextToken = getNextToken(ast);
 520  
             }
 521  
             else {
 522  29
                 lcurly = ast.findFirstToken(TokenTypes.SLIST);
 523  29
                 rcurly = lcurly.getLastChild();
 524  29
                 nextToken = getNextToken(ast);
 525  
             }
 526  128
             return new Details(lcurly, rcurly, nextToken, false);
 527  
         }
 528  
 
 529  
         /**
 530  
          * Collects validation details for loops' tokens.
 531  
          * @param ast a {@code DetailAST} value
 532  
          * @return an object containing all details to make a validation
 533  
          */
 534  
         private static Details getDetailsForLoops(DetailAST ast) {
 535  35
             DetailAST rcurly = null;
 536  
             final DetailAST lcurly;
 537  
             final DetailAST nextToken;
 538  35
             final int tokenType = ast.getType();
 539  35
             if (tokenType == TokenTypes.LITERAL_DO) {
 540  17
                 nextToken = ast.findFirstToken(TokenTypes.DO_WHILE);
 541  17
                 lcurly = ast.findFirstToken(TokenTypes.SLIST);
 542  17
                 if (lcurly != null) {
 543  16
                     rcurly = lcurly.getLastChild();
 544  
                 }
 545  
             }
 546  
             else {
 547  18
                 lcurly = ast.findFirstToken(TokenTypes.SLIST);
 548  18
                 if (lcurly != null) {
 549  
                     // SLIST could be absent in code like "while(true);"
 550  17
                     rcurly = lcurly.getLastChild();
 551  
                 }
 552  18
                 nextToken = getNextToken(ast);
 553  
             }
 554  35
             return new Details(lcurly, rcurly, nextToken, false);
 555  
         }
 556  
 
 557  
         /**
 558  
          * Collects validation details for Lambdas.
 559  
          * @param ast a {@code DetailAST} value
 560  
          * @return an object containing all details to make a validation
 561  
          */
 562  
         private static Details getDetailsForLambda(DetailAST ast) {
 563  47
             final DetailAST lcurly = ast.findFirstToken(TokenTypes.SLIST);
 564  47
             boolean shouldCheckLastRcurly = false;
 565  47
             DetailAST nextToken = getNextToken(ast);
 566  47
             if (nextToken.getType() != TokenTypes.RPAREN
 567  32
                     && nextToken.getType() != TokenTypes.COMMA) {
 568  27
                 shouldCheckLastRcurly = true;
 569  27
                 nextToken = getNextToken(nextToken);
 570  
             }
 571  47
             DetailAST rcurly = null;
 572  47
             if (lcurly != null) {
 573  44
                 rcurly = lcurly.getLastChild();
 574  
             }
 575  47
             return new Details(lcurly, rcurly, nextToken, shouldCheckLastRcurly);
 576  
         }
 577  
 
 578  
         /**
 579  
          * Finds next token after the given one.
 580  
          * @param ast the given node.
 581  
          * @return the token which represents next lexical item.
 582  
          */
 583  
         private static DetailAST getNextToken(DetailAST ast) {
 584  278
             DetailAST next = null;
 585  278
             DetailAST parent = ast;
 586  683
             while (next == null) {
 587  405
                 next = parent.getNextSibling();
 588  405
                 parent = parent.getParent();
 589  
             }
 590  278
             return CheckUtils.getFirstNode(next);
 591  
         }
 592  
     }
 593  
 }