1 ///////////////////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3 // Copyright (C) 2001-2025 the original author or authors.
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ///////////////////////////////////////////////////////////////////////////////////////////////
19
20 package com.puppycrawl.tools.checkstyle.checks.indentation;
21
22 import com.puppycrawl.tools.checkstyle.api.DetailAST;
23 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
24
25 /**
26 * Handler for try blocks.
27 *
28 */
29 public class TryHandler extends BlockParentHandler {
30
31 /**
32 * Construct an instance of this handler with the given indentation check,
33 * abstract syntax tree, and parent handler.
34 *
35 * @param indentCheck the indentation check
36 * @param ast the abstract syntax tree
37 * @param parent the parent handler
38 */
39 public TryHandler(IndentationCheck indentCheck,
40 DetailAST ast, AbstractExpressionHandler parent) {
41 super(indentCheck, "try", ast, parent);
42 }
43
44 /**
45 * Method to find left parenthesis of try with resources.
46 *
47 * @return DetailAst left parenthesis of try with resources
48 */
49 private DetailAST getTryResLparen() {
50 return getMainAst().getFirstChild().getFirstChild();
51 }
52
53 /**
54 * Method to find right parenthesis of try with resources.
55 *
56 * @return DetailAst right parenthesis of try with resources
57 */
58 private DetailAST getTryResRparen() {
59 return getMainAst().getFirstChild().getLastChild();
60 }
61
62 @Override
63 public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) {
64 final IndentLevel result;
65 if (child instanceof CatchHandler
66 || child instanceof FinallyHandler
67 || child instanceof NewHandler
68 && isTryBlocksResourceSpecification(child)) {
69 result = getIndent();
70 }
71 else {
72 result = super.getSuggestedChildIndent(child);
73 }
74 return result;
75 }
76
77 @Override
78 public void checkIndentation() {
79 super.checkIndentation();
80 if (getMainAst().getFirstChild().getType() == TokenTypes.RESOURCE_SPECIFICATION) {
81 checkTryResParen(getTryResLparen(), "lparen");
82 checkTryResParen(getTryResRparen(), "rparen");
83 checkTryResources(getMainAst().getFirstChild());
84 }
85 }
86
87 /**
88 * Method to check the indentation of left paren or right paren.
89 * This method itself checks whether either of these are on start of line. This method
90 * takes care of line wrapping strict condition as well.
91 *
92 * @param parenAst lparen or rparen ast to check
93 * @param subType name to be used in log message
94 */
95 private void checkTryResParen(final DetailAST parenAst,
96 final String subType) {
97 if (isOnStartOfLine(parenAst)) {
98 final IndentLevel expectedIdent = new IndentLevel(getIndent(), 0,
99 getIndentCheck().getLineWrappingIndentation());
100
101 checkChildIndentation(parenAst, subType, expectedIdent);
102 }
103 }
104
105 /**
106 * Method to check indentation of try resources children.
107 * It takes into account forceStrictCondition value when logging violations.
108 * Example of usage would include checking for try parenthesis and try resources.
109 *
110 * @param ast AST to check.
111 * @param subType String representing child type.
112 * @param expectedIdent Expected indent level.
113 */
114 private void checkChildIndentation(DetailAST ast, String subType, IndentLevel expectedIdent) {
115 if (getIndentCheck().isForceStrictCondition()) {
116 if (!expectedIdent.isAcceptable(expandedTabsColumnNo(ast))) {
117 logError(ast, subType, expandedTabsColumnNo(ast), expectedIdent);
118 }
119 }
120 else {
121 if (expandedTabsColumnNo(ast) < expectedIdent.getFirstIndentLevel()) {
122 logError(ast, subType, expandedTabsColumnNo(ast), expectedIdent);
123 }
124 }
125 }
126
127 /**
128 * Checks indentation of resources parameters in try resources.
129 *
130 * @param resourcesSpecAst Resource specification ast
131 */
132 private void checkTryResources(final DetailAST resourcesSpecAst) {
133 final DetailAST resourcesAst = resourcesSpecAst.findFirstToken(TokenTypes.RESOURCES);
134 final int indentation = getIndent().getFirstIndentLevel()
135 + getIndentCheck().getLineWrappingIndentation();
136 final IndentLevel expectedResourceIndent = new IndentLevel(indentation);
137
138 final String subType = "resource";
139
140 DetailAST resourceAst = resourcesAst.getFirstChild();
141 while (resourceAst != null) {
142 if (resourceAst.getType() == TokenTypes.RESOURCE) {
143 final DetailAST nextSibling;
144 if (resourceAst.getNextSibling() == null) {
145 nextSibling = getTryResRparen();
146 }
147 else {
148 nextSibling = resourceAst.getNextSibling();
149 }
150 if (isOnStartOfLine(resourceAst)) {
151 checkChildIndentation(resourceAst, subType, expectedResourceIndent);
152 checkWrappingIndentation(
153 resourceAst,
154 nextSibling,
155 getIndentCheck().getLineWrappingIndentation(),
156 expectedResourceIndent.getFirstIndentLevel(),
157 true);
158 }
159 else {
160 checkWrappingIndentation(resourceAst, nextSibling);
161 }
162 }
163 resourceAst = resourceAst.getNextSibling();
164 }
165 }
166
167 /**
168 * Check if the expression is resource of
169 * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20.3">
170 * try block</a>.
171 *
172 * @param expression The expression to check
173 * @return if the expression provided is try block's resource specification.
174 */
175 private static boolean isTryBlocksResourceSpecification(AbstractExpressionHandler expression) {
176 boolean isResourceSpecificationExpression = false;
177
178 DetailAST ast = expression.getMainAst();
179
180 while (ast.getType() != TokenTypes.LITERAL_TRY) {
181 if (ast.getType() == TokenTypes.RESOURCE_SPECIFICATION) {
182 isResourceSpecificationExpression = true;
183 break;
184 }
185
186 ast = ast.getParent();
187 }
188
189 return isResourceSpecificationExpression;
190 }
191
192 }