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 array initialization blocks. 027 * 028 */ 029public class ArrayInitHandler extends BlockParentHandler { 030 031 /** 032 * Constant to define that the required character does not exist at any position. 033 */ 034 private static final int NOT_EXIST = -1; 035 036 /** 037 * Construct an instance of this handler with the given indentation check, 038 * abstract syntax tree, and parent handler. 039 * 040 * @param indentCheck the indentation check 041 * @param ast the abstract syntax tree 042 * @param parent the parent handler 043 */ 044 public ArrayInitHandler(IndentationCheck indentCheck, 045 DetailAST ast, AbstractExpressionHandler parent) { 046 super(indentCheck, "array initialization", ast, parent); 047 } 048 049 @Override 050 protected IndentLevel getIndentImpl() { 051 final DetailAST parentAST = getMainAst().getParent(); 052 final int type = parentAST.getType(); 053 final IndentLevel indentLevel; 054 if (type == TokenTypes.LITERAL_NEW || type == TokenTypes.ASSIGN) { 055 // note: assumes new or assignment is line to align with 056 indentLevel = new IndentLevel(getLineStart(parentAST)); 057 } 058 else { 059 // at this point getParent() is instance of BlockParentHandler 060 indentLevel = ((BlockParentHandler) getParent()).getChildrenExpectedIndent(); 061 } 062 return indentLevel; 063 } 064 065 @Override 066 protected DetailAST getTopLevelAst() { 067 return null; 068 } 069 070 @Override 071 protected DetailAST getLeftCurly() { 072 return getMainAst(); 073 } 074 075 @Override 076 protected IndentLevel curlyIndent() { 077 int offset = 0; 078 079 final DetailAST lcurly = getLeftCurly(); 080 081 if (isOnStartOfLine(lcurly) 082 && lcurly.getParent().getType() != TokenTypes.ARRAY_INIT) { 083 offset = getBraceAdjustment(); 084 } 085 086 final IndentLevel level = new IndentLevel(getIndent(), offset); 087 return IndentLevel.addAcceptable(level, level.getLastIndentLevel() 088 + getLineWrappingIndentation()); 089 } 090 091 @Override 092 protected DetailAST getRightCurly() { 093 return getMainAst().findFirstToken(TokenTypes.RCURLY); 094 } 095 096 @Override 097 protected boolean canChildrenBeNested() { 098 return true; 099 } 100 101 @Override 102 protected DetailAST getListChild() { 103 return getMainAst(); 104 } 105 106 @Override 107 protected IndentLevel getChildrenExpectedIndent() { 108 IndentLevel expectedIndent = 109 new IndentLevel(getIndent(), getIndentCheck().getArrayInitIndent(), 110 getIndentCheck().getLineWrappingIndentation()); 111 112 final int firstLine = getFirstLine(getListChild()); 113 final int lcurlyPos = expandedTabsColumnNo(getLeftCurly()); 114 final int firstChildPos = 115 getNextFirstNonBlankOnLineAfter(firstLine, lcurlyPos); 116 117 if (firstChildPos != NOT_EXIST) { 118 expectedIndent = IndentLevel.addAcceptable(expectedIndent, firstChildPos, lcurlyPos 119 + getLineWrappingIndentation()); 120 } 121 return expectedIndent; 122 } 123 124 /** 125 * Returns column number of first non-blank char after 126 * specified column on specified line or {@code NOT_EXIST} if 127 * such char doesn't exist. 128 * 129 * @param lineNo number of line on which we search 130 * @param columnNo number of column after which we search 131 * 132 * @return column number of first non-blank char after 133 * specified column on specified line or {@code NOT_EXIST} if 134 * such char doesn't exist. 135 */ 136 private int getNextFirstNonBlankOnLineAfter(int lineNo, int columnNo) { 137 int realColumnNo = columnNo + 1; 138 final String line = getIndentCheck().getLines()[lineNo - 1]; 139 final int lineLength = line.length(); 140 while (realColumnNo < lineLength 141 && Character.isWhitespace(line.charAt(realColumnNo))) { 142 realColumnNo++; 143 } 144 145 if (realColumnNo == lineLength) { 146 realColumnNo = NOT_EXIST; 147 } 148 return realColumnNo; 149 } 150 151 /** 152 * A shortcut for {@code IndentationCheck} property. 153 * 154 * @return value of lineWrappingIndentation property 155 * of {@code IndentationCheck} 156 */ 157 private int getLineWrappingIndentation() { 158 return getIndentCheck().getLineWrappingIndentation(); 159 } 160 161}