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 member definitions.
27   *
28   */
29  public class MemberDefHandler extends AbstractExpressionHandler {
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 MemberDefHandler(IndentationCheck indentCheck,
40          DetailAST ast, AbstractExpressionHandler parent) {
41          super(indentCheck, "member def", ast, parent);
42      }
43  
44      @Override
45      public void checkIndentation() {
46          final DetailAST modifiersNode = getMainAst().findFirstToken(TokenTypes.MODIFIERS);
47          if (modifiersNode.getChildCount() == 0) {
48              checkType();
49          }
50          else {
51              checkModifiers();
52          }
53          final DetailAST firstNode = getMainAst();
54          final DetailAST lastNode = getVarDefStatementSemicolon(firstNode);
55  
56          if (lastNode != null && !isArrayDeclaration(firstNode)) {
57              checkWrappingIndentation(firstNode, lastNode);
58          }
59      }
60  
61      @Override
62      public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) {
63          return getIndent();
64      }
65  
66      @Override
67      protected void checkModifiers() {
68          final DetailAST modifier = getMainAst().findFirstToken(TokenTypes.MODIFIERS);
69          if (isOnStartOfLine(modifier)
70              && !getIndent().isAcceptable(expandedTabsColumnNo(modifier))) {
71              logError(modifier, "modifier", expandedTabsColumnNo(modifier));
72          }
73      }
74  
75      /**
76       * Check the indentation of the method type.
77       */
78      private void checkType() {
79          final DetailAST type = getMainAst().findFirstToken(TokenTypes.TYPE);
80          final DetailAST ident = AbstractExpressionHandler.getFirstToken(type);
81          final int columnNo = expandedTabsColumnNo(ident);
82          if (isOnStartOfLine(ident) && !getIndent().isAcceptable(columnNo)) {
83              logError(ident, "type", columnNo);
84          }
85      }
86  
87      /**
88       * Checks if variable_def node is array declaration.
89       * @param variableDef current variable_def.
90       * @return true if variable_def node is array declaration.
91       */
92      private static boolean isArrayDeclaration(DetailAST variableDef) {
93          return variableDef.findFirstToken(TokenTypes.TYPE)
94              .findFirstToken(TokenTypes.ARRAY_DECLARATOR) != null;
95      }
96  
97      /**
98       * Returns semicolon for variable definition statement.
99       * @param variableDef
100      *          ast node of type TokenTypes.VARIABLE_DEF
101      * @return ast node of type TokenTypes.SEMI
102      */
103     private static DetailAST getVarDefStatementSemicolon(DetailAST variableDef) {
104         DetailAST lastNode = variableDef.getLastChild();
105         if (lastNode.getType() != TokenTypes.SEMI) {
106             lastNode = variableDef.getNextSibling();
107         }
108         return lastNode;
109     }
110 
111 }