1
2
3
4
5 package com.qulice.checkstyle;
6
7 import com.google.common.base.Optional;
8 import com.google.common.collect.ImmutableMap;
9 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
10 import com.puppycrawl.tools.checkstyle.api.DetailAST;
11 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.Map;
15
16
17
18
19
20
21
22
23 public final class MethodsOrderCheck extends AbstractCheck {
24
25 @Override
26 public int[] getDefaultTokens() {
27 return new int[]{
28 TokenTypes.CLASS_DEF,
29 TokenTypes.ENUM_DEF,
30 };
31 }
32
33 @Override
34 public int[] getAcceptableTokens() {
35 return this.getDefaultTokens();
36 }
37
38 @Override
39 public int[] getRequiredTokens() {
40 return this.getDefaultTokens();
41 }
42
43 @Override
44 public void visitToken(final DetailAST ast) {
45 if (ast.getType() == TokenTypes.CLASS_DEF
46 || ast.getType() == TokenTypes.ENUM_DEF) {
47 this.checkClass(ast);
48 }
49 }
50
51
52
53
54
55 private void checkClass(final DetailAST node) {
56 final DetailAST obj = node.findFirstToken(TokenTypes.OBJBLOCK);
57 if (obj != null) {
58 this.checkOrder(
59 MethodsOrderCheck.findAllChildren(
60 obj, TokenTypes.METHOD_DEF
61 )
62 );
63 }
64 }
65
66
67
68
69
70 private void checkOrder(final Iterable<DetailAST> methods) {
71 MethodsOrderCheck.Modifiers prev = MethodsOrderCheck.Modifiers.PUB;
72 for (final DetailAST method : methods) {
73 final MethodsOrderCheck.Modifiers mtype =
74 MethodsOrderCheck.getModifierType(method);
75 if (mtype.getOrder() < prev.getOrder()) {
76 this.log(
77 method.getLineNo(),
78 "Wrong method declaration order"
79 );
80 } else {
81 prev = mtype;
82 }
83 }
84 }
85
86
87
88
89
90
91 private static MethodsOrderCheck.Modifiers getModifierType(
92 final DetailAST method
93 ) {
94 final DetailAST modifiers = method.findFirstToken(TokenTypes.MODIFIERS);
95 final DetailAST modifier = Optional.fromNullable(
96 modifiers.findFirstToken(
97 MethodsOrderCheck.Modifiers.PUB.getType()
98 )
99 ).or(
100 Optional.fromNullable(
101 modifiers.findFirstToken(
102 MethodsOrderCheck.Modifiers.PROT.getType()
103 )
104 )
105 ).or(
106 Optional.fromNullable(
107 modifiers.findFirstToken(
108 MethodsOrderCheck.Modifiers.PRIV.getType()
109 )
110 )
111 ).orNull();
112 final MethodsOrderCheck.Modifiers mod;
113 if (modifier == null) {
114 mod = MethodsOrderCheck.Modifiers.DEF;
115 } else {
116 mod = getByType(modifier.getType());
117 }
118 return mod;
119 }
120
121
122
123
124
125
126
127 private static Iterable<DetailAST> findAllChildren(final DetailAST base,
128 final int type) {
129 final List<DetailAST> children = new ArrayList<>(base.getChildCount());
130 DetailAST child = base.getFirstChild();
131 while (child != null) {
132 if (child.getType() == type) {
133 children.add(child);
134 }
135 child = child.getNextSibling();
136 }
137 return children;
138 }
139
140
141
142
143
144
145 private static MethodsOrderCheck.Modifiers getByType(final int type) {
146 return MethodsOrderCheck.Modifiers.mdos.get(type);
147 }
148
149
150
151
152 private enum Modifiers {
153
154
155
156
157 PUB(TokenTypes.LITERAL_PUBLIC, 1),
158
159
160
161
162 PROT(TokenTypes.LITERAL_PROTECTED, 2),
163
164
165
166
167
168 DEF(-1, 3),
169
170
171
172
173 PRIV(TokenTypes.LITERAL_PRIVATE, 4);
174
175
176
177
178 private static Map<Integer, MethodsOrderCheck.Modifiers> mdos;
179
180 static {
181 MethodsOrderCheck.Modifiers.mdos =
182 ImmutableMap.<Integer, MethodsOrderCheck.Modifiers>builder()
183 .put(PUB.getType(), PUB)
184 .put(PROT.getType(), PROT)
185 .put(-1, DEF)
186 .put(PRIV.getType(), PRIV)
187 .build();
188 }
189
190
191
192
193 private final Integer type;
194
195
196
197
198 private final int order;
199
200
201
202
203
204
205 Modifiers(final Integer type, final Integer ord) {
206 this.type = type;
207 this.order = ord;
208 }
209
210
211
212
213
214 int getType() {
215 return this.type;
216 }
217
218
219
220
221
222 int getOrder() {
223 return this.order;
224 }
225 }
226 }