001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2018 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;
024
025/**
026 * Handler for try blocks.
027 *
028 * @author jrichard
029 */
030public class TryHandler extends BlockParentHandler {
031
032    /**
033     * Construct an instance of this handler with the given indentation check,
034     * abstract syntax tree, and parent handler.
035     *
036     * @param indentCheck   the indentation check
037     * @param ast           the abstract syntax tree
038     * @param parent        the parent handler
039     */
040    public TryHandler(IndentationCheck indentCheck,
041        DetailAST ast, AbstractExpressionHandler parent) {
042        super(indentCheck, "try", ast, parent);
043    }
044
045    /**
046     * Method to find left parenthesis of try with resources.
047     *
048     * @return DetailAst    left parenthesis of try with resources
049     */
050    private DetailAST getTryResLparen() {
051        return getMainAst().getFirstChild().getFirstChild();
052    }
053
054    /**
055     * Method to find right parenthesis of try with resources.
056     *
057     * @return DetailAst    right parenthesis of try with resources
058     */
059    private DetailAST getTryResRparen() {
060        return getMainAst().getFirstChild().getLastChild();
061    }
062
063    @Override
064    public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) {
065        final IndentLevel result;
066        if (child instanceof CatchHandler
067            || child instanceof FinallyHandler) {
068            result = getIndent();
069        }
070        else {
071            result = super.getSuggestedChildIndent(child);
072        }
073        return result;
074    }
075
076    @Override
077    public void checkIndentation() {
078        super.checkIndentation();
079        if (getMainAst().getFirstChild().getType() == TokenTypes.RESOURCE_SPECIFICATION) {
080            checkTryResParen(getTryResLparen(), "lparen");
081            checkTryResParen(getTryResRparen(), "rparen");
082            checkTryResources(getMainAst().getFirstChild());
083        }
084    }
085
086    /**
087     * Method to check the indentation of left paren or right paren.
088     * This method itself checks whether either of these are on start of line. This method
089     * takes care of line wrapping strict condition as well.
090     *
091     * @param parenAst      lparen or rparen ast to check
092     * @param subType       name to be used in log message
093     */
094    private void checkTryResParen(final DetailAST parenAst,
095                                    final String subType) {
096        if (isOnStartOfLine(parenAst)) {
097            final IndentLevel expectedIdent = new IndentLevel(getIndent(), 0,
098                getIndentCheck().getLineWrappingIndentation());
099
100            checkChildIndentation(parenAst, subType, expectedIdent);
101        }
102    }
103
104    /**
105     * Method to check indentation of try resources children.
106     * It takes into account forceStrictCondition value when logging errors.
107     * Example of usage would include checking for try parenthesis and try resources.
108     *
109     * @param ast           AST to check.
110     * @param subType       String representing child type.
111     * @param expectedIdent Expected indent level.
112     */
113    private void checkChildIndentation(DetailAST ast, String subType, IndentLevel expectedIdent) {
114        if (getIndentCheck().isForceStrictCondition()) {
115            if (!expectedIdent.isAcceptable(expandedTabsColumnNo(ast))) {
116                logError(ast, subType, expandedTabsColumnNo(ast), expectedIdent);
117            }
118        }
119        else {
120            if (expandedTabsColumnNo(ast) < expectedIdent.getFirstIndentLevel()) {
121                logError(ast, subType, expandedTabsColumnNo(ast), expectedIdent);
122            }
123        }
124    }
125
126    /**
127     * Checks indentation of resources parameters in try resources.
128     *
129     * @param resourcesSpecAst   Resource specification ast
130     */
131    private void checkTryResources(final DetailAST resourcesSpecAst) {
132        final DetailAST resourcesAst = resourcesSpecAst.findFirstToken(TokenTypes.RESOURCES);
133        final int indentation = getIndent().getFirstIndentLevel()
134            + getIndentCheck().getLineWrappingIndentation();
135        final IndentLevel expectedResourceIndent = new IndentLevel(indentation);
136
137        final String subType = "resource";
138
139        DetailAST resourceAst = resourcesAst.getFirstChild();
140        while (resourceAst != null) {
141            if (resourceAst.getType() == TokenTypes.RESOURCE) {
142                final DetailAST nextSibling;
143                if (resourceAst.getNextSibling() == null) {
144                    nextSibling = getTryResRparen();
145                }
146                else {
147                    nextSibling = resourceAst.getNextSibling();
148                }
149                if (isOnStartOfLine(resourceAst)) {
150                    checkChildIndentation(resourceAst, subType, expectedResourceIndent);
151                    checkWrappingIndentation(
152                        resourceAst,
153                        nextSibling,
154                        getIndentCheck().getLineWrappingIndentation(),
155                        expectedResourceIndent.getFirstIndentLevel(),
156                        true);
157                }
158                else {
159                    checkWrappingIndentation(resourceAst, nextSibling);
160                }
161            }
162            resourceAst = resourceAst.getNextSibling();
163        }
164    }
165
166}