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}