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.google.common.collect.Lists;
10 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
11 import com.puppycrawl.tools.checkstyle.api.DetailAST;
12 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
13 import java.util.List;
14 import java.util.Map;
15
16
17
18
19
20
21
22 public final class MethodsOrderCheck extends AbstractCheck {
23
24 @Override
25 public int[] getDefaultTokens() {
26 return new int[]{
27 TokenTypes.CLASS_DEF,
28 TokenTypes.ENUM_DEF,
29 };
30 }
31
32 @Override
33 public int[] getAcceptableTokens() {
34 return this.getDefaultTokens();
35 }
36
37 @Override
38 public int[] getRequiredTokens() {
39 return this.getDefaultTokens();
40 }
41
42 @Override
43 public void visitToken(final DetailAST ast) {
44 if (ast.getType() == TokenTypes.CLASS_DEF
45 || ast.getType() == TokenTypes.ENUM_DEF) {
46 this.checkClass(ast);
47 }
48 }
49
50
51
52
53
54 private void checkClass(final DetailAST node) {
55 final DetailAST obj = node.findFirstToken(TokenTypes.OBJBLOCK);
56 if (obj != null) {
57 this.checkOrder(
58 MethodsOrderCheck.findAllChildren(
59 obj, TokenTypes.METHOD_DEF
60 )
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 = Lists.newArrayList();
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 PUB(TokenTypes.LITERAL_PUBLIC, 1),
157
158
159
160
161 PROT(TokenTypes.LITERAL_PROTECTED, 2),
162
163
164
165
166
167 DEF(-1, 3),
168
169
170
171
172 PRIV(TokenTypes.LITERAL_PRIVATE, 4);
173
174
175
176
177 private static Map<Integer, MethodsOrderCheck.Modifiers> mdos;
178
179 static {
180 MethodsOrderCheck.Modifiers.mdos =
181 ImmutableMap.<Integer, MethodsOrderCheck.Modifiers>builder()
182 .put(PUB.getType(), PUB)
183 .put(PROT.getType(), PROT)
184 .put(-1, DEF)
185 .put(PRIV.getType(), PRIV)
186 .build();
187 }
188
189
190
191
192 private final Integer type;
193
194
195
196
197 private final int order;
198
199
200
201
202
203
204 Modifiers(final Integer type, final Integer ord) {
205 this.type = type;
206 this.order = ord;
207 }
208
209
210
211
212
213 public int getType() {
214 return this.type;
215 }
216
217
218
219
220
221 public int getOrder() {
222 return this.order;
223 }
224 }
225 }