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 java.util.BitSet;
23
24 import com.puppycrawl.tools.checkstyle.api.DetailAST;
25 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
26 import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
27
28 /**
29 * Handler for a list of statements.
30 *
31 */
32 public class SlistHandler extends BlockParentHandler {
33
34 /**
35 * Parent token types.
36 */
37 private static final BitSet PARENT_TOKEN_TYPES = TokenUtil.asBitSet(
38 TokenTypes.CTOR_DEF,
39 TokenTypes.METHOD_DEF,
40 TokenTypes.STATIC_INIT,
41 TokenTypes.LITERAL_SYNCHRONIZED,
42 TokenTypes.LITERAL_IF,
43 TokenTypes.LITERAL_WHILE,
44 TokenTypes.LITERAL_DO,
45 TokenTypes.LITERAL_FOR,
46 TokenTypes.LITERAL_ELSE,
47 TokenTypes.LITERAL_TRY,
48 TokenTypes.LITERAL_CATCH,
49 TokenTypes.LITERAL_FINALLY,
50 TokenTypes.COMPACT_CTOR_DEF
51 );
52
53 /**
54 * Construct an instance of this handler with the given indentation check,
55 * abstract syntax tree, and parent handler.
56 *
57 * @param indentCheck the indentation check
58 * @param ast the abstract syntax tree
59 * @param parent the parent handler
60 */
61 public SlistHandler(IndentationCheck indentCheck,
62 DetailAST ast, AbstractExpressionHandler parent) {
63 super(indentCheck, "block", ast, parent);
64 }
65
66 @Override
67 public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) {
68 // this is:
69 // switch (var) {
70 // case 3: {
71 // break;
72 // }
73 // }
74 // ... the case SLIST is followed by a user-created SLIST and
75 // preceded by a switch
76
77 final IndentLevel result;
78 // if our parent is a block handler we want to be transparent
79 if (getParent() instanceof BlockParentHandler
80 && !(getParent() instanceof SlistHandler)
81 || child instanceof SlistHandler
82 && getParent() instanceof CaseHandler) {
83 result = getParent().getSuggestedChildIndent(child);
84 }
85 else {
86 result = super.getSuggestedChildIndent(child);
87 }
88 return result;
89 }
90
91 @Override
92 protected DetailAST getListChild() {
93 return getMainAst();
94 }
95
96 @Override
97 protected DetailAST getLeftCurly() {
98 return getMainAst();
99 }
100
101 @Override
102 protected DetailAST getRightCurly() {
103 return getMainAst().findFirstToken(TokenTypes.RCURLY);
104 }
105
106 @Override
107 protected DetailAST getTopLevelAst() {
108 return null;
109 }
110
111 /**
112 * Determine if the expression we are handling has a block parent.
113 *
114 * @return true if it does, false otherwise
115 */
116 private boolean hasBlockParent() {
117 final int parentType = getMainAst().getParent().getType();
118 return PARENT_TOKEN_TYPES.get(parentType);
119 }
120
121 @Override
122 public void checkIndentation() {
123 // only need to check this if parent is not
124 // an if, else, while, do, ctor, method
125 if (!hasBlockParent() && !isSameLineCaseGroup()) {
126 super.checkIndentation();
127 }
128 }
129
130 /**
131 * Checks if SLIST node is placed at the same line as CASE_GROUP node.
132 *
133 * @return true, if SLIST node is places at the same line as CASE_GROUP node.
134 */
135 private boolean isSameLineCaseGroup() {
136 final DetailAST parentNode = getMainAst().getParent();
137 return parentNode.getType() == TokenTypes.CASE_GROUP
138 && TokenUtil.areOnSameLine(getMainAst(), parentNode);
139 }
140
141 }