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
56
57
58 public WhitespaceAfterCheck() {
59
60 }
61
62 @Override
63 public int[] getDefaultTokens() {
64 return new int[] {
65 TokenTypes.COMMA,
66 TokenTypes.SEMI,
67 TokenTypes.TYPECAST,
68 TokenTypes.LITERAL_IF,
69 TokenTypes.LITERAL_ELSE,
70 TokenTypes.LITERAL_WHILE,
71 TokenTypes.LITERAL_DO,
72 TokenTypes.LITERAL_FOR,
73 TokenTypes.LITERAL_FINALLY,
74 TokenTypes.LITERAL_RETURN,
75 TokenTypes.LITERAL_YIELD,
76 TokenTypes.LITERAL_CATCH,
77 TokenTypes.DO_WHILE,
78 TokenTypes.ELLIPSIS,
79 TokenTypes.LITERAL_SWITCH,
80 TokenTypes.LITERAL_SYNCHRONIZED,
81 TokenTypes.LITERAL_TRY,
82 TokenTypes.LITERAL_CASE,
83 TokenTypes.LAMBDA,
84 TokenTypes.LITERAL_WHEN,
85 };
86 }
87
88 @Override
89 public int[] getAcceptableTokens() {
90 return new int[] {
91 TokenTypes.COMMA,
92 TokenTypes.SEMI,
93 TokenTypes.TYPECAST,
94 TokenTypes.LITERAL_IF,
95 TokenTypes.LITERAL_ELSE,
96 TokenTypes.LITERAL_WHILE,
97 TokenTypes.LITERAL_DO,
98 TokenTypes.LITERAL_FOR,
99 TokenTypes.LITERAL_FINALLY,
100 TokenTypes.LITERAL_RETURN,
101 TokenTypes.LITERAL_YIELD,
102 TokenTypes.LITERAL_CATCH,
103 TokenTypes.DO_WHILE,
104 TokenTypes.ELLIPSIS,
105 TokenTypes.LITERAL_SWITCH,
106 TokenTypes.LITERAL_SYNCHRONIZED,
107 TokenTypes.LITERAL_TRY,
108 TokenTypes.LITERAL_CASE,
109 TokenTypes.LAMBDA,
110 TokenTypes.LITERAL_WHEN,
111 TokenTypes.ANNOTATIONS,
112 };
113 }
114
115 @Override
116 public int[] getRequiredTokens() {
117 return CommonUtil.EMPTY_INT_ARRAY;
118 }
119
120 @Override
121 public void visitToken(DetailAST ast) {
122 if (ast.getType() == TokenTypes.TYPECAST) {
123 final DetailAST targetAST = ast.findFirstToken(TokenTypes.RPAREN);
124 final int[] line = getLineCodePoints(targetAST.getLineNo() - 1);
125 if (!isFollowedByWhitespace(targetAST, line)) {
126 log(targetAST, MSG_WS_TYPECAST);
127 }
128 }
129 else if (ast.getType() == TokenTypes.ANNOTATIONS) {
130 if (ast.getFirstChild() != null) {
131 DetailAST targetAST = ast.getFirstChild().getLastChild();
132 if (targetAST.getType() == TokenTypes.DOT) {
133 targetAST = targetAST.getLastChild();
134 }
135 final int[] line = getLineCodePoints(targetAST.getLineNo() - 1);
136 if (!isFollowedByWhitespace(targetAST, line)) {
137 final Object[] message = {targetAST.getText()};
138 log(targetAST, MSG_WS_NOT_FOLLOWED, message);
139 }
140 }
141 }
142 else {
143 final int[] line = getLineCodePoints(ast.getLineNo() - 1);
144 if (!isFollowedByWhitespace(ast, line)) {
145 final Object[] message = {ast.getText()};
146 log(ast, MSG_WS_NOT_FOLLOWED, message);
147 }
148 }
149 }
150
151
152
153
154
155
156
157
158 private static boolean isFollowedByWhitespace(DetailAST targetAST, int... line) {
159 final int after =
160 targetAST.getColumnNo() + targetAST.getText().length();
161 boolean followedByWhitespace = true;
162
163 if (after < line.length) {
164 final int codePoint = line[after];
165
166 followedByWhitespace = codePoint == ';'
167 || codePoint == ')'
168 || Character.isWhitespace(codePoint);
169 }
170 return followedByWhitespace;
171 }
172
173 }