View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ///////////////////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.checks.indentation;
21  
22  import com.puppycrawl.tools.checkstyle.api.DetailAST;
23  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
24  
25  /**
26   * Handler for annotation array initialization blocks.
27   *
28   */
29  public class AnnotationArrayInitHandler extends BlockParentHandler {
30  
31      /**
32       * Constant to define that the required character does not exist at any position.
33       */
34      private static final int NOT_EXIST = -1;
35  
36      /**
37       * Construct an instance of this handler with the given indentation check,
38       * abstract syntax tree, and parent handler.
39       *
40       * @param indentCheck   the indentation check
41       * @param ast           the abstract syntax tree
42       * @param parent        the parent handler
43       */
44      public AnnotationArrayInitHandler(IndentationCheck indentCheck,
45                              DetailAST ast, AbstractExpressionHandler parent) {
46          super(indentCheck, "annotation array initialization", ast, parent);
47      }
48  
49      @Override
50      protected IndentLevel getIndentImpl() {
51          final DetailAST parentAST = getMainAst().getParent();
52          return new IndentLevel(getLineStart(parentAST));
53      }
54  
55      @Override
56      protected DetailAST getTopLevelAst() {
57          return null;
58      }
59  
60      @Override
61      protected DetailAST getLeftCurly() {
62          return getMainAst();
63      }
64  
65      @Override
66      protected IndentLevel curlyIndent() {
67          int offset = 0;
68  
69          final DetailAST lcurly = getLeftCurly();
70          if (isOnStartOfLine(lcurly)) {
71              offset = getBraceAdjustment();
72          }
73  
74          final IndentLevel level = new IndentLevel(getIndent(), offset);
75          return IndentLevel.addAcceptable(level, level.getLastIndentLevel()
76              + getLineWrappingIndentation());
77      }
78  
79      @Override
80      protected DetailAST getRightCurly() {
81          return getMainAst().findFirstToken(TokenTypes.RCURLY);
82      }
83  
84      @Override
85      protected boolean canChildrenBeNested() {
86          return true;
87      }
88  
89      @Override
90      protected DetailAST getListChild() {
91          return getMainAst();
92      }
93  
94      @Override
95      protected IndentLevel getChildrenExpectedIndent() {
96          IndentLevel expectedIndent =
97              new IndentLevel(getIndent(), getArrayInitIndentation(), getLineWrappingIndentation());
98  
99          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 }