2 * Copyright 2003-2008 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 private static final int PARENTHESIZED_PRECEDENCE
= 0;
33 private static final int LITERAL_PRECEDENCE
= 0;
34 public static final int METHOD_CALL_PRECEDENCE
= 1;
35 private 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 private static final int RELATIONAL_PRECEDENCE
= 8;
42 private static final int EQUALITY_PRECEDENCE
= 9;
43 private static final int BINARY_AND_PRECEDENCE
= 10;
44 private static final int BINARY_XOR_PRECEDENCE
= 11;
45 private 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 private static final int ASSIGNMENT_PRECEDENCE
= 16;
50 private static final int NUM_PRECEDENCES
= 17;
52 private static final Map
<String
, Integer
> s_binaryOperatorPrecedence
=
53 new HashMap
<String
, Integer
>(NUM_PRECEDENCES
);
56 s_binaryOperatorPrecedence
.put("+", ADDITIVE_PRECEDENCE
);
57 s_binaryOperatorPrecedence
.put("-", ADDITIVE_PRECEDENCE
);
58 s_binaryOperatorPrecedence
.put("*", MULTIPLICATIVE_PRECEDENCE
);
59 s_binaryOperatorPrecedence
.put("/", MULTIPLICATIVE_PRECEDENCE
);
60 s_binaryOperatorPrecedence
.put("%", MULTIPLICATIVE_PRECEDENCE
);
61 s_binaryOperatorPrecedence
.put("&&", AND_PRECEDENCE
);
62 s_binaryOperatorPrecedence
.put("||", OR_PRECEDENCE
);
63 s_binaryOperatorPrecedence
.put("&", BINARY_AND_PRECEDENCE
);
64 s_binaryOperatorPrecedence
.put("|", BINARY_OR_PRECEDENCE
);
65 s_binaryOperatorPrecedence
.put("^", BINARY_XOR_PRECEDENCE
);
66 s_binaryOperatorPrecedence
.put("<<", SHIFT_PRECEDENCE
);
67 s_binaryOperatorPrecedence
.put(">>", SHIFT_PRECEDENCE
);
68 s_binaryOperatorPrecedence
.put(">>>", SHIFT_PRECEDENCE
);
69 s_binaryOperatorPrecedence
.put(">", RELATIONAL_PRECEDENCE
);
70 s_binaryOperatorPrecedence
.put(">=", RELATIONAL_PRECEDENCE
);
71 s_binaryOperatorPrecedence
.put("<", RELATIONAL_PRECEDENCE
);
72 s_binaryOperatorPrecedence
.put("<=", RELATIONAL_PRECEDENCE
);
73 s_binaryOperatorPrecedence
.put("==", EQUALITY_PRECEDENCE
);
74 s_binaryOperatorPrecedence
.put("!=", 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 private static int getPrecedenceForBinaryOperator(
152 @NotNull PsiJavaToken sign
){
153 final String operator
= sign
.getText();
154 final Integer precedence
= s_binaryOperatorPrecedence
.get(operator
);
155 return precedence
.intValue();
158 public static void removeParentheses(@NotNull PsiExpression expression
,
159 boolean ignoreClarifyingParentheses
)
160 throws IncorrectOperationException
{
161 if(expression
instanceof PsiMethodCallExpression
){
162 final PsiMethodCallExpression methodCall
=
163 (PsiMethodCallExpression
)expression
;
164 removeParensFromMethodCallExpression(methodCall
,
165 ignoreClarifyingParentheses
);
167 if(expression
instanceof PsiReferenceExpression
){
168 final PsiReferenceExpression referenceExpression
=
169 (PsiReferenceExpression
)expression
;
170 removeParensFromReferenceExpression(referenceExpression
,
171 ignoreClarifyingParentheses
);
173 if(expression
instanceof PsiNewExpression
){
174 final PsiNewExpression newExpression
= (PsiNewExpression
)expression
;
175 removeParensFromNewExpression(newExpression
,
176 ignoreClarifyingParentheses
);
178 if(expression
instanceof PsiAssignmentExpression
){
179 final PsiAssignmentExpression assignmentExpression
=
180 (PsiAssignmentExpression
)expression
;
181 removeParensFromAssignmentExpression(assignmentExpression
,
182 ignoreClarifyingParentheses
);
184 if(expression
instanceof PsiArrayInitializerExpression
){
185 final PsiArrayInitializerExpression arrayInitializerExpression
=
186 (PsiArrayInitializerExpression
)expression
;
187 removeParensFromArrayInitializerExpression(
188 arrayInitializerExpression
, ignoreClarifyingParentheses
);
190 if(expression
instanceof PsiTypeCastExpression
){
191 final PsiTypeCastExpression typeCastExpression
=
192 (PsiTypeCastExpression
)expression
;
193 removeParensFromTypeCastExpression(typeCastExpression
,
194 ignoreClarifyingParentheses
);
196 if(expression
instanceof PsiArrayAccessExpression
){
197 final PsiArrayAccessExpression arrayAccessExpression
=
198 (PsiArrayAccessExpression
)expression
;
199 removeParensFromArrayAccessExpression(arrayAccessExpression
,
200 ignoreClarifyingParentheses
);
202 if(expression
instanceof PsiPrefixExpression
){
203 final PsiPrefixExpression prefixExpression
=
204 (PsiPrefixExpression
)expression
;
205 removeParensFromPrefixExpression(prefixExpression
,
206 ignoreClarifyingParentheses
);
208 if(expression
instanceof PsiPostfixExpression
){
209 final PsiPostfixExpression postfixExpression
=
210 (PsiPostfixExpression
)expression
;
211 removeParensFromPostfixExpression(postfixExpression
,
212 ignoreClarifyingParentheses
);
214 if(expression
instanceof PsiBinaryExpression
){
215 final PsiBinaryExpression binaryExpression
=
216 (PsiBinaryExpression
)expression
;
217 removeParensFromBinaryExpression(binaryExpression
,
218 ignoreClarifyingParentheses
);
220 if(expression
instanceof PsiInstanceOfExpression
){
221 final PsiInstanceOfExpression instanceofExpression
=
222 (PsiInstanceOfExpression
)expression
;
223 removeParensFromInstanceOfExpression(instanceofExpression
,
224 ignoreClarifyingParentheses
);
226 if(expression
instanceof PsiConditionalExpression
){
227 final PsiConditionalExpression conditionalExpression
=
228 (PsiConditionalExpression
)expression
;
229 removeParensFromConditionalExpression(conditionalExpression
,
230 ignoreClarifyingParentheses
);
232 if(expression
instanceof PsiParenthesizedExpression
){
233 final PsiParenthesizedExpression parenthesizedExpression
=
234 (PsiParenthesizedExpression
)expression
;
235 removeParensFromParenthesizedExpression(
236 parenthesizedExpression
, ignoreClarifyingParentheses
);
240 private static void removeParensFromReferenceExpression(
241 @NotNull PsiReferenceExpression referenceExpression
,
242 boolean ignoreClarifyingParentheses
)
243 throws IncorrectOperationException
{
244 final PsiExpression qualifier
=
245 referenceExpression
.getQualifierExpression();
246 if(qualifier
!= null){
247 removeParentheses(qualifier
, ignoreClarifyingParentheses
);
251 private static void removeParensFromParenthesizedExpression(
252 @NotNull PsiParenthesizedExpression parenthesizedExpression
,
253 boolean ignoreClarifyingParentheses
)
254 throws IncorrectOperationException
{
255 final PsiExpression body
= parenthesizedExpression
.getExpression();
257 parenthesizedExpression
.delete();
260 final PsiElement parent
= parenthesizedExpression
.getParent();
261 if(!(parent
instanceof PsiExpression
)){
262 final PsiExpression newExpression
=
263 (PsiExpression
) parenthesizedExpression
.replace(body
);
264 removeParentheses(newExpression
, ignoreClarifyingParentheses
);
267 final PsiExpression parentExpression
= (PsiExpression
) parent
;
268 final int parentPrecedence
= getPrecedence(parentExpression
);
269 final int childPrecedence
= getPrecedence(body
);
270 if(parentPrecedence
< childPrecedence
){
271 final PsiElement bodyParent
= body
.getParent();
272 final PsiParenthesizedExpression newParenthesizedExpression
=
273 (PsiParenthesizedExpression
)
274 parenthesizedExpression
.replace(bodyParent
);
275 final PsiExpression expression
=
276 newParenthesizedExpression
.getExpression();
277 if (expression
!= null) {
278 removeParentheses(expression
, ignoreClarifyingParentheses
);
280 } else if(parentPrecedence
== childPrecedence
){
281 if(parentExpression
instanceof PsiBinaryExpression
&&
282 body
instanceof PsiBinaryExpression
){
283 final PsiBinaryExpression parentBinaryExpression
=
284 (PsiBinaryExpression
)parentExpression
;
285 final IElementType parentOperator
=
286 parentBinaryExpression
.getOperationTokenType();
287 final PsiBinaryExpression bodyBinaryExpression
=
288 (PsiBinaryExpression
)body
;
289 final IElementType bodyOperator
=
290 bodyBinaryExpression
.getOperationTokenType();
291 final PsiType parentType
= parentBinaryExpression
.getType();
292 final PsiType bodyType
= body
.getType();
293 if(parentType
!= null && parentType
.equals(bodyType
) &&
294 parentOperator
.equals(bodyOperator
)) {
295 final PsiExpression rhs
=
296 parentBinaryExpression
.getROperand();
297 if (!PsiTreeUtil
.isAncestor(rhs
, body
, true) ||
298 isCommutativeBinaryOperator(bodyOperator
)) {
299 // use addAfter() + delete() instead of replace() to
300 // workaround automatic insertion of parentheses by psi
301 final PsiExpression newExpression
= (PsiExpression
)
302 parent
.addAfter(body
, parenthesizedExpression
);
303 parenthesizedExpression
.delete();
304 removeParentheses(newExpression
,
305 ignoreClarifyingParentheses
);
309 if (ignoreClarifyingParentheses
) {
310 if (parentOperator
.equals(bodyOperator
)) {
311 removeParentheses(body
, ignoreClarifyingParentheses
);
314 final PsiExpression newExpression
= (PsiExpression
)
315 parenthesizedExpression
.replace(body
);
316 removeParentheses(newExpression
,
317 ignoreClarifyingParentheses
);
320 final PsiExpression newExpression
=
321 (PsiExpression
) parenthesizedExpression
.replace(body
);
322 removeParentheses(newExpression
, ignoreClarifyingParentheses
);
325 if (ignoreClarifyingParentheses
&&
326 parent
instanceof PsiBinaryExpression
&&
327 (body
instanceof PsiBinaryExpression
||
328 body
instanceof PsiInstanceOfExpression
)) {
329 removeParentheses(body
, ignoreClarifyingParentheses
);
331 final PsiExpression newExpression
=
332 (PsiExpression
) parenthesizedExpression
.replace(body
);
333 removeParentheses(newExpression
, ignoreClarifyingParentheses
);
338 private static void removeParensFromConditionalExpression(
339 @NotNull PsiConditionalExpression conditionalExpression
,
340 boolean ignoreClarifyingParentheses
)
341 throws IncorrectOperationException
{
342 final PsiExpression condition
= conditionalExpression
.getCondition();
343 removeParentheses(condition
, ignoreClarifyingParentheses
);
344 final PsiExpression thenBranch
=
345 conditionalExpression
.getThenExpression();
346 if (thenBranch
!= null) {
347 removeParentheses(thenBranch
, ignoreClarifyingParentheses
);
349 final PsiExpression elseBranch
=
350 conditionalExpression
.getElseExpression();
351 if (elseBranch
!= null) {
352 removeParentheses(elseBranch
, ignoreClarifyingParentheses
);
356 private static void removeParensFromInstanceOfExpression(
357 @NotNull PsiInstanceOfExpression instanceofExpression
,
358 boolean ignoreClarifyingParentheses
)
359 throws IncorrectOperationException
{
360 final PsiExpression operand
= instanceofExpression
.getOperand();
361 removeParentheses(operand
, ignoreClarifyingParentheses
);
364 private static void removeParensFromBinaryExpression(
365 @NotNull PsiBinaryExpression binaryExpression
,
366 boolean ignoreClarifyingParentheses
)
367 throws IncorrectOperationException
{
368 final PsiExpression lhs
= binaryExpression
.getLOperand();
369 removeParentheses(lhs
, ignoreClarifyingParentheses
);
370 final PsiExpression rhs
= binaryExpression
.getROperand();
372 removeParentheses(rhs
, ignoreClarifyingParentheses
);
376 private static void removeParensFromPostfixExpression(
377 @NotNull PsiPostfixExpression postfixExpression
,
378 boolean ignoreClarifyingParentheses
)
379 throws IncorrectOperationException
{
380 final PsiExpression operand
= postfixExpression
.getOperand();
381 removeParentheses(operand
, ignoreClarifyingParentheses
);
384 private static void removeParensFromPrefixExpression(
385 @NotNull PsiPrefixExpression prefixExpression
,
386 boolean ignoreClarifyingParentheses
)
387 throws IncorrectOperationException
{
388 final PsiExpression operand
= prefixExpression
.getOperand();
389 if (operand
!= null) {
390 removeParentheses(operand
, ignoreClarifyingParentheses
);
394 private static void removeParensFromArrayAccessExpression(
395 @NotNull PsiArrayAccessExpression arrayAccessExpression
,
396 boolean ignoreClarifyingParentheses
)
397 throws IncorrectOperationException
{
398 final PsiExpression arrayExpression
=
399 arrayAccessExpression
.getArrayExpression();
400 removeParentheses(arrayExpression
, ignoreClarifyingParentheses
);
401 final PsiExpression indexExpression
=
402 arrayAccessExpression
.getIndexExpression();
403 if (indexExpression
!= null) {
404 removeParentheses(indexExpression
, ignoreClarifyingParentheses
);
408 private static void removeParensFromTypeCastExpression(
409 @NotNull PsiTypeCastExpression typeCastExpression
,
410 boolean ignoreClarifyingParentheses
)
411 throws IncorrectOperationException
{
412 final PsiExpression operand
= typeCastExpression
.getOperand();
413 if (operand
!= null) {
414 removeParentheses(operand
, ignoreClarifyingParentheses
);
418 private static void removeParensFromArrayInitializerExpression(
419 @NotNull PsiArrayInitializerExpression arrayInitializerExpression
,
420 boolean ignoreClarifyingParentheses
)
421 throws IncorrectOperationException
{
422 final PsiExpression
[] initializers
=
423 arrayInitializerExpression
.getInitializers();
424 for (final PsiExpression initializer
: initializers
) {
425 removeParentheses(initializer
, ignoreClarifyingParentheses
);
429 private static void removeParensFromAssignmentExpression(
430 @NotNull PsiAssignmentExpression assignment
,
431 boolean ignoreClarifyingParentheses
)
432 throws IncorrectOperationException
{
433 final PsiExpression lhs
= assignment
.getLExpression();
434 final PsiExpression rhs
= assignment
.getRExpression();
435 removeParentheses(lhs
, ignoreClarifyingParentheses
);
437 removeParentheses(rhs
, ignoreClarifyingParentheses
);
441 private static void removeParensFromNewExpression(
442 @NotNull PsiNewExpression newExpression
,
443 boolean ignoreClarifyingParentheses
)
444 throws IncorrectOperationException
{
445 final PsiExpression
[] dimensions
= newExpression
.getArrayDimensions();
446 for (PsiExpression dimension
: dimensions
) {
447 removeParentheses(dimension
, ignoreClarifyingParentheses
);
449 final PsiExpression qualifier
= newExpression
.getQualifier();
450 if(qualifier
!= null){
451 removeParentheses(qualifier
, ignoreClarifyingParentheses
);
453 final PsiExpression arrayInitializer
=
454 newExpression
.getArrayInitializer();
455 if(arrayInitializer
!= null){
456 removeParentheses(arrayInitializer
, ignoreClarifyingParentheses
);
458 final PsiExpressionList argumentList
= newExpression
.getArgumentList();
459 if(argumentList
!= null){
460 final PsiExpression
[] arguments
= argumentList
.getExpressions();
461 for (PsiExpression argument
: arguments
) {
462 removeParentheses(argument
, ignoreClarifyingParentheses
);
467 private static void removeParensFromMethodCallExpression(
468 @NotNull PsiMethodCallExpression methodCallExpression
,
469 boolean ignoreClarifyingParentheses
)
470 throws IncorrectOperationException
{
471 final PsiReferenceExpression target
=
472 methodCallExpression
.getMethodExpression();
473 final PsiExpressionList argumentList
=
474 methodCallExpression
.getArgumentList();
475 final PsiExpression
[] arguments
= argumentList
.getExpressions();
476 removeParentheses(target
, ignoreClarifyingParentheses
);
477 for (final PsiExpression argument
: arguments
) {
478 removeParentheses(argument
, ignoreClarifyingParentheses
);
482 public static boolean areParenthesesNeeded(
483 PsiParenthesizedExpression expression
,
484 boolean ignoreClarifyingParentheses
) {
485 final PsiElement parent
= expression
.getParent();
486 final PsiElement child
= expression
.getExpression();
487 if (parent
instanceof PsiBinaryExpression
&&
488 child
instanceof PsiBinaryExpression
) {
489 final PsiBinaryExpression parentBinaryExpression
=
490 (PsiBinaryExpression
)parent
;
491 final PsiBinaryExpression childBinaryExpression
=
492 (PsiBinaryExpression
)child
;
493 final IElementType childOperator
=
494 childBinaryExpression
.getOperationTokenType();
495 final IElementType parentOperator
=
496 parentBinaryExpression
.getOperationTokenType();
497 if (ignoreClarifyingParentheses
&&
498 !childOperator
.equals(parentOperator
)) {
501 final PsiType parentType
=
502 parentBinaryExpression
.getType();
503 if (parentType
== null) {
506 final PsiType childType
= childBinaryExpression
.getType();
507 if (!parentType
.equals(childType
)) {
510 if (parentBinaryExpression
.getROperand() == expression
) {
511 if (!isCommutativeBinaryOperator(