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 @StatelessCheck
76 public class ModifierOrderCheck
77 extends AbstractCheck {
78
79
80
81
82
83 public static final String MSG_ANNOTATION_ORDER = "annotation.order";
84
85
86
87
88
89 public static final String MSG_MODIFIER_ORDER = "mod.order";
90
91
92
93
94
95 private static final String[] JLS_ORDER = {
96 "public", "protected", "private", "abstract", "default", "static",
97 "sealed", "non-sealed", "final", "transient", "volatile",
98 "synchronized", "native", "strictfp",
99 };
100
101 @Override
102 public int[] getDefaultTokens() {
103 return getRequiredTokens();
104 }
105
106 @Override
107 public int[] getAcceptableTokens() {
108 return getRequiredTokens();
109 }
110
111 @Override
112 public int[] getRequiredTokens() {
113 return new int[] {TokenTypes.MODIFIERS};
114 }
115
116 @Override
117 public void visitToken(DetailAST ast) {
118 final List<DetailAST> mods = new ArrayList<>();
119 DetailAST modifier = ast.getFirstChild();
120 while (modifier != null) {
121 mods.add(modifier);
122 modifier = modifier.getNextSibling();
123 }
124
125 if (!mods.isEmpty()) {
126 final DetailAST error = checkOrderSuggestedByJls(mods);
127 if (error != null) {
128 if (error.getType() == TokenTypes.ANNOTATION) {
129 log(error,
130 MSG_ANNOTATION_ORDER,
131 error.getFirstChild().getText()
132 + error.getFirstChild().getNextSibling()
133 .getText());
134 }
135 else {
136 log(error, MSG_MODIFIER_ORDER, error.getText());
137 }
138 }
139 }
140 }
141
142
143
144
145
146
147
148
149
150 private static DetailAST checkOrderSuggestedByJls(List<DetailAST> modifiers) {
151 final Iterator<DetailAST> iterator = modifiers.iterator();
152
153
154 DetailAST modifier = skipAnnotations(iterator);
155
156 DetailAST offendingModifier = null;
157
158
159 if (modifier.getType() != TokenTypes.ANNOTATION) {
160 int index = 0;
161
162 while (modifier != null
163 && offendingModifier == null) {
164 if (modifier.getType() == TokenTypes.ANNOTATION) {
165 if (!isAnnotationOnType(modifier)) {
166
167 offendingModifier = modifier;
168 }
169 break;
170 }
171
172 while (index < JLS_ORDER.length
173 && !JLS_ORDER[index].equals(modifier.getText())) {
174 index++;
175 }
176
177 if (index == JLS_ORDER.length) {
178
179 offendingModifier = modifier;
180 }
181 else if (iterator.hasNext()) {
182 modifier = iterator.next();
183 }
184 else {
185
186 modifier = null;
187 }
188 }
189 }
190 return offendingModifier;
191 }
192
193
194
195
196
197
198
199 private static DetailAST skipAnnotations(Iterator<DetailAST> modifierIterator) {
200 DetailAST modifier;
201 do {
202 modifier = modifierIterator.next();
203 } while (modifierIterator.hasNext() && modifier.getType() == TokenTypes.ANNOTATION);
204 return modifier;
205 }
206
207
208
209
210
211
212
213 private static boolean isAnnotationOnType(DetailAST modifier) {
214 boolean annotationOnType = false;
215 final DetailAST modifiers = modifier.getParent();
216 final DetailAST definition = modifiers.getParent();
217 final int definitionType = definition.getType();
218 if (definitionType == TokenTypes.VARIABLE_DEF
219 || definitionType == TokenTypes.PARAMETER_DEF
220 || definitionType == TokenTypes.CTOR_DEF) {
221 annotationOnType = true;
222 }
223 else if (definitionType == TokenTypes.METHOD_DEF) {
224 final DetailAST typeToken = definition.findFirstToken(TokenTypes.TYPE);
225 final int methodReturnType = typeToken.getLastChild().getType();
226 if (methodReturnType != TokenTypes.LITERAL_VOID) {
227 annotationOnType = true;
228 }
229 }
230 return annotationOnType;
231 }
232
233 }