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  import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
25  
26  /**
27   * Handler for operator new.
28   */
29  public class NewHandler extends AbstractExpressionHandler {
30  
31      /** The AST which is handled by this handler. */
32      private final DetailAST mainAst;
33  
34      /**
35       * Construct an instance of this handler with the given indentation check,
36       * abstract syntax tree, and parent handler.
37       *
38       * @param indentCheck   the indentation check
39       * @param ast           the abstract syntax tree
40       * @param parent        the parent handler
41       */
42      public NewHandler(IndentationCheck indentCheck,
43                        DetailAST ast,
44                        AbstractExpressionHandler parent) {
45          super(indentCheck, "new", ast, parent);
46          mainAst = ast;
47      }
48  
49      @Override
50      public void checkIndentation() {
51          // if new is on the line start and it is not the part of assignment.
52          if (isOnStartOfLine(mainAst)) {
53              final int columnNo = expandedTabsColumnNo(mainAst);
54              final IndentLevel level = getIndentImpl();
55  
56              final boolean forceStrictCondition = getIndentCheck().isForceStrictCondition();
57              if (forceStrictCondition && !level.isAcceptable(columnNo)
58                  || !forceStrictCondition && level.isGreaterThan(columnNo)) {
59                  logError(mainAst, "", columnNo, level);
60              }
61          }
62  
63          final DetailAST firstChild = mainAst.getFirstChild();
64          if (firstChild != null) {
65              checkExpressionSubtree(firstChild, getIndent(), false, false);
66          }
67  
68          final DetailAST lparen = mainAst.findFirstToken(TokenTypes.LPAREN);
69          checkLeftParen(lparen);
70      }
71  
72      @Override
73      public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) {
74          final int offset;
75          if (TokenUtil.isOfType(child.getMainAst(), TokenTypes.OBJBLOCK)) {
76              offset = getBasicOffset();
77          }
78          else {
79              offset = getLineWrappingIndent();
80          }
81          return new IndentLevel(getIndent(), offset);
82      }
83  
84      @Override
85      protected IndentLevel getIndentImpl() {
86          IndentLevel result;
87          // if our expression isn't first on the line, just use the start
88          // of the line
89          if (getLineStart(mainAst) == mainAst.getColumnNo()) {
90              result = super.getIndentImpl();
91  
92              final boolean isLineWrappedNew = TokenUtil.isOfType(mainAst.getParent().getParent(),
93                                          TokenTypes.ASSIGN, TokenTypes.LITERAL_RETURN);
94  
95              if (isLineWrappedNew || doesChainedMethodNeedsLineWrapping()) {
96                  result = new IndentLevel(result, getLineWrappingIndent());
97              }
98          }
99          else {
100             result = new IndentLevel(getLineStart(mainAst));
101         }
102 
103         return result;
104     }
105 
106     /**
107      * A shortcut for {@code IndentationCheck} property.
108      *
109      * @return value of lineWrappingIndentation property
110      *         of {@code IndentationCheck}
111      */
112     private int getLineWrappingIndent() {
113         return getIndentCheck().getLineWrappingIndentation();
114     }
115 
116     @Override
117     protected boolean shouldIncreaseIndent() {
118         return false;
119     }
120 
121     /**
122      * The function checks if the new keyword is a child of chained method calls,
123      * it checks if the new is directly followed by equal operator or return operator.
124      *
125      * @return true if the new it is chained method calls and new keyword is directly followed
126      *         by assign or return
127      */
128     private boolean doesChainedMethodNeedsLineWrapping() {
129         DetailAST ast = mainAst.getParent();
130 
131         while (TokenUtil.isOfType(ast, TokenTypes.DOT, TokenTypes.METHOD_CALL, TokenTypes.EXPR)) {
132             ast = ast.getParent();
133         }
134 
135         return TokenUtil.isOfType(ast, TokenTypes.ASSIGN, TokenTypes.LITERAL_RETURN);
136     }
137 
138 }