001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2024 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018/////////////////////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.checks.indentation; 021 022import com.puppycrawl.tools.checkstyle.api.DetailAST; 023import com.puppycrawl.tools.checkstyle.api.TokenTypes; 024import com.puppycrawl.tools.checkstyle.utils.TokenUtil; 025 026/** 027 * Handler for operator new. 028 */ 029public class NewHandler extends AbstractExpressionHandler { 030 031 /** The AST which is handled by this handler. */ 032 private final DetailAST mainAst; 033 034 /** 035 * Construct an instance of this handler with the given indentation check, 036 * abstract syntax tree, and parent handler. 037 * 038 * @param indentCheck the indentation check 039 * @param ast the abstract syntax tree 040 * @param parent the parent handler 041 */ 042 public NewHandler(IndentationCheck indentCheck, 043 DetailAST ast, 044 AbstractExpressionHandler parent) { 045 super(indentCheck, "new", ast, parent); 046 mainAst = ast; 047 } 048 049 @Override 050 public void checkIndentation() { 051 // if new is on the line start and it is not the part of assignment. 052 if (isOnStartOfLine(mainAst)) { 053 final int columnNo = expandedTabsColumnNo(mainAst); 054 final IndentLevel level = getIndentImpl(); 055 056 final boolean forceStrictCondition = getIndentCheck().isForceStrictCondition(); 057 if (forceStrictCondition && !level.isAcceptable(columnNo) 058 || !forceStrictCondition && level.isGreaterThan(columnNo)) { 059 logError(mainAst, "", columnNo, level); 060 } 061 } 062 063 final DetailAST firstChild = mainAst.getFirstChild(); 064 if (firstChild != null) { 065 checkExpressionSubtree(firstChild, getIndent(), false, false); 066 } 067 068 final DetailAST lparen = mainAst.findFirstToken(TokenTypes.LPAREN); 069 checkLeftParen(lparen); 070 } 071 072 @Override 073 public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) { 074 final int offset; 075 if (TokenUtil.isOfType(child.getMainAst(), TokenTypes.OBJBLOCK)) { 076 offset = getBasicOffset(); 077 } 078 else { 079 offset = getLineWrappingIndent(); 080 } 081 return new IndentLevel(getIndent(), offset); 082 } 083 084 @Override 085 protected IndentLevel getIndentImpl() { 086 IndentLevel result; 087 // if our expression isn't first on the line, just use the start 088 // of the line 089 if (getLineStart(mainAst) == mainAst.getColumnNo()) { 090 result = super.getIndentImpl(); 091 092 final boolean isLineWrappedNew = TokenUtil.isOfType(mainAst.getParent().getParent(), 093 TokenTypes.ASSIGN, TokenTypes.LITERAL_RETURN); 094 095 if (isLineWrappedNew || doesChainedMethodNeedsLineWrapping()) { 096 result = new IndentLevel(result, getLineWrappingIndent()); 097 } 098 } 099 else { 100 result = new IndentLevel(getLineStart(mainAst)); 101 } 102 103 return result; 104 } 105 106 /** 107 * A shortcut for {@code IndentationCheck} property. 108 * 109 * @return value of lineWrappingIndentation property 110 * of {@code IndentationCheck} 111 */ 112 private int getLineWrappingIndent() { 113 return getIndentCheck().getLineWrappingIndentation(); 114 } 115 116 @Override 117 protected boolean shouldIncreaseIndent() { 118 return false; 119 } 120 121 /** 122 * The function checks if the new keyword is a child of chained method calls, 123 * it checks if the new is directly followed by equal operator or return operator. 124 * 125 * @return true if the new it is chained method calls and new keyword is directly followed 126 * by assign or return 127 */ 128 private boolean doesChainedMethodNeedsLineWrapping() { 129 DetailAST ast = mainAst.getParent(); 130 131 while (TokenUtil.isOfType(ast, TokenTypes.DOT, TokenTypes.METHOD_CALL, TokenTypes.EXPR)) { 132 ast = ast.getParent(); 133 } 134 135 return TokenUtil.isOfType(ast, TokenTypes.ASSIGN, TokenTypes.LITERAL_RETURN); 136 } 137 138}