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 java.util.Arrays;
23
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
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
86 public class ParenPadCheck extends AbstractParenPadCheck {
87
88
89
90
91 private final int[] acceptableTokens;
92
93
94
95
96 public ParenPadCheck() {
97 acceptableTokens = makeAcceptableTokens();
98 Arrays.sort(acceptableTokens);
99 }
100
101 @Override
102 public int[] getDefaultTokens() {
103 return makeAcceptableTokens();
104 }
105
106 @Override
107 public int[] getAcceptableTokens() {
108 return makeAcceptableTokens();
109 }
110
111 @Override
112 public int[] getRequiredTokens() {
113 return CommonUtil.EMPTY_INT_ARRAY;
114 }
115
116 @Override
117 public void visitToken(DetailAST ast) {
118 switch (ast.getType()) {
119 case TokenTypes.METHOD_CALL:
120 processLeft(ast);
121 processRight(ast.findFirstToken(TokenTypes.RPAREN));
122 break;
123 case TokenTypes.DOT:
124 case TokenTypes.EXPR:
125 case TokenTypes.QUESTION:
126 processExpression(ast);
127 break;
128 case TokenTypes.LITERAL_FOR:
129 visitLiteralFor(ast);
130 break;
131 case TokenTypes.ANNOTATION:
132 case TokenTypes.ENUM_CONSTANT_DEF:
133 case TokenTypes.LITERAL_NEW:
134 case TokenTypes.LITERAL_SYNCHRONIZED:
135 case TokenTypes.LAMBDA:
136 visitTokenWithOptionalParentheses(ast);
137 break;
138 case TokenTypes.RESOURCE_SPECIFICATION:
139 visitResourceSpecification(ast);
140 break;
141 default:
142 processLeft(ast.findFirstToken(TokenTypes.LPAREN));
143 processRight(ast.findFirstToken(TokenTypes.RPAREN));
144 }
145 }
146
147
148
149
150
151
152
153
154 private void visitTokenWithOptionalParentheses(DetailAST ast) {
155 final DetailAST parenAst = ast.findFirstToken(TokenTypes.LPAREN);
156 if (parenAst != null) {
157 processLeft(parenAst);
158 processRight(ast.findFirstToken(TokenTypes.RPAREN));
159 }
160 }
161
162
163
164
165
166 private void visitResourceSpecification(DetailAST ast) {
167 processLeft(ast.findFirstToken(TokenTypes.LPAREN));
168 final DetailAST rparen = ast.findFirstToken(TokenTypes.RPAREN);
169 if (!hasPrecedingSemiColon(rparen)) {
170 processRight(rparen);
171 }
172 }
173
174
175
176
177
178
179 private static boolean hasPrecedingSemiColon(DetailAST ast) {
180 return ast.getPreviousSibling().getType() == TokenTypes.SEMI;
181 }
182
183
184
185
186
187 private void visitLiteralFor(DetailAST ast) {
188 final DetailAST lparen = ast.findFirstToken(TokenTypes.LPAREN);
189 if (!isPrecedingEmptyForInit(lparen)) {
190 processLeft(lparen);
191 }
192 final DetailAST rparen = ast.findFirstToken(TokenTypes.RPAREN);
193 if (!isFollowsEmptyForIterator(rparen)) {
194 processRight(rparen);
195 }
196 }
197
198
199
200
201
202
203 private void processExpression(DetailAST ast) {
204 DetailAST childAst = ast.getFirstChild();
205 while (childAst != null) {
206 if (childAst.getType() == TokenTypes.LPAREN) {
207 processLeft(childAst);
208 }
209 else if (childAst.getType() == TokenTypes.RPAREN && !isInTypecast(childAst)) {
210 processRight(childAst);
211 }
212 else if (!isAcceptableToken(childAst)) {
213
214
215 processExpression(childAst);
216 }
217 childAst = childAst.getNextSibling();
218 }
219 }
220
221
222
223
224
225
226 private boolean isAcceptableToken(DetailAST ast) {
227 boolean result = false;
228 if (Arrays.binarySearch(acceptableTokens, ast.getType()) >= 0) {
229 result = true;
230 }
231 return result;
232 }
233
234
235
236
237
238 private static int[] makeAcceptableTokens() {
239 return new int[] {TokenTypes.ANNOTATION,
240 TokenTypes.ANNOTATION_FIELD_DEF,
241 TokenTypes.CTOR_CALL,
242 TokenTypes.CTOR_DEF,
243 TokenTypes.DOT,
244 TokenTypes.ENUM_CONSTANT_DEF,
245 TokenTypes.EXPR,
246 TokenTypes.LITERAL_CATCH,
247 TokenTypes.LITERAL_DO,
248 TokenTypes.LITERAL_FOR,
249 TokenTypes.LITERAL_IF,
250 TokenTypes.LITERAL_NEW,
251 TokenTypes.LITERAL_SWITCH,
252 TokenTypes.LITERAL_SYNCHRONIZED,
253 TokenTypes.LITERAL_WHILE,
254 TokenTypes.METHOD_CALL,
255 TokenTypes.METHOD_DEF,
256 TokenTypes.QUESTION,
257 TokenTypes.RESOURCE_SPECIFICATION,
258 TokenTypes.SUPER_CTOR_CALL,
259 TokenTypes.LAMBDA,
260 };
261 }
262
263
264
265
266
267
268
269 private static boolean isInTypecast(DetailAST ast) {
270 boolean result = false;
271 if (ast.getParent().getType() == TokenTypes.TYPECAST) {
272 final DetailAST firstRparen = ast.getParent().findFirstToken(TokenTypes.RPAREN);
273 if (firstRparen.getLineNo() == ast.getLineNo()
274 && firstRparen.getColumnNo() == ast.getColumnNo()) {
275 result = true;
276 }
277 }
278 return result;
279 }
280
281
282
283
284
285
286 private static boolean isFollowsEmptyForIterator(DetailAST ast) {
287 boolean result = false;
288 final DetailAST parent = ast.getParent();
289
290 if (parent.findFirstToken(TokenTypes.FOR_EACH_CLAUSE) == null) {
291 final DetailAST forIterator =
292 parent.findFirstToken(TokenTypes.FOR_ITERATOR);
293 result = forIterator.getChildCount() == 0;
294 }
295 return result;
296 }
297
298
299
300
301
302
303 private static boolean isPrecedingEmptyForInit(DetailAST ast) {
304 boolean result = false;
305 final DetailAST parent = ast.getParent();
306
307 if (parent.findFirstToken(TokenTypes.FOR_EACH_CLAUSE) == null) {
308 final DetailAST forIterator =
309 parent.findFirstToken(TokenTypes.FOR_INIT);
310 result = forIterator.getChildCount() == 0;
311 }
312 return result;
313 }
314
315 }