1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2019 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       * Construct an instance of this handler with the given indentation check,
33       * abstract syntax tree, and parent handler.
34       *
35       * @param indentCheck   the indentation check
36       * @param ast           the abstract syntax tree
37       * @param parent        the parent handler
38       */
39      public ArrayInitHandler(IndentationCheck indentCheck,
40          DetailAST ast, AbstractExpressionHandler parent) {
41          super(indentCheck, "array initialization", ast, parent);
42      }
43  
44      @Override
45      protected IndentLevel getIndentImpl() {
46          final DetailAST parentAST = getMainAst().getParent();
47          final int type = parentAST.getType();
48          final IndentLevel indentLevel;
49          if (type == TokenTypes.LITERAL_NEW || type == TokenTypes.ASSIGN) {
50              // note: assumes new or assignment is line to align with
51              indentLevel = new IndentLevel(getLineStart(parentAST));
52          }
53          else {
54              // at this point getParent() is instance of BlockParentHandler
55              indentLevel = ((BlockParentHandler) getParent()).getChildrenExpectedIndent();
56          }
57          return indentLevel;
58      }
59  
60      @Override
61      protected DetailAST getTopLevelAst() {
62          return null;
63      }
64  
65      @Override
66      protected DetailAST getLeftCurly() {
67          return getMainAst();
68      }
69  
70      @Override
71      protected IndentLevel curlyIndent() {
72          final IndentLevel level = new IndentLevel(getIndent(), getBraceAdjustment());
73          return IndentLevel.addAcceptable(level, level.getLastIndentLevel()
74                  + getLineWrappingIndentation());
75      }
76  
77      @Override
78      protected DetailAST getRightCurly() {
79          return getMainAst().findFirstToken(TokenTypes.RCURLY);
80      }
81  
82      @Override
83      protected boolean canChildrenBeNested() {
84          return true;
85      }
86  
87      @Override
88      protected DetailAST getListChild() {
89          return getMainAst();
90      }
91  
92      @Override
93      protected IndentLevel getChildrenExpectedIndent() {
94          IndentLevel expectedIndent =
95              new IndentLevel(getIndent(), getIndentCheck().getArrayInitIndent(),
96                      getIndentCheck().getLineWrappingIndentation());
97  
98          final int firstLine = getFirstLine(Integer.MAX_VALUE, getListChild());
99          final int lcurlyPos = expandedTabsColumnNo(getLeftCurly());
100         final int firstChildPos =
101             getNextFirstNonBlankOnLineAfter(firstLine, lcurlyPos);
102         if (firstChildPos >= 0) {
103             expectedIndent = IndentLevel.addAcceptable(expectedIndent, firstChildPos, lcurlyPos
104                     + getLineWrappingIndentation());
105         }
106         return expectedIndent;
107     }
108 
109     /**
110      * Returns column number of first non-blank char after
111      * specified column on specified line or -1 if
112      * such char doesn't exist.
113      *
114      * @param lineNo   number of line on which we search
115      * @param columnNo number of column after which we search
116      *
117      * @return column number of first non-blank char after
118      *         specified column on specified line or -1 if
119      *         such char doesn't exist.
120      */
121     private int getNextFirstNonBlankOnLineAfter(int lineNo, int columnNo) {
122         int realColumnNo = columnNo + 1;
123         final String line = getIndentCheck().getLines()[lineNo - 1];
124         final int lineLength = line.length();
125         while (realColumnNo < lineLength
126                && Character.isWhitespace(line.charAt(realColumnNo))) {
127             realColumnNo++;
128         }
129 
130         if (realColumnNo == lineLength) {
131             realColumnNo = -1;
132         }
133         return realColumnNo;
134     }
135 
136     /**
137      * A shortcut for {@code IndentationCheck} property.
138      * @return value of lineWrappingIndentation property
139      *         of {@code IndentationCheck}
140      */
141     private int getLineWrappingIndentation() {
142         return getIndentCheck().getLineWrappingIndentation();
143     }
144 
145 }