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 array initialization blocks.
27   *
28   */
29  public class ArrayInitHandler 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 ArrayInitHandler(IndentationCheck indentCheck,
45          DetailAST ast, AbstractExpressionHandler parent) {
46          super(indentCheck, "array initialization", ast, parent);
47      }
48  
49      @Override
50      protected IndentLevel getIndentImpl() {
51          final DetailAST parentAST = getMainAst().getParent();
52          final int type = parentAST.getType();
53          final IndentLevel indentLevel;
54          if (type == TokenTypes.LITERAL_NEW || type == TokenTypes.ASSIGN) {
55              // note: assumes new or assignment is line to align with
56              indentLevel = new IndentLevel(getLineStart(parentAST));
57          }
58          else {
59              // at this point getParent() is instance of BlockParentHandler
60              indentLevel = ((BlockParentHandler) getParent()).getChildrenExpectedIndent();
61          }
62          return indentLevel;
63      }
64  
65      @Override
66      protected DetailAST getTopLevelAst() {
67          return null;
68      }
69  
70      @Override
71      protected DetailAST getLeftCurly() {
72          return getMainAst();
73      }
74  
75      @Override
76      protected IndentLevel curlyIndent() {
77          int offset = 0;
78  
79          final DetailAST lcurly = getLeftCurly();
80  
81          if (isOnStartOfLine(lcurly)
82              && lcurly.getParent().getType() != TokenTypes.ARRAY_INIT) {
83              offset = getBraceAdjustment();
84          }
85  
86          final IndentLevel level = new IndentLevel(getIndent(), offset);
87          return IndentLevel.addAcceptable(level, level.getLastIndentLevel()
88                  + getLineWrappingIndentation());
89      }
90  
91      @Override
92      protected DetailAST getRightCurly() {
93          return getMainAst().findFirstToken(TokenTypes.RCURLY);
94      }
95  
96      @Override
97      protected boolean canChildrenBeNested() {
98          return true;
99      }
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 }