001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2020 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, "operator 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                && !isNewKeywordFollowedByAssign()) {
054            final int columnNo = expandedTabsColumnNo(mainAst);
055            final IndentLevel level = getIndentImpl();
056
057            if (columnNo < level.getFirstIndentLevel()) {
058                logError(mainAst, "", columnNo, level);
059            }
060        }
061
062        final DetailAST firstChild = mainAst.getFirstChild();
063        if (firstChild != null) {
064            checkExpressionSubtree(firstChild, getIndent(), false, false);
065        }
066
067        final DetailAST lparen = mainAst.findFirstToken(TokenTypes.LPAREN);
068        checkLeftParen(lparen);
069    }
070
071    @Override
072    public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) {
073        final int offset;
074        if (TokenUtil.isOfType(child.getMainAst(), TokenTypes.OBJBLOCK)) {
075            offset = getBasicOffset();
076        }
077        else {
078            offset = getLineWrappingIndent();
079        }
080        return new IndentLevel(getIndent(), offset);
081    }
082
083    @Override
084    protected IndentLevel getIndentImpl() {
085        IndentLevel result;
086        // if our expression isn't first on the line, just use the start
087        // of the line
088        if (getLineStart(mainAst) == mainAst.getColumnNo()) {
089            result = super.getIndentImpl();
090
091            if (isNewKeywordFollowedByAssign()) {
092                result = new IndentLevel(result, getLineWrappingIndent());
093            }
094        }
095        else {
096            result = new IndentLevel(getLineStart(mainAst));
097        }
098
099        return result;
100    }
101
102    /**
103     * Checks if the 'new' keyword is followed by an assignment.
104     *
105     * @return true if new keyword is followed by assignment.
106     */
107    private boolean isNewKeywordFollowedByAssign() {
108        return mainAst.getParent().getParent().getType() == TokenTypes.ASSIGN;
109    }
110
111    /**
112     * A shortcut for {@code IndentationCheck} property.
113     *
114     * @return value of lineWrappingIndentation property
115     *         of {@code IndentationCheck}
116     */
117    private int getLineWrappingIndent() {
118        return getIndentCheck().getLineWrappingIndentation();
119    }
120
121    @Override
122    protected boolean shouldIncreaseIndent() {
123        return false;
124    }
125
126}