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 annotation array initialization blocks. 027 * 028 */ 029public class AnnotationArrayInitHandler 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 AnnotationArrayInitHandler(IndentationCheck indentCheck, 045 DetailAST ast, AbstractExpressionHandler parent) { 046 super(indentCheck, "annotation array initialization", ast, parent); 047 } 048 049 @Override 050 protected IndentLevel getIndentImpl() { 051 final DetailAST parentAST = getMainAst().getParent(); 052 return new IndentLevel(getLineStart(parentAST)); 053 } 054 055 @Override 056 protected DetailAST getTopLevelAst() { 057 return null; 058 } 059 060 @Override 061 protected DetailAST getLeftCurly() { 062 return getMainAst(); 063 } 064 065 @Override 066 protected IndentLevel curlyIndent() { 067 int offset = 0; 068 069 final DetailAST lcurly = getLeftCurly(); 070 if (isOnStartOfLine(lcurly)) { 071 offset = getBraceAdjustment(); 072 } 073 074 final IndentLevel level = new IndentLevel(getIndent(), offset); 075 return IndentLevel.addAcceptable(level, level.getLastIndentLevel() 076 + getLineWrappingIndentation()); 077 } 078 079 @Override 080 protected DetailAST getRightCurly() { 081 return getMainAst().findFirstToken(TokenTypes.RCURLY); 082 } 083 084 @Override 085 protected boolean canChildrenBeNested() { 086 return true; 087 } 088 089 @Override 090 protected DetailAST getListChild() { 091 return getMainAst(); 092 } 093 094 @Override 095 protected IndentLevel getChildrenExpectedIndent() { 096 IndentLevel expectedIndent = 097 new IndentLevel(getIndent(), getArrayInitIndentation(), getLineWrappingIndentation()); 098 099 final DetailAST leftCurly = getLeftCurly(); 100 final int firstLine = getFirstLine(getListChild()); 101 final int lcurlyPos = expandedTabsColumnNo(leftCurly); 102 final int firstChildPos = 103 getNextFirstNonBlankOnLineAfter(firstLine, lcurlyPos); 104 105 // the code is written with old style where curlies are given their own line, 106 // the code block should be aligned to lcurly pos + lineWrappingIndent 107 if (firstChildPos == NOT_EXIST && lcurlyPos == getLineStart(leftCurly)) { 108 expectedIndent = IndentLevel.addAcceptable(expectedIndent, 109 lcurlyPos + getLineWrappingIndentation()); 110 } 111 112 if (firstChildPos != NOT_EXIST) { 113 expectedIndent = IndentLevel.addAcceptable(expectedIndent, firstChildPos, lcurlyPos 114 + getLineWrappingIndentation()); 115 } 116 117 return expectedIndent; 118 } 119 120 /** 121 * Returns column number of first non-blank char after 122 * specified column on specified line or -1 if 123 * such char doesn't exist. 124 * 125 * @param lineNo number of line on which we search 126 * @param columnNo number of column after which we search 127 * 128 * @return column number of first non-blank char after 129 * specified column on specified line or -1 if 130 * such char doesn't exist. 131 */ 132 private int getNextFirstNonBlankOnLineAfter(int lineNo, int columnNo) { 133 int realColumnNo = columnNo + 1; 134 final String line = getIndentCheck().getLines()[lineNo - 1]; 135 final int lineLength = line.length(); 136 while (realColumnNo < lineLength 137 && Character.isWhitespace(line.charAt(realColumnNo))) { 138 realColumnNo++; 139 } 140 141 if (realColumnNo == lineLength) { 142 realColumnNo = -1; 143 } 144 return realColumnNo; 145 } 146 147 /** 148 * A shortcut for {@code IndentationCheck} property. 149 * 150 * @return value of lineWrappingIndentation property 151 * of {@code IndentationCheck} 152 */ 153 private int getLineWrappingIndentation() { 154 return getIndentCheck().getLineWrappingIndentation(); 155 } 156 157 /** 158 * A shortcut for {@code IndentationCheck} property. 159 * 160 * @return value of arrayInitIndent property 161 * of {@code IndentationCheck} 162 */ 163 private int getArrayInitIndentation() { 164 return getIndentCheck().getArrayInitIndent(); 165 } 166 167}