1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
27
28
29 public class ClassDefHandler extends BlockParentHandler {
30
31
32 private static final String MODIFIER = "modifier";
33
34
35
36
37
38
39
40
41
42 public ClassDefHandler(IndentationCheck indentCheck,
43 DetailAST ast,
44 AbstractExpressionHandler parent) {
45 super(indentCheck, getHandlerName(ast), ast, parent);
46 }
47
48 @Override
49 protected DetailAST getLeftCurly() {
50 return getMainAst().findFirstToken(TokenTypes.OBJBLOCK)
51 .findFirstToken(TokenTypes.LCURLY);
52 }
53
54 @Override
55 protected DetailAST getRightCurly() {
56 return getMainAst().findFirstToken(TokenTypes.OBJBLOCK)
57 .findFirstToken(TokenTypes.RCURLY);
58 }
59
60 @Override
61 protected DetailAST getTopLevelAst() {
62 return null;
63
64 }
65
66 @Override
67 protected DetailAST getListChild() {
68 return getMainAst().findFirstToken(TokenTypes.OBJBLOCK);
69 }
70
71 @Override
72 public void checkIndentation() {
73 final DetailAST modifiers = getMainAst().findFirstToken(TokenTypes.MODIFIERS);
74 if (modifiers.hasChildren()) {
75 checkModifiers();
76 }
77 else {
78 if (getMainAst().getType() != TokenTypes.ANNOTATION_DEF) {
79 final DetailAST ident = getMainAst().findFirstToken(TokenTypes.IDENT);
80 DetailAST tokenToCheck = getMainAst();
81 if (ident.getLineNo() == getMainAst().getLineNo()) {
82 tokenToCheck = ident;
83 }
84 final int lineStart = getLineStart(tokenToCheck);
85 if (!getIndent().isAcceptable(lineStart)) {
86 logError(tokenToCheck, "ident", lineStart);
87 }
88 }
89 }
90 if (getMainAst().getType() == TokenTypes.ANNOTATION_DEF) {
91 final DetailAST atAst = getMainAst().findFirstToken(TokenTypes.AT);
92 if (isOnStartOfLine(atAst)) {
93 checkWrappingIndentation(getMainAst(), getListChild(), 0,
94 getIndent().getFirstIndentLevel(),
95 LineWrappingHandler.LineWrappingOptions.NONE);
96 }
97 }
98 else {
99 checkWrappingIndentation(getMainAst(), getListChild());
100 }
101 super.checkIndentation();
102 }
103
104 @Override
105 protected int[] getCheckedChildren() {
106 return new int[] {
107 TokenTypes.EXPR,
108 TokenTypes.OBJBLOCK,
109 TokenTypes.LITERAL_BREAK,
110 TokenTypes.LITERAL_RETURN,
111 TokenTypes.LITERAL_THROW,
112 TokenTypes.LITERAL_CONTINUE,
113 };
114 }
115
116
117
118
119 private void checkModifiers() {
120 if (getMainAst().getType() == TokenTypes.ANNOTATION_DEF) {
121 checkAnnotationDefModifiers();
122 }
123 else {
124 checkClassDefModifiers();
125 }
126 }
127
128
129
130
131
132 private void checkAnnotationDefModifiers() {
133 final DetailAST modifiers = getMainAst().findFirstToken(TokenTypes.MODIFIERS);
134 for (DetailAST modifier = modifiers.getFirstChild();
135 modifier != null;
136 modifier = modifier.getNextSibling()) {
137 if (isOnStartOfLine(modifier)
138 && !getIndent().isAcceptable(expandedTabsColumnNo(modifier))) {
139 logError(modifier, MODIFIER, expandedTabsColumnNo(modifier));
140 }
141 }
142 }
143
144
145
146
147
148
149
150
151 private void checkClassDefModifiers() {
152 final DetailAST modifiers = getMainAst().findFirstToken(TokenTypes.MODIFIERS);
153 final DetailAST firstModifier = modifiers.getFirstChild();
154 final DetailAST firstNonAnnotationMod = getFirstNonAnnotationModifier(firstModifier);
155 final int firstModifierLine = firstModifier.getLineNo();
156 final int firstNonAnnotationLine = firstNonAnnotationMod.getLineNo();
157
158 checkLineModifiers(firstModifier, firstModifierLine);
159
160 if (firstModifierLine != firstNonAnnotationLine) {
161 checkNonFirstLineModifiers(firstNonAnnotationMod);
162 }
163 }
164
165
166
167
168
169
170
171 private void checkLineModifiers(DetailAST firstModifier,
172 int firstModifierLine) {
173 for (DetailAST modifier = firstModifier;
174 modifier != null
175 && modifier.getLineNo() == firstModifierLine;
176 modifier = modifier.getNextSibling()) {
177 if (isOnStartOfLine(modifier)
178 && !getIndent().isAcceptable(expandedTabsColumnNo(modifier))) {
179 logError(modifier, MODIFIER, expandedTabsColumnNo(modifier));
180 }
181 }
182 }
183
184
185
186
187
188
189
190
191 private void checkNonFirstLineModifiers(DetailAST firstNonAnnotationMod) {
192 for (DetailAST modifier = firstNonAnnotationMod;
193 modifier != null;
194 modifier = modifier.getNextSibling()) {
195 if (isOnStartOfLine(modifier)
196 && !getIndent().isAcceptable(
197 expandedTabsColumnNo(modifier))) {
198 logError(modifier, MODIFIER, expandedTabsColumnNo(modifier));
199 }
200 }
201 }
202
203
204
205
206
207
208
209 private static DetailAST getFirstNonAnnotationModifier(DetailAST firstModifier) {
210 DetailAST result = firstModifier;
211 for (DetailAST modifier = firstModifier;
212 modifier != null;
213 modifier = modifier.getNextSibling()) {
214 if (modifier.getType() != TokenTypes.ANNOTATION) {
215 result = modifier;
216 break;
217 }
218 }
219 return result;
220 }
221
222
223
224
225
226
227
228 private static String getHandlerName(DetailAST ast) {
229 final int tokenType = ast.getType();
230
231 return switch (tokenType) {
232 case TokenTypes.CLASS_DEF -> "class def";
233 case TokenTypes.ENUM_DEF -> "enum def";
234 case TokenTypes.ANNOTATION_DEF -> "annotation def";
235 case TokenTypes.RECORD_DEF -> "record def";
236 default -> "interface def";
237 };
238 }
239
240 }