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.design;
21
22 import java.util.BitSet;
23
24 import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
25 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
26 import com.puppycrawl.tools.checkstyle.api.DetailAST;
27 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
28 import com.puppycrawl.tools.checkstyle.utils.ScopeUtil;
29 import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
30
31 /**
32 * <p>
33 * Checks nested (internal) classes/interfaces are declared at the bottom of the
34 * primary (top-level) class after all init and static init blocks,
35 * method, constructor and field declarations.
36 * </p>
37 * <p>
38 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
39 * </p>
40 * <p>
41 * Violation Message Keys:
42 * </p>
43 * <ul>
44 * <li>
45 * {@code arrangement.members.before.inner}
46 * </li>
47 * </ul>
48 *
49 * @since 5.2
50 */
51 @FileStatefulCheck
52 public class InnerTypeLastCheck extends AbstractCheck {
53
54 /**
55 * A key is pointing to the warning message text in "messages.properties"
56 * file.
57 */
58 public static final String MSG_KEY = "arrangement.members.before.inner";
59
60 /** Set of class member tokens. */
61 private static final BitSet CLASS_MEMBER_TOKENS = TokenUtil.asBitSet(
62 TokenTypes.VARIABLE_DEF,
63 TokenTypes.METHOD_DEF,
64 TokenTypes.CTOR_DEF,
65 TokenTypes.INSTANCE_INIT,
66 TokenTypes.STATIC_INIT,
67 TokenTypes.COMPACT_CTOR_DEF
68 );
69
70 /** Meet a root class. */
71 private boolean rootClass;
72
73 @Override
74 public int[] getDefaultTokens() {
75 return getRequiredTokens();
76 }
77
78 @Override
79 public int[] getAcceptableTokens() {
80 return getRequiredTokens();
81 }
82
83 @Override
84 public int[] getRequiredTokens() {
85 return new int[] {
86 TokenTypes.CLASS_DEF,
87 TokenTypes.INTERFACE_DEF,
88 TokenTypes.RECORD_DEF,
89 };
90 }
91
92 @Override
93 public void beginTree(DetailAST rootAST) {
94 rootClass = true;
95 }
96
97 @Override
98 public void visitToken(DetailAST ast) {
99 // First root class
100 if (rootClass) {
101 rootClass = false;
102 }
103 else {
104 DetailAST nextSibling = ast;
105 while (nextSibling != null) {
106 if (!ScopeUtil.isInCodeBlock(ast)
107 && CLASS_MEMBER_TOKENS.get(nextSibling.getType())) {
108 log(nextSibling, MSG_KEY);
109 }
110 nextSibling = nextSibling.getNextSibling();
111 }
112 }
113 }
114
115 @Override
116 public void leaveToken(DetailAST ast) {
117 if (TokenUtil.isRootNode(ast.getParent())) {
118 rootClass = true;
119 }
120 }
121
122 }