
com.puppycrawl.tools.checkstyle.checks.indentation.BlockParentHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of checkstyle Show documentation
Show all versions of checkstyle Show documentation
Checkstyle is a development tool to help programmers write Java code
that adheres to a coding standard
///////////////////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code and other text files for adherence to a set of rules.
// Copyright (C) 2001-2025 the original author or authors.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
///////////////////////////////////////////////////////////////////////////////////////////////
package com.puppycrawl.tools.checkstyle.checks.indentation;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
/**
* Handler for parents of blocks ('if', 'else', 'while', etc).
*
*
* The "block" handler classes use a common superclass BlockParentHandler,
* employing the Template Method pattern.
*
*
*
* - template method to get the lcurly
* - template method to get the rcurly
* - if curlies aren't present, then template method to get expressions
* is called
* - now all the repetitious code which checks for BOL, if curlies are on
* same line, etc. can be collapsed into the superclass
*
*
*
*/
public class BlockParentHandler extends AbstractExpressionHandler {
/**
* Children checked by parent handlers.
*/
private static final int[] CHECKED_CHILDREN = {
TokenTypes.VARIABLE_DEF,
TokenTypes.EXPR,
TokenTypes.ANNOTATION,
TokenTypes.OBJBLOCK,
TokenTypes.LITERAL_BREAK,
TokenTypes.LITERAL_RETURN,
TokenTypes.LITERAL_THROW,
TokenTypes.LITERAL_CONTINUE,
TokenTypes.CTOR_CALL,
TokenTypes.SUPER_CTOR_CALL,
};
/**
* Construct an instance of this handler with the given indentation check,
* name, abstract syntax tree, and parent handler.
*
* @param indentCheck the indentation check
* @param name the name of the handler
* @param ast the abstract syntax tree
* @param parent the parent handler
* @noinspection WeakerAccess
* @noinspectionreason WeakerAccess - we avoid 'protected' when possible
*/
public BlockParentHandler(IndentationCheck indentCheck,
String name, DetailAST ast, AbstractExpressionHandler parent) {
super(indentCheck, name, ast, parent);
}
/**
* Returns array of token types which should be checked among children.
*
* @return array of token types to check.
*/
protected int[] getCheckedChildren() {
return CHECKED_CHILDREN.clone();
}
/**
* Get the top level expression being managed by this handler.
*
* @return the top level expression
*/
protected DetailAST getTopLevelAst() {
return getMainAst();
}
/**
* Check the indent of the top level token.
*/
protected void checkTopLevelToken() {
final DetailAST topLevel = getTopLevelAst();
if (topLevel != null
&& !getIndent().isAcceptable(expandedTabsColumnNo(topLevel))
&& isOnStartOfLine(topLevel)) {
logError(topLevel, "", expandedTabsColumnNo(topLevel));
}
}
/**
* Determines if this block expression has curly braces.
*
* @return true if curly braces are present, false otherwise
*/
private boolean hasCurlies() {
return getLeftCurly() != null && getRightCurly() != null;
}
/**
* Get the left curly brace portion of the expression we are handling.
*
* @return the left curly brace expression
*/
protected DetailAST getLeftCurly() {
return getMainAst().findFirstToken(TokenTypes.SLIST);
}
/**
* Get the right curly brace portion of the expression we are handling.
*
* @return the right curly brace expression
*/
protected DetailAST getRightCurly() {
final DetailAST slist = getMainAst().findFirstToken(TokenTypes.SLIST);
return slist.findFirstToken(TokenTypes.RCURLY);
}
/**
* Check the indentation of the left curly brace.
*/
private void checkLeftCurly() {
// the lcurly can either be at the correct indentation, or nested
// with a previous expression
final DetailAST lcurly = getLeftCurly();
final int lcurlyPos = expandedTabsColumnNo(lcurly);
if (!curlyIndent().isAcceptable(lcurlyPos) && isOnStartOfLine(lcurly)) {
logError(lcurly, "lcurly", lcurlyPos, curlyIndent());
}
}
/**
* Get the expected indentation level for the curly braces.
*
* @return the curly brace indentation level
*/
protected IndentLevel curlyIndent() {
final DetailAST lcurly = getLeftCurly();
IndentLevel expIndentLevel = new IndentLevel(getIndent(), getBraceAdjustment());
if (!isOnStartOfLine(lcurly)
|| lcurly.getParent().getType() == TokenTypes.INSTANCE_INIT) {
expIndentLevel = new IndentLevel(getIndent(), 0);
}
return expIndentLevel;
}
/**
* Determines if child elements within the expression may be nested.
*
* @return false
*/
protected boolean canChildrenBeNested() {
return false;
}
/**
* Check the indentation of the right curly brace.
*/
private void checkRightCurly() {
final DetailAST rcurly = getRightCurly();
final int rcurlyPos = expandedTabsColumnNo(rcurly);
if (!curlyIndent().isAcceptable(rcurlyPos)
&& isOnStartOfLine(rcurly)) {
logError(rcurly, "rcurly", rcurlyPos, curlyIndent());
}
}
/**
* Get the child element that is not a list of statements.
*
* @return the non-list child element
*/
protected DetailAST getNonListChild() {
return getMainAst().findFirstToken(TokenTypes.RPAREN).getNextSibling();
}
/**
* Check the indentation level of a child that is not a list of statements.
*/
private void checkNonListChild() {
final DetailAST nonList = getNonListChild();
if (nonList != null) {
final IndentLevel expected = new IndentLevel(getIndent(), getBasicOffset());
checkExpressionSubtree(nonList, expected, false, false);
final DetailAST nonListStartAst = getFirstAstNode(nonList);
if (nonList != nonListStartAst) {
checkExpressionSubtree(nonListStartAst, expected, false, false);
}
}
}
/**
* Get the child element representing the list of statements.
*
* @return the statement list child
*/
protected DetailAST getListChild() {
return getMainAst().findFirstToken(TokenTypes.SLIST);
}
/**
* Get the right parenthesis portion of the expression we are handling.
*
* @return the right parenthesis expression
*/
private DetailAST getRightParen() {
return getMainAst().findFirstToken(TokenTypes.RPAREN);
}
/**
* Get the left parenthesis portion of the expression we are handling.
*
* @return the left parenthesis expression
*/
private DetailAST getLeftParen() {
return getMainAst().findFirstToken(TokenTypes.LPAREN);
}
@Override
public void checkIndentation() {
checkTopLevelToken();
// separate to allow for eventual configuration
checkLeftParen(getLeftParen());
checkRightParen(getLeftParen(), getRightParen());
if (hasCurlies()) {
checkLeftCurly();
checkRightCurly();
}
final DetailAST listChild = getListChild();
if (listChild == null) {
checkNonListChild();
}
else {
// NOTE: switch statements usually don't have curlies
if (!hasCurlies() || !TokenUtil.areOnSameLine(getLeftCurly(), getRightCurly())) {
checkChildren(listChild,
getCheckedChildren(),
getChildrenExpectedIndent(),
true,
canChildrenBeNested());
}
}
}
/**
* Gets indentation level expected for children.
*
* @return indentation level expected for children
*/
protected IndentLevel getChildrenExpectedIndent() {
IndentLevel indentLevel = new IndentLevel(getIndent(), getBasicOffset());
// if we have multileveled expected level then we should
// try to suggest single level to children using curlies'
// levels.
if (getIndent().isMultiLevel() && hasCurlies()) {
if (isOnStartOfLine(getLeftCurly())) {
indentLevel = new IndentLevel(expandedTabsColumnNo(getLeftCurly())
+ getBasicOffset());
}
else if (isOnStartOfLine(getRightCurly())) {
final IndentLevel level = new IndentLevel(curlyIndent(), getBasicOffset());
indentLevel = IndentLevel.addAcceptable(level, level.getFirstIndentLevel()
+ getLineWrappingIndent());
}
}
if (hasCurlies() && isOnStartOfLine(getLeftCurly())) {
indentLevel = IndentLevel.addAcceptable(indentLevel,
curlyIndent().getFirstIndentLevel() + getBasicOffset());
}
return indentLevel;
}
@Override
public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) {
return getChildrenExpectedIndent();
}
/**
* A shortcut for {@code IndentationCheck} property.
*
* @return value of lineWrappingIndentation property
* of {@code IndentationCheck}
*/
private int getLineWrappingIndent() {
return getIndentCheck().getLineWrappingIndentation();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy