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.utils;
21
22 import java.util.ArrayList;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Set;
26 import java.util.regex.Pattern;
27
28 import com.puppycrawl.tools.checkstyle.api.DetailAST;
29 import com.puppycrawl.tools.checkstyle.api.FullIdent;
30 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
31 import com.puppycrawl.tools.checkstyle.checks.naming.AccessModifier;
32
33
34
35
36
37 public final class CheckUtil {
38
39
40
41 private static final int BASE_2 = 2;
42
43
44 private static final int BASE_8 = 8;
45
46
47 private static final int BASE_10 = 10;
48
49
50 private static final int BASE_16 = 16;
51
52
53 private static final int SETTER_GETTER_MAX_CHILDREN = 7;
54
55
56 private static final int SETTER_BODY_SIZE = 3;
57
58
59 private static final int GETTER_BODY_SIZE = 2;
60
61
62 private static final Pattern UNDERSCORE_PATTERN = Pattern.compile("_");
63
64
65 private static final Pattern SETTER_PATTERN = Pattern.compile("^set[A-Z].*");
66
67
68 private static final Pattern GETTER_PATTERN = Pattern.compile("^(is|get)[A-Z].*");
69
70
71 private CheckUtil() {
72 }
73
74
75
76
77
78
79 public static FullIdent createFullType(final DetailAST typeAST) {
80 DetailAST ast = typeAST;
81
82
83 while (ast.findFirstToken(TokenTypes.ARRAY_DECLARATOR) != null) {
84 ast = ast.findFirstToken(TokenTypes.ARRAY_DECLARATOR);
85 }
86
87 return FullIdent.createFullIdent(ast.getFirstChild());
88 }
89
90
91
92
93
94
95
96 public static boolean isEqualsMethod(DetailAST ast) {
97 boolean equalsMethod = false;
98
99 if (ast.getType() == TokenTypes.METHOD_DEF) {
100 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS);
101 final boolean staticOrAbstract =
102 modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) != null
103 || modifiers.findFirstToken(TokenTypes.ABSTRACT) != null;
104
105 if (!staticOrAbstract) {
106 final DetailAST nameNode = ast.findFirstToken(TokenTypes.IDENT);
107 final String name = nameNode.getText();
108
109 if ("equals".equals(name)) {
110
111 final DetailAST paramsNode = ast.findFirstToken(TokenTypes.PARAMETERS);
112 equalsMethod = paramsNode.getChildCount() == 1;
113 }
114 }
115 }
116 return equalsMethod;
117 }
118
119
120
121
122
123
124 public static boolean isElseIf(DetailAST ast) {
125 final DetailAST parentAST = ast.getParent();
126
127 return ast.getType() == TokenTypes.LITERAL_IF
128 && (isElse(parentAST) || isElseWithCurlyBraces(parentAST));
129 }
130
131
132
133
134
135
136 private static boolean isElse(DetailAST ast) {
137 return ast.getType() == TokenTypes.LITERAL_ELSE;
138 }
139
140
141
142
143
144
145
146 private static boolean isElseWithCurlyBraces(DetailAST ast) {
147 return ast.getType() == TokenTypes.SLIST
148 && ast.getChildCount() == 2
149 && isElse(ast.getParent());
150 }
151
152
153
154
155
156
157
158
159
160 public static double parseDouble(String text, int type) {
161 String txt = UNDERSCORE_PATTERN.matcher(text).replaceAll("");
162 final double result;
163 switch (type) {
164 case TokenTypes.NUM_FLOAT:
165 case TokenTypes.NUM_DOUBLE:
166 result = Double.parseDouble(txt);
167 break;
168 case TokenTypes.NUM_INT:
169 case TokenTypes.NUM_LONG:
170 int radix = BASE_10;
171 if (txt.startsWith("0x") || txt.startsWith("0X")) {
172 radix = BASE_16;
173 txt = txt.substring(2);
174 }
175 else if (txt.startsWith("0b") || txt.startsWith("0B")) {
176 radix = BASE_2;
177 txt = txt.substring(2);
178 }
179 else if (CommonUtil.startsWithChar(txt, '0')) {
180 radix = BASE_8;
181 txt = txt.substring(1);
182 }
183 result = parseNumber(txt, radix, type);
184 break;
185 default:
186 result = Double.NaN;
187 break;
188 }
189 return result;
190 }
191
192
193
194
195
196
197
198
199
200
201
202
203 private static double parseNumber(final String text, final int radix, final int type) {
204 String txt = text;
205 if (CommonUtil.endsWithChar(txt, 'L') || CommonUtil.endsWithChar(txt, 'l')) {
206 txt = txt.substring(0, txt.length() - 1);
207 }
208 final double result;
209 if (txt.isEmpty()) {
210 result = 0.0;
211 }
212 else {
213 final boolean negative = txt.charAt(0) == '-';
214 if (type == TokenTypes.NUM_INT) {
215 if (negative) {
216 result = Integer.parseInt(txt, radix);
217 }
218 else {
219 result = Integer.parseUnsignedInt(txt, radix);
220 }
221 }
222 else {
223 if (negative) {
224 result = Long.parseLong(txt, radix);
225 }
226 else {
227 result = Long.parseUnsignedLong(txt, radix);
228 }
229 }
230 }
231 return result;
232 }
233
234
235
236
237
238
239 public static DetailAST getFirstNode(final DetailAST node) {
240 DetailAST currentNode = node;
241 DetailAST child = node.getFirstChild();
242 while (child != null) {
243 final DetailAST newNode = getFirstNode(child);
244 if (newNode.getLineNo() < currentNode.getLineNo()
245 || newNode.getLineNo() == currentNode.getLineNo()
246 && newNode.getColumnNo() < currentNode.getColumnNo()) {
247 currentNode = newNode;
248 }
249 child = child.getNextSibling();
250 }
251
252 return currentNode;
253 }
254
255
256
257
258
259
260 public static List<String> getTypeParameterNames(final DetailAST node) {
261 final DetailAST typeParameters =
262 node.findFirstToken(TokenTypes.TYPE_PARAMETERS);
263
264 final List<String> typeParameterNames = new ArrayList<>();
265 if (typeParameters != null) {
266 final DetailAST typeParam =
267 typeParameters.findFirstToken(TokenTypes.TYPE_PARAMETER);
268 typeParameterNames.add(
269 typeParam.findFirstToken(TokenTypes.IDENT).getText());
270
271 DetailAST sibling = typeParam.getNextSibling();
272 while (sibling != null) {
273 if (sibling.getType() == TokenTypes.TYPE_PARAMETER) {
274 typeParameterNames.add(
275 sibling.findFirstToken(TokenTypes.IDENT).getText());
276 }
277 sibling = sibling.getNextSibling();
278 }
279 }
280
281 return typeParameterNames;
282 }
283
284
285
286
287
288
289 public static List<DetailAST> getTypeParameters(final DetailAST node) {
290 final DetailAST typeParameters =
291 node.findFirstToken(TokenTypes.TYPE_PARAMETERS);
292
293 final List<DetailAST> typeParams = new ArrayList<>();
294 if (typeParameters != null) {
295 final DetailAST typeParam =
296 typeParameters.findFirstToken(TokenTypes.TYPE_PARAMETER);
297 typeParams.add(typeParam);
298
299 DetailAST sibling = typeParam.getNextSibling();
300 while (sibling != null) {
301 if (sibling.getType() == TokenTypes.TYPE_PARAMETER) {
302 typeParams.add(sibling);
303 }
304 sibling = sibling.getNextSibling();
305 }
306 }
307
308 return typeParams;
309 }
310
311
312
313
314
315
316 public static boolean isSetterMethod(final DetailAST ast) {
317 boolean setterMethod = false;
318
319
320
321
322 if (ast.getType() == TokenTypes.METHOD_DEF
323 && ast.getChildCount() == SETTER_GETTER_MAX_CHILDREN) {
324 final DetailAST type = ast.findFirstToken(TokenTypes.TYPE);
325 final String name = type.getNextSibling().getText();
326 final boolean matchesSetterFormat = SETTER_PATTERN.matcher(name).matches();
327 final boolean voidReturnType = type.findFirstToken(TokenTypes.LITERAL_VOID) != null;
328
329 final DetailAST params = ast.findFirstToken(TokenTypes.PARAMETERS);
330 final boolean singleParam = params.getChildCount(TokenTypes.PARAMETER_DEF) == 1;
331
332 if (matchesSetterFormat && voidReturnType && singleParam) {
333
334
335
336
337 final DetailAST slist = ast.findFirstToken(TokenTypes.SLIST);
338
339 if (slist != null && slist.getChildCount() == SETTER_BODY_SIZE) {
340 final DetailAST expr = slist.getFirstChild();
341 setterMethod = expr.getFirstChild().getType() == TokenTypes.ASSIGN;
342 }
343 }
344 }
345 return setterMethod;
346 }
347
348
349
350
351
352
353 public static boolean isGetterMethod(final DetailAST ast) {
354 boolean getterMethod = false;
355
356
357
358
359 if (ast.getType() == TokenTypes.METHOD_DEF
360 && ast.getChildCount() == SETTER_GETTER_MAX_CHILDREN) {
361 final DetailAST type = ast.findFirstToken(TokenTypes.TYPE);
362 final String name = type.getNextSibling().getText();
363 final boolean matchesGetterFormat = GETTER_PATTERN.matcher(name).matches();
364 final boolean noVoidReturnType = type.findFirstToken(TokenTypes.LITERAL_VOID) == null;
365
366 final DetailAST params = ast.findFirstToken(TokenTypes.PARAMETERS);
367 final boolean noParams = params.getChildCount(TokenTypes.PARAMETER_DEF) == 0;
368
369 if (matchesGetterFormat && noVoidReturnType && noParams) {
370
371
372
373 final DetailAST slist = ast.findFirstToken(TokenTypes.SLIST);
374
375 if (slist != null && slist.getChildCount() == GETTER_BODY_SIZE) {
376 final DetailAST expr = slist.getFirstChild();
377 getterMethod = expr.getType() == TokenTypes.LITERAL_RETURN;
378 }
379 }
380 }
381 return getterMethod;
382 }
383
384
385
386
387
388
389
390 public static boolean isNonVoidMethod(DetailAST methodDefAst) {
391 boolean returnValue = false;
392 if (methodDefAst.getType() == TokenTypes.METHOD_DEF) {
393 final DetailAST typeAST = methodDefAst.findFirstToken(TokenTypes.TYPE);
394 if (typeAST.findFirstToken(TokenTypes.LITERAL_VOID) == null) {
395 returnValue = true;
396 }
397 }
398 return returnValue;
399 }
400
401
402
403
404
405
406
407 public static boolean isReceiverParameter(DetailAST parameterDefAst) {
408 return parameterDefAst.getType() == TokenTypes.PARAMETER_DEF
409 && parameterDefAst.findFirstToken(TokenTypes.IDENT) == null;
410 }
411
412
413
414
415
416
417
418 public static AccessModifier getAccessModifierFromModifiersToken(DetailAST modifiersToken) {
419 if (modifiersToken == null || modifiersToken.getType() != TokenTypes.MODIFIERS) {
420 throw new IllegalArgumentException("expected non-null AST-token with type 'MODIFIERS'");
421 }
422
423
424 AccessModifier accessModifier = AccessModifier.PACKAGE;
425 for (DetailAST token = modifiersToken.getFirstChild(); token != null;
426 token = token.getNextSibling()) {
427 final int tokenType = token.getType();
428 if (tokenType == TokenTypes.LITERAL_PUBLIC) {
429 accessModifier = AccessModifier.PUBLIC;
430 }
431 else if (tokenType == TokenTypes.LITERAL_PROTECTED) {
432 accessModifier = AccessModifier.PROTECTED;
433 }
434 else if (tokenType == TokenTypes.LITERAL_PRIVATE) {
435 accessModifier = AccessModifier.PRIVATE;
436 }
437 }
438 return accessModifier;
439 }
440
441
442
443
444
445
446
447 public static Set<String> parseClassNames(String... classNames) {
448 final Set<String> illegalClassNames = new HashSet<>();
449 for (final String name : classNames) {
450 illegalClassNames.add(name);
451 final int lastDot = name.lastIndexOf('.');
452 if (lastDot != -1 && lastDot < name.length() - 1) {
453 final String shortName = name
454 .substring(name.lastIndexOf('.') + 1);
455 illegalClassNames.add(shortName);
456 }
457 }
458 return illegalClassNames;
459 }
460
461 }