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