2 * Copyright 2003-2009 Dave Griffith, Bas Leijdekkers
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.siyeh
.ig
.psiutils
;
18 import com
.intellij
.psi
.*;
19 import com
.intellij
.psi
.tree
.IElementType
;
20 import com
.intellij
.psi
.util
.PsiTreeUtil
;
21 import com
.intellij
.util
.IncorrectOperationException
;
22 import org
.jetbrains
.annotations
.NotNull
;
23 import org
.jetbrains
.annotations
.Nullable
;
25 import java
.util
.HashMap
;
28 public class ParenthesesUtils
{
30 private ParenthesesUtils(){}
32 public static final int PARENTHESIZED_PRECEDENCE
= 0;
33 public static final int LITERAL_PRECEDENCE
= 0;
34 public static final int METHOD_CALL_PRECEDENCE
= 1;
35 public static final int POSTFIX_PRECEDENCE
= 2;
36 public static final int PREFIX_PRECEDENCE
= 3;
37 public static final int TYPE_CAST_PRECEDENCE
= 4;
38 public static final int MULTIPLICATIVE_PRECEDENCE
= 5;
39 public static final int ADDITIVE_PRECEDENCE
= 6;
40 public static final int SHIFT_PRECEDENCE
= 7;
41 public static final int RELATIONAL_PRECEDENCE
= 8;
42 public static final int EQUALITY_PRECEDENCE
= 9;
43 public static final int BINARY_AND_PRECEDENCE
= 10;
44 public static final int BINARY_XOR_PRECEDENCE
= 11;
45 public static final int BINARY_OR_PRECEDENCE
= 12;
46 public static final int AND_PRECEDENCE
= 13;
47 public static final int OR_PRECEDENCE
= 14;
48 public static final int CONDITIONAL_PRECEDENCE
= 15;
49 public static final int ASSIGNMENT_PRECEDENCE
= 16;
50 public static final int NUM_PRECEDENCES
= 17;
52 private static final Map
<IElementType
, Integer
> s_binaryOperatorPrecedence
=
53 new HashMap
<IElementType
, Integer
>(NUM_PRECEDENCES
);
56 s_binaryOperatorPrecedence
.put(JavaTokenType
.PLUS
, ADDITIVE_PRECEDENCE
);
57 s_binaryOperatorPrecedence
.put(JavaTokenType
.MINUS
, ADDITIVE_PRECEDENCE
);
58 s_binaryOperatorPrecedence
.put(JavaTokenType
.ASTERISK
, MULTIPLICATIVE_PRECEDENCE
);
59 s_binaryOperatorPrecedence
.put(JavaTokenType
.DIV
, MULTIPLICATIVE_PRECEDENCE
);
60 s_binaryOperatorPrecedence
.put(JavaTokenType
.PERC
, MULTIPLICATIVE_PRECEDENCE
);
61 s_binaryOperatorPrecedence
.put(JavaTokenType
.ANDAND
, AND_PRECEDENCE
);
62 s_binaryOperatorPrecedence
.put(JavaTokenType
.OROR
, OR_PRECEDENCE
);
63 s_binaryOperatorPrecedence
.put(JavaTokenType
.AND
, BINARY_AND_PRECEDENCE
);
64 s_binaryOperatorPrecedence
.put(JavaTokenType
.OR
, BINARY_OR_PRECEDENCE
);
65 s_binaryOperatorPrecedence
.put(JavaTokenType
.XOR
, BINARY_XOR_PRECEDENCE
);
66 s_binaryOperatorPrecedence
.put(JavaTokenType
.LTLT
, SHIFT_PRECEDENCE
);
67 s_binaryOperatorPrecedence
.put(JavaTokenType
.GTGT
, SHIFT_PRECEDENCE
);
68 s_binaryOperatorPrecedence
.put(JavaTokenType
.GTGTGT
, SHIFT_PRECEDENCE
);
69 s_binaryOperatorPrecedence
.put(JavaTokenType
.GT
, RELATIONAL_PRECEDENCE
);
70 s_binaryOperatorPrecedence
.put(JavaTokenType
.GE
, RELATIONAL_PRECEDENCE
);
71 s_binaryOperatorPrecedence
.put(JavaTokenType
.LT
, RELATIONAL_PRECEDENCE
);
72 s_binaryOperatorPrecedence
.put(JavaTokenType
.LE
, RELATIONAL_PRECEDENCE
);
73 s_binaryOperatorPrecedence
.put(JavaTokenType
.EQEQ
, EQUALITY_PRECEDENCE
);
74 s_binaryOperatorPrecedence
.put(JavaTokenType
.NE
, EQUALITY_PRECEDENCE
);
78 public static PsiExpression
stripParentheses(
79 @Nullable PsiExpression expression
){
80 while(expression
instanceof PsiParenthesizedExpression
){
81 final PsiParenthesizedExpression parenthesizedExpression
=
82 (PsiParenthesizedExpression
)expression
;
83 expression
= parenthesizedExpression
.getExpression();
88 public static boolean isCommutativeBinaryOperator(
89 @NotNull IElementType token
) {
90 return !(token
.equals(JavaTokenType
.MINUS
) ||
91 token
.equals(JavaTokenType
.DIV
) ||
92 token
.equals(JavaTokenType
.PERC
) ||
93 token
.equals(JavaTokenType
.LTLT
) ||
94 token
.equals(JavaTokenType
.GTGT
) ||
95 token
.equals(JavaTokenType
.GTGTGT
));
98 public static int getPrecedence(PsiExpression expression
){
99 if(expression
instanceof PsiThisExpression
||
100 expression
instanceof PsiLiteralExpression
||
101 expression
instanceof PsiSuperExpression
||
102 expression
instanceof PsiClassObjectAccessExpression
||
103 expression
instanceof PsiArrayAccessExpression
||
104 expression
instanceof PsiArrayInitializerExpression
){
105 return LITERAL_PRECEDENCE
;
107 if(expression
instanceof PsiReferenceExpression
){
108 final PsiReferenceExpression referenceExpression
=
109 (PsiReferenceExpression
)expression
;
110 if(referenceExpression
.getQualifier() != null){
111 return METHOD_CALL_PRECEDENCE
;
113 return LITERAL_PRECEDENCE
;
116 if(expression
instanceof PsiMethodCallExpression
||
117 expression
instanceof PsiNewExpression
){
118 return METHOD_CALL_PRECEDENCE
;
120 if(expression
instanceof PsiTypeCastExpression
){
121 return TYPE_CAST_PRECEDENCE
;
123 if(expression
instanceof PsiPrefixExpression
){
124 return PREFIX_PRECEDENCE
;
126 if(expression
instanceof PsiPostfixExpression
){
127 return POSTFIX_PRECEDENCE
;
129 if(expression
instanceof PsiBinaryExpression
){
130 final PsiBinaryExpression binaryExpression
=
131 (PsiBinaryExpression
)expression
;
132 final PsiJavaToken sign
=
133 binaryExpression
.getOperationSign();
134 return getPrecedenceForBinaryOperator(sign
);
136 if(expression
instanceof PsiInstanceOfExpression
){
137 return RELATIONAL_PRECEDENCE
;
139 if(expression
instanceof PsiConditionalExpression
){
140 return CONDITIONAL_PRECEDENCE
;
142 if(expression
instanceof PsiAssignmentExpression
){
143 return ASSIGNMENT_PRECEDENCE
;
145 if(expression
instanceof PsiParenthesizedExpression
){
146 return PARENTHESIZED_PRECEDENCE
;
151 public static int getPrecedenceForBinaryOperator(@NotNull PsiJavaToken sign
){
152 final IElementType tokenType
= sign
.getTokenType();
153 return getPrecedenceForBinaryOperator(tokenType
);
156 public static int getPrecedenceForBinaryOperator(IElementType operator
) {
157 final Integer precedence
= s_binaryOperatorPrecedence
.get(operator
);
158 return precedence
.intValue();
161 public static void removeParentheses(@NotNull PsiExpression expression
,
162 boolean ignoreClarifyingParentheses
)
163 throws IncorrectOperationException
{
164 if(expression
instanceof PsiMethodCallExpression
){
165 final PsiMethodCallExpression methodCall
=
166 (PsiMethodCallExpression
)expression
;
167 removeParensFromMethodCallExpression(methodCall
,
168 ignoreClarifyingParentheses
);
170 if(expression
instanceof PsiReferenceExpression
){
171 final PsiReferenceExpression referenceExpression
=
172 (PsiReferenceExpression
)expression
;
173 removeParensFromReferenceExpression(referenceExpression
,
174 ignoreClarifyingParentheses
);
176 if(expression
instanceof PsiNewExpression
){
177 final PsiNewExpression newExpression
= (PsiNewExpression
)expression
;
178 removeParensFromNewExpression(newExpression
,
179 ignoreClarifyingParentheses
);
181 if(expression
instanceof PsiAssignmentExpression
){
182 final PsiAssignmentExpression assignmentExpression
=
183 (PsiAssignmentExpression
)expression
;
184 removeParensFromAssignmentExpression(assignmentExpression
,
185 ignoreClarifyingParentheses
);
187 if(expression
instanceof PsiArrayInitializerExpression
){
188 final PsiArrayInitializerExpression arrayInitializerExpression
=
189 (PsiArrayInitializerExpression
)expression
;
190 removeParensFromArrayInitializerExpression(
191 arrayInitializerExpression
, ignoreClarifyingParentheses
);
193 if(expression
instanceof PsiTypeCastExpression
){
194 final PsiTypeCastExpression typeCastExpression
=
195 (PsiTypeCastExpression
)expression
;
196 removeParensFromTypeCastExpression(typeCastExpression
,
197 ignoreClarifyingParentheses
);
199 if(expression
instanceof PsiArrayAccessExpression
){
200 final PsiArrayAccessExpression arrayAccessExpression
=
201 (PsiArrayAccessExpression
)expression
;
202 removeParensFromArrayAccessExpression(arrayAccessExpression
,
203 ignoreClarifyingParentheses
);
205 if(expression
instanceof PsiPrefixExpression
){
206 final PsiPrefixExpression prefixExpression
=
207 (PsiPrefixExpression
)expression
;
208 removeParensFromPrefixExpression(prefixExpression
,
209 ignoreClarifyingParentheses
);
211 if(expression
instanceof PsiPostfixExpression
){
212 final PsiPostfixExpression postfixExpression
=
213 (PsiPostfixExpression
)expression
;
214 removeParensFromPostfixExpression(postfixExpression
,
215 ignoreClarifyingParentheses
);
217 if(expression
instanceof PsiBinaryExpression
){
218 final PsiBinaryExpression binaryExpression
=
219 (PsiBinaryExpression
)expression
;
220 removeParensFromBinaryExpression(binaryExpression
,
221 ignoreClarifyingParentheses
);
223 if(expression
instanceof PsiInstanceOfExpression
){
224 final PsiInstanceOfExpression instanceofExpression
=
225 (PsiInstanceOfExpression
)expression
;
226 removeParensFromInstanceOfExpression(instanceofExpression
,
227 ignoreClarifyingParentheses
);
229 if(expression
instanceof PsiConditionalExpression
){
230 final PsiConditionalExpression conditionalExpression
=
231 (PsiConditionalExpression
)expression
;
232 removeParensFromConditionalExpression(conditionalExpression
,
233 ignoreClarifyingParentheses
);
235 if(expression
instanceof PsiParenthesizedExpression
){
236 final PsiParenthesizedExpression parenthesizedExpression
=
237 (PsiParenthesizedExpression
)expression
;
238 removeParensFromParenthesizedExpression(
239 parenthesizedExpression
, ignoreClarifyingParentheses
);
243 private static void removeParensFromReferenceExpression(
244 @NotNull PsiReferenceExpression referenceExpression
,
245 boolean ignoreClarifyingParentheses
)
246 throws IncorrectOperationException
{
247 final PsiExpression qualifier
=
248 referenceExpression
.getQualifierExpression();
249 if(qualifier
!= null){
250 removeParentheses(qualifier
, ignoreClarifyingParentheses
);
254 private static void removeParensFromParenthesizedExpression(
255 @NotNull PsiParenthesizedExpression parenthesizedExpression
,
256 boolean ignoreClarifyingParentheses
)
257 throws IncorrectOperationException
{
258 final PsiExpression body
= parenthesizedExpression
.getExpression();
260 parenthesizedExpression
.delete();
263 final PsiElement parent
= parenthesizedExpression
.getParent();
264 if(!(parent
instanceof PsiExpression
) ||
265 parent
instanceof PsiParenthesizedExpression
){
266 final PsiExpression newExpression
=
267 (PsiExpression
) parenthesizedExpression
.replace(body
);
268 removeParentheses(newExpression
, ignoreClarifyingParentheses
);
271 final PsiExpression parentExpression
= (PsiExpression
) parent
;
272 final int parentPrecedence
= getPrecedence(parentExpression
);
273 final int childPrecedence
= getPrecedence(body
);
274 if(parentPrecedence
< childPrecedence
){
275 final PsiElement bodyParent
= body
.getParent();
276 final PsiParenthesizedExpression newParenthesizedExpression
=
277 (PsiParenthesizedExpression
)
278 parenthesizedExpression
.replace(bodyParent
);
279 final PsiExpression expression
=
280 newParenthesizedExpression
.getExpression();
281 if (expression
!= null) {
282 removeParentheses(expression
, ignoreClarifyingParentheses
);
284 } else if(parentPrecedence
== childPrecedence
){
285 if(parentExpression
instanceof PsiBinaryExpression
&&
286 body
instanceof PsiBinaryExpression
){
287 final PsiBinaryExpression parentBinaryExpression
=
288 (PsiBinaryExpression
)parentExpression
;
289 final IElementType parentOperator
=
290 parentBinaryExpression
.getOperationTokenType();
291 final PsiBinaryExpression bodyBinaryExpression
=
292 (PsiBinaryExpression
)body
;
293 final IElementType bodyOperator
=
294 bodyBinaryExpression
.getOperationTokenType();
295 final PsiType parentType
= parentBinaryExpression
.getType();
296 final PsiType bodyType
= body
.getType();
297 if(parentType
!= null && parentType
.equals(bodyType
) &&
298 parentOperator
.equals(bodyOperator
)) {
299 final PsiExpression rhs
=
300 parentBinaryExpression
.getROperand();
301 if (!PsiTreeUtil
.isAncestor(rhs
, body
, true) ||
302 isCommutativeBinaryOperator(bodyOperator
)) {
303 // use addAfter() + delete() instead of replace() to
304 // workaround automatic insertion of parentheses by psi
305 final PsiExpression newExpression
= (PsiExpression
)
306 parent
.addAfter(body
, parenthesizedExpression
);
307 parenthesizedExpression
.delete();
308 removeParentheses(newExpression
,
309 ignoreClarifyingParentheses
);
313 if (ignoreClarifyingParentheses
) {
314 if (parentOperator
.equals(bodyOperator
)) {
315 removeParentheses(body
, ignoreClarifyingParentheses
);
318 final PsiExpression newExpression
= (PsiExpression
)
319 parenthesizedExpression
.replace(body
);
320 removeParentheses(newExpression
,
321 ignoreClarifyingParentheses
);
324 final PsiExpression newExpression
=
325 (PsiExpression
) parenthesizedExpression
.replace(body
);
326 removeParentheses(newExpression
, ignoreClarifyingParentheses
);
329 if (ignoreClarifyingParentheses
&&
330 parent
instanceof PsiBinaryExpression
&&
331 (body
instanceof PsiBinaryExpression
||
332 body
instanceof PsiInstanceOfExpression
)) {
333 removeParentheses(body
, ignoreClarifyingParentheses
);
335 final PsiExpression newExpression
=
336 (PsiExpression
) parenthesizedExpression
.replace(body
);
337 removeParentheses(newExpression
, ignoreClarifyingParentheses
);
342 private static void removeParensFromConditionalExpression(
343 @NotNull PsiConditionalExpression conditionalExpression
,
344 boolean ignoreClarifyingParentheses
)
345 throws IncorrectOperationException
{
346 final PsiExpression condition
= conditionalExpression
.getCondition();
347 removeParentheses(condition
, ignoreClarifyingParentheses
);
348 final PsiExpression thenBranch
=
349 conditionalExpression
.getThenExpression();
350 if (thenBranch
!= null) {
351 removeParentheses(thenBranch
, ignoreClarifyingParentheses
);
353 final PsiExpression elseBranch
=
354 conditionalExpression
.getElseExpression();
355 if (elseBranch
!= null) {
356 removeParentheses(elseBranch
, ignoreClarifyingParentheses
);
360 private static void removeParensFromInstanceOfExpression(
361 @NotNull PsiInstanceOfExpression instanceofExpression
,
362 boolean ignoreClarifyingParentheses
)
363 throws IncorrectOperationException
{
364 final PsiExpression operand
= instanceofExpression
.getOperand();
365 removeParentheses(operand
, ignoreClarifyingParentheses
);
368 private static void removeParensFromBinaryExpression(
369 @NotNull PsiBinaryExpression binaryExpression
,
370 boolean ignoreClarifyingParentheses
)
371 throws IncorrectOperationException
{
372 final PsiExpression lhs
= binaryExpression
.getLOperand();
373 removeParentheses(lhs
, ignoreClarifyingParentheses
);
374 final PsiExpression rhs
= binaryExpression
.getROperand();
376 removeParentheses(rhs
, ignoreClarifyingParentheses
);
380 private static void removeParensFromPostfixExpression(
381 @NotNull PsiPostfixExpression postfixExpression
,
382 boolean ignoreClarifyingParentheses
)
383 throws IncorrectOperationException
{
384 final PsiExpression operand
= postfixExpression
.getOperand();
385 removeParentheses(operand
, ignoreClarifyingParentheses
);
388 private static void removeParensFromPrefixExpression(
389 @NotNull PsiPrefixExpression prefixExpression
,
390 boolean ignoreClarifyingParentheses
)
391 throws IncorrectOperationException
{
392 final PsiExpression operand
= prefixExpression
.getOperand();
393 if (operand
!= null) {
394 removeParentheses(operand
, ignoreClarifyingParentheses
);
398 private static void removeParensFromArrayAccessExpression(
399 @NotNull PsiArrayAccessExpression arrayAccessExpression
,
400 boolean ignoreClarifyingParentheses
)
401 throws IncorrectOperationException
{
402 final PsiExpression arrayExpression
=
403 arrayAccessExpression
.getArrayExpression();
404 removeParentheses(arrayExpression
, ignoreClarifyingParentheses
);
405 final PsiExpression indexExpression
=
406 arrayAccessExpression
.getIndexExpression();
407 if (indexExpression
!= null) {
408 removeParentheses(indexExpression
, ignoreClarifyingParentheses
);
412 private static void removeParensFromTypeCastExpression(
413 @NotNull PsiTypeCastExpression typeCastExpression
,
414 boolean ignoreClarifyingParentheses
)
415 throws IncorrectOperationException
{
416 final PsiExpression operand
= typeCastExpression
.getOperand();
417 if (operand
!= null) {
418 removeParentheses(operand
, ignoreClarifyingParentheses
);
422 private static void removeParensFromArrayInitializerExpression(
423 @NotNull PsiArrayInitializerExpression arrayInitializerExpression
,
424 boolean ignoreClarifyingParentheses
)
425 throws IncorrectOperationException
{
426 final PsiExpression
[] initializers
=
427 arrayInitializerExpression
.getInitializers();
428 for (final PsiExpression initializer
: initializers
) {
429 removeParentheses(initializer
, ignoreClarifyingParentheses
);
433 private static void removeParensFromAssignmentExpression(
434 @NotNull PsiAssignmentExpression assignment
,
435 boolean ignoreClarifyingParentheses
)
436 throws IncorrectOperationException
{
437 final PsiExpression lhs
= assignment
.getLExpression();
438 final PsiExpression rhs
= assignment
.getRExpression();
439 removeParentheses(lhs
, ignoreClarifyingParentheses
);
441 removeParentheses(rhs
, ignoreClarifyingParentheses
);
445 private static void removeParensFromNewExpression(
446 @NotNull PsiNewExpression newExpression
,
447 boolean ignoreClarifyingParentheses
)
448 throws IncorrectOperationException
{
449 final PsiExpression
[] dimensions
= newExpression
.getArrayDimensions();
450 for (PsiExpression dimension
: dimensions
) {
451 removeParentheses(dimension
, ignoreClarifyingParentheses
);
453 final PsiExpression qualifier
= newExpression
.getQualifier();
454 if(qualifier
!= null){
455 removeParentheses(qualifier
, ignoreClarifyingParentheses
);
457 final PsiExpression arrayInitializer
=
458 newExpression
.getArrayInitializer();
459 if(arrayInitializer
!= null){
460 removeParentheses(arrayInitializer
, ignoreClarifyingParentheses
);
462 final PsiExpressionList argumentList
= newExpression
.getArgumentList();
463 if(argumentList
!= null){
464 final PsiExpression
[] arguments
= argumentList
.getExpressions();
465 for (PsiExpression argument
: arguments
) {
466 removeParentheses(argument
, ignoreClarifyingParentheses
);
471 private static void removeParensFromMethodCallExpression(
472 @NotNull PsiMethodCallExpression methodCallExpression
,
473 boolean ignoreClarifyingParentheses
)
474 throws IncorrectOperationException
{
475 final PsiReferenceExpression target
=
476 methodCallExpression
.getMethodExpression();
477 final PsiExpressionList argumentList
=
478 methodCallExpression
.getArgumentList();
479 final PsiExpression
[] arguments
= argumentList
.getExpressions();
480 removeParentheses(target
, ignoreClarifyingParentheses
);
481 for (final PsiExpression argument
: arguments
) {
482 removeParentheses(argument
, ignoreClarifyingParentheses
);
486 public static boolean areParenthesesNeeded(
487 PsiParenthesizedExpression expression
,
488 boolean ignoreClarifyingParentheses
) {
489 final PsiElement parent
= expression
.getParent();
490 final PsiExpression child
= expression
.getExpression();
491 return areParenthesesNeeded(child
, parent
,
492 ignoreClarifyingParentheses
);
495 public static boolean areParenthesesNeeded(
496 PsiExpression expression
, PsiElement parentExpression
,
497 boolean ignoreClarifyingParentheses
) {
498 if (parentExpression
instanceof PsiBinaryExpression
) {
499 final PsiBinaryExpression parentBinaryExpression
=
500 (PsiBinaryExpression
) parentExpression
;
501 if (expression
instanceof PsiBinaryExpression
) {
502 final PsiBinaryExpression childBinaryExpression
=
503 (PsiBinaryExpression
)expression
;
504 final IElementType childOperator
=
505 childBinaryExpression
.getOperationTokenType();
506 final IElementType parentOperator
=
507 parentBinaryExpression
.getOperationTokenType();
508 if (ignoreClarifyingParentheses
&&
509 !childOperator
.equals(parentOperator
)) {
512 final PsiType parentType
= parentBinaryExpression
.getType();
513 if (parentType
== null) {
516 final PsiType childType
= childBinaryExpression
.getType();
517 if (!parentType
.equals(childType
)) {
520 if (PsiTreeUtil
.isAncestor(parentBinaryExpression
.getROperand(),
521 expression
, false)) {
522 if (!isCommutativeBinaryOperator(parentOperator
)) {
527 } else if (expression
instanceof PsiConditionalExpression
) {
528 if (PsiTreeUtil
.isAncestor(parentBinaryExpression
.getROperand(),
529 expression
, false)) {
533 } else if (parentExpression
instanceof PsiPrefixExpression
) {
534 if (expression
instanceof PsiBinaryExpression
) {