001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2020 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 final IndentLevel level = new IndentLevel(getIndent(), getBraceAdjustment()); 078 return IndentLevel.addAcceptable(level, level.getLastIndentLevel() 079 + getLineWrappingIndentation()); 080 } 081 082 @Override 083 protected DetailAST getRightCurly() { 084 return getMainAst().findFirstToken(TokenTypes.RCURLY); 085 } 086 087 @Override 088 protected boolean canChildrenBeNested() { 089 return true; 090 } 091 092 @Override 093 protected DetailAST getListChild() { 094 return getMainAst(); 095 } 096 097 @Override 098 protected IndentLevel getChildrenExpectedIndent() { 099 IndentLevel expectedIndent = 100 new IndentLevel(getIndent(), getIndentCheck().getArrayInitIndent(), 101 getIndentCheck().getLineWrappingIndentation()); 102 103 final int firstLine = getFirstLine(getListChild()); 104 final int lcurlyPos = expandedTabsColumnNo(getLeftCurly()); 105 final int firstChildPos = 106 getNextFirstNonBlankOnLineAfter(firstLine, lcurlyPos); 107 108 if (firstChildPos != NOT_EXIST) { 109 expectedIndent = IndentLevel.addAcceptable(expectedIndent, firstChildPos, lcurlyPos 110 + getLineWrappingIndentation()); 111 } 112 return expectedIndent; 113 } 114 115 /** 116 * Returns column number of first non-blank char after 117 * specified column on specified line or {@code NOT_EXIST} if 118 * such char doesn't exist. 119 * 120 * @param lineNo number of line on which we search 121 * @param columnNo number of column after which we search 122 * 123 * @return column number of first non-blank char after 124 * specified column on specified line or {@code NOT_EXIST} if 125 * such char doesn't exist. 126 */ 127 private int getNextFirstNonBlankOnLineAfter(int lineNo, int columnNo) { 128 int realColumnNo = columnNo + 1; 129 final String line = getIndentCheck().getLines()[lineNo - 1]; 130 final int lineLength = line.length(); 131 while (realColumnNo < lineLength 132 && Character.isWhitespace(line.charAt(realColumnNo))) { 133 realColumnNo++; 134 } 135 136 if (realColumnNo == lineLength) { 137 realColumnNo = NOT_EXIST; 138 } 139 return realColumnNo; 140 } 141 142 /** 143 * A shortcut for {@code IndentationCheck} property. 144 * 145 * @return value of lineWrappingIndentation property 146 * of {@code IndentationCheck} 147 */ 148 private int getLineWrappingIndentation() { 149 return getIndentCheck().getLineWrappingIndentation(); 150 } 151 152}