001///////////////////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code and other text files for adherence to a set of rules.
003// Copyright (C) 2001-2026 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 */
029public class TryHandler extends BlockParentHandler {
030
031    /**
032     * Construct an instance of this handler with the given indentation check,
033     * abstract syntax tree, and parent handler.
034     *
035     * @param indentCheck   the indentation check
036     * @param ast           the abstract syntax tree
037     * @param parent        the parent handler
038     */
039    public TryHandler(IndentationCheck indentCheck,
040        DetailAST ast, AbstractExpressionHandler parent) {
041        super(indentCheck, "try", ast, parent);
042    }
043
044    /**
045     * Method to find left parenthesis of try with resources.
046     *
047     * @return DetailAst    left parenthesis of try with resources
048     */
049    private DetailAST getTryResLparen() {
050        return getMainAst().getFirstChild().getFirstChild();
051    }
052
053    /**
054     * Method to find right parenthesis of try with resources.
055     *
056     * @return DetailAst    right parenthesis of try with resources
057     */
058    private DetailAST getTryResRparen() {
059        return getMainAst().getFirstChild().getLastChild();
060    }
061
062    @Override
063    public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) {
064        final IndentLevel result;
065        if (child instanceof CatchHandler
066            || child instanceof FinallyHandler
067            || child instanceof NewHandler
068                && isTryBlocksResourceSpecification(child)) {
069            result = getIndent();
070        }
071        else {
072            result = super.getSuggestedChildIndent(child);
073        }
074        return result;
075    }
076
077    @Override
078    public void checkIndentation() {
079        super.checkIndentation();
080        if (getMainAst().getFirstChild().getType() == TokenTypes.RESOURCE_SPECIFICATION) {
081            checkTryResParen(getTryResLparen(), "lparen");
082            checkTryResParen(getTryResRparen(), "rparen");
083            checkTryResources(getMainAst().getFirstChild());
084        }
085    }
086
087    @Override
088    protected boolean shouldCheckIndentationForChild(DetailAST child) {
089        final DetailAST leftCurly = getLeftCurly();
090        return getFirstAstNode(child).getLineNo() != leftCurly.getLineNo();
091    }
092
093    /**
094     * Method to check the indentation of left paren or right paren.
095     * This method itself checks whether either of these are on start of line. This method
096     * takes care of line wrapping strict condition as well.
097     *
098     * @param parenAst      lparen or rparen ast to check
099     * @param subType       name to be used in log message
100     */
101    private void checkTryResParen(final DetailAST parenAst,
102                                    final String subType) {
103        if (isOnStartOfLine(parenAst)) {
104            final IndentLevel expectedIdent = new IndentLevel(getIndent(), 0,
105                getIndentCheck().getLineWrappingIndentation());
106
107            checkChildIndentation(parenAst, subType, expectedIdent);
108        }
109    }
110
111    /**
112     * Method to check indentation of try resources children.
113     * It takes into account forceStrictCondition value when logging violations.
114     * Example of usage would include checking for try parenthesis and try resources.
115     *
116     * @param ast           AST to check.
117     * @param subType       String representing child type.
118     * @param expectedIdent Expected indent level.
119     */
120    private void checkChildIndentation(DetailAST ast, String subType, IndentLevel expectedIdent) {
121        if (getIndentCheck().isForceStrictCondition()) {
122            if (!expectedIdent.isAcceptable(expandedTabsColumnNo(ast))) {
123                logError(ast, subType, expandedTabsColumnNo(ast), expectedIdent);
124            }
125        }
126        else {
127            if (expandedTabsColumnNo(ast) < expectedIdent.getFirstIndentLevel()) {
128                logError(ast, subType, expandedTabsColumnNo(ast), expectedIdent);
129            }
130        }
131    }
132
133    /**
134     * Checks indentation of resources parameters in try resources.
135     *
136     * @param resourcesSpecAst   Resource specification ast
137     */
138    private void checkTryResources(final DetailAST resourcesSpecAst) {
139        final DetailAST resourcesAst = resourcesSpecAst.findFirstToken(TokenTypes.RESOURCES);
140        final int indentation = getIndent().getFirstIndentLevel()
141            + getIndentCheck().getLineWrappingIndentation();
142        final IndentLevel expectedResourceIndent = new IndentLevel(indentation);
143
144        final String subType = "resource";
145
146        DetailAST resourceAst = resourcesAst.getFirstChild();
147        while (resourceAst != null) {
148            if (resourceAst.getType() == TokenTypes.RESOURCE) {
149                final DetailAST nextSibling;
150                if (resourceAst.getNextSibling() == null) {
151                    nextSibling = getTryResRparen();
152                }
153                else {
154                    nextSibling = resourceAst.getNextSibling();
155                }
156                if (isOnStartOfLine(resourceAst)) {
157                    checkChildIndentation(resourceAst, subType, expectedResourceIndent);
158                    checkWrappingIndentation(
159                        resourceAst,
160                        nextSibling,
161                        getIndentCheck().getLineWrappingIndentation(),
162                        expectedResourceIndent.getFirstIndentLevel(),
163                        true);
164                }
165                else {
166                    checkWrappingIndentation(resourceAst, nextSibling);
167                }
168            }
169            resourceAst = resourceAst.getNextSibling();
170        }
171    }
172
173    /**
174     * Check if the expression is resource of
175     * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20.3">
176     * try block</a>.
177     *
178     * @param expression The expression to check
179     * @return if the expression provided is try block's resource specification.
180     */
181    private static boolean isTryBlocksResourceSpecification(AbstractExpressionHandler expression) {
182        boolean isResourceSpecificationExpression = false;
183
184        DetailAST ast = expression.getMainAst();
185
186        while (ast.getType() != TokenTypes.LITERAL_TRY) {
187            if (ast.getType() == TokenTypes.RESOURCE_SPECIFICATION) {
188                isResourceSpecificationExpression = true;
189                break;
190            }
191
192            ast = ast.getParent();
193        }
194
195        return isResourceSpecificationExpression;
196    }
197
198}