001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2024 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 /** 088 * Method to check the indentation of left paren or right paren. 089 * This method itself checks whether either of these are on start of line. This method 090 * takes care of line wrapping strict condition as well. 091 * 092 * @param parenAst lparen or rparen ast to check 093 * @param subType name to be used in log message 094 */ 095 private void checkTryResParen(final DetailAST parenAst, 096 final String subType) { 097 if (isOnStartOfLine(parenAst)) { 098 final IndentLevel expectedIdent = new IndentLevel(getIndent(), 0, 099 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}