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.modifier;
21
22 import java.util.ArrayList;
23 import java.util.Iterator;
24 import java.util.List;
25
26 import com.puppycrawl.tools.checkstyle.StatelessCheck;
27 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
28 import com.puppycrawl.tools.checkstyle.api.DetailAST;
29 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 @StatelessCheck
86 public class ModifierOrderCheck
87 extends AbstractCheck {
88
89
90
91
92
93 public static final String MSG_ANNOTATION_ORDER = "annotation.order";
94
95
96
97
98
99 public static final String MSG_MODIFIER_ORDER = "mod.order";
100
101
102
103
104
105 private static final String[] JLS_ORDER = {
106 "public", "protected", "private", "abstract", "default", "static",
107 "sealed", "non-sealed", "final", "transient", "volatile",
108 "synchronized", "native", "strictfp",
109 };
110
111 @Override
112 public int[] getDefaultTokens() {
113 return getRequiredTokens();
114 }
115
116 @Override
117 public int[] getAcceptableTokens() {
118 return getRequiredTokens();
119 }
120
121 @Override
122 public int[] getRequiredTokens() {
123 return new int[] {TokenTypes.MODIFIERS};
124 }
125
126 @Override
127 public void visitToken(DetailAST ast) {
128 final List<DetailAST> mods = new ArrayList<>();
129 DetailAST modifier = ast.getFirstChild();
130 while (modifier != null) {
131 mods.add(modifier);
132 modifier = modifier.getNextSibling();
133 }
134
135 if (!mods.isEmpty()) {
136 final DetailAST error = checkOrderSuggestedByJls(mods);
137 if (error != null) {
138 if (error.getType() == TokenTypes.ANNOTATION) {
139 log(error,
140 MSG_ANNOTATION_ORDER,
141 error.getFirstChild().getText()
142 + error.getFirstChild().getNextSibling()
143 .getText());
144 }
145 else {
146 log(error, MSG_MODIFIER_ORDER, error.getText());
147 }
148 }
149 }
150 }
151
152
153
154
155
156
157
158
159
160 private static DetailAST checkOrderSuggestedByJls(List<DetailAST> modifiers) {
161 final Iterator<DetailAST> iterator = modifiers.iterator();
162
163
164 DetailAST modifier = skipAnnotations(iterator);
165
166 DetailAST offendingModifier = null;
167
168
169 if (modifier.getType() != TokenTypes.ANNOTATION) {
170 int index = 0;
171
172 while (modifier != null
173 && offendingModifier == null) {
174 if (modifier.getType() == TokenTypes.ANNOTATION) {
175 if (!isAnnotationOnType(modifier)) {
176
177 offendingModifier = modifier;
178 }
179 break;
180 }
181
182 while (index < JLS_ORDER.length
183 && !JLS_ORDER[index].equals(modifier.getText())) {
184 index++;
185 }
186
187 if (index == JLS_ORDER.length) {
188
189 offendingModifier = modifier;
190 }
191 else if (iterator.hasNext()) {
192 modifier = iterator.next();
193 }
194 else {
195
196 modifier = null;
197 }
198 }
199 }
200 return offendingModifier;
201 }
202
203
204
205
206
207
208
209 private static DetailAST skipAnnotations(Iterator<DetailAST> modifierIterator) {
210 DetailAST modifier;
211 do {
212 modifier = modifierIterator.next();
213 } while (modifierIterator.hasNext() && modifier.getType() == TokenTypes.ANNOTATION);
214 return modifier;
215 }
216
217
218
219
220
221
222
223 private static boolean isAnnotationOnType(DetailAST modifier) {
224 boolean annotationOnType = false;
225 final DetailAST modifiers = modifier.getParent();
226 final DetailAST definition = modifiers.getParent();
227 final int definitionType = definition.getType();
228 if (definitionType == TokenTypes.VARIABLE_DEF
229 || definitionType == TokenTypes.PARAMETER_DEF
230 || definitionType == TokenTypes.CTOR_DEF) {
231 annotationOnType = true;
232 }
233 else if (definitionType == TokenTypes.METHOD_DEF) {
234 final DetailAST typeToken = definition.findFirstToken(TokenTypes.TYPE);
235 final int methodReturnType = typeToken.getLastChild().getType();
236 if (methodReturnType != TokenTypes.LITERAL_VOID) {
237 annotationOnType = true;
238 }
239 }
240 return annotationOnType;
241 }
242
243 }