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.whitespace;
21
22 import com.puppycrawl.tools.checkstyle.StatelessCheck;
23 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
24 import com.puppycrawl.tools.checkstyle.api.DetailAST;
25 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
26 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
27
28
29
30
31
32
33
34
35
36
37
38
39 @StatelessCheck
40 public class WhitespaceAfterCheck
41 extends AbstractCheck {
42
43
44
45
46
47 public static final String MSG_WS_NOT_FOLLOWED = "ws.notFollowed";
48
49
50
51
52
53 public static final String MSG_WS_TYPECAST = "ws.typeCast";
54
55 @Override
56 public int[] getDefaultTokens() {
57 return new int[] {
58 TokenTypes.COMMA,
59 TokenTypes.SEMI,
60 TokenTypes.TYPECAST,
61 TokenTypes.LITERAL_IF,
62 TokenTypes.LITERAL_ELSE,
63 TokenTypes.LITERAL_WHILE,
64 TokenTypes.LITERAL_DO,
65 TokenTypes.LITERAL_FOR,
66 TokenTypes.LITERAL_FINALLY,
67 TokenTypes.LITERAL_RETURN,
68 TokenTypes.LITERAL_YIELD,
69 TokenTypes.LITERAL_CATCH,
70 TokenTypes.DO_WHILE,
71 TokenTypes.ELLIPSIS,
72 TokenTypes.LITERAL_SWITCH,
73 TokenTypes.LITERAL_SYNCHRONIZED,
74 TokenTypes.LITERAL_TRY,
75 TokenTypes.LITERAL_CASE,
76 TokenTypes.LAMBDA,
77 TokenTypes.LITERAL_WHEN,
78 };
79 }
80
81 @Override
82 public int[] getAcceptableTokens() {
83 return new int[] {
84 TokenTypes.COMMA,
85 TokenTypes.SEMI,
86 TokenTypes.TYPECAST,
87 TokenTypes.LITERAL_IF,
88 TokenTypes.LITERAL_ELSE,
89 TokenTypes.LITERAL_WHILE,
90 TokenTypes.LITERAL_DO,
91 TokenTypes.LITERAL_FOR,
92 TokenTypes.LITERAL_FINALLY,
93 TokenTypes.LITERAL_RETURN,
94 TokenTypes.LITERAL_YIELD,
95 TokenTypes.LITERAL_CATCH,
96 TokenTypes.DO_WHILE,
97 TokenTypes.ELLIPSIS,
98 TokenTypes.LITERAL_SWITCH,
99 TokenTypes.LITERAL_SYNCHRONIZED,
100 TokenTypes.LITERAL_TRY,
101 TokenTypes.LITERAL_CASE,
102 TokenTypes.LAMBDA,
103 TokenTypes.LITERAL_WHEN,
104 TokenTypes.ANNOTATIONS,
105 };
106 }
107
108 @Override
109 public int[] getRequiredTokens() {
110 return CommonUtil.EMPTY_INT_ARRAY;
111 }
112
113 @Override
114 public void visitToken(DetailAST ast) {
115 if (ast.getType() == TokenTypes.TYPECAST) {
116 final DetailAST targetAST = ast.findFirstToken(TokenTypes.RPAREN);
117 final int[] line = getLineCodePoints(targetAST.getLineNo() - 1);
118 if (!isFollowedByWhitespace(targetAST, line)) {
119 log(targetAST, MSG_WS_TYPECAST);
120 }
121 }
122 else if (ast.getType() == TokenTypes.ANNOTATIONS) {
123 if (ast.getFirstChild() != null) {
124 DetailAST targetAST = ast.getFirstChild().getLastChild();
125 if (targetAST.getType() == TokenTypes.DOT) {
126 targetAST = targetAST.getLastChild();
127 }
128 final int[] line = getLineCodePoints(targetAST.getLineNo() - 1);
129 if (!isFollowedByWhitespace(targetAST, line)) {
130 final Object[] message = {targetAST.getText()};
131 log(targetAST, MSG_WS_NOT_FOLLOWED, message);
132 }
133 }
134 }
135 else {
136 final int[] line = getLineCodePoints(ast.getLineNo() - 1);
137 if (!isFollowedByWhitespace(ast, line)) {
138 final Object[] message = {ast.getText()};
139 log(ast, MSG_WS_NOT_FOLLOWED, message);
140 }
141 }
142 }
143
144
145
146
147
148
149
150
151 private static boolean isFollowedByWhitespace(DetailAST targetAST, int... line) {
152 final int after =
153 targetAST.getColumnNo() + targetAST.getText().length();
154 boolean followedByWhitespace = true;
155
156 if (after < line.length) {
157 final int codePoint = line[after];
158
159 followedByWhitespace = codePoint == ';'
160 || codePoint == ')'
161 || Character.isWhitespace(codePoint);
162 }
163 return followedByWhitespace;
164 }
165
166 }