IDEADEV-40452
[fedora-idea.git] / plugins / InspectionGadgets / src / com / siyeh / ig / psiutils / ParenthesesUtils.java
blobbbfb0a75a10fec01f7c82535812b6f8121a10c44
1 /*
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;
26 import java.util.Map;
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);
55 static {
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);
77 @Nullable
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();
85 return expression;
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;
112 } else{
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;
148 return -1;
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();
259 if (body == null) {
260 parenthesizedExpression.delete();
261 return;
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);
269 return;
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);
310 return;
313 if (ignoreClarifyingParentheses) {
314 if (parentOperator.equals(bodyOperator)) {
315 removeParentheses(body, ignoreClarifyingParentheses);
317 } else {
318 final PsiExpression newExpression = (PsiExpression)
319 parenthesizedExpression.replace(body);
320 removeParentheses(newExpression,
321 ignoreClarifyingParentheses);
323 } else{
324 final PsiExpression newExpression =
325 (PsiExpression) parenthesizedExpression.replace(body);
326 removeParentheses(newExpression, ignoreClarifyingParentheses);
328 } else {
329 if (ignoreClarifyingParentheses &&
330 parent instanceof PsiBinaryExpression &&
331 (body instanceof PsiBinaryExpression ||
332 body instanceof PsiInstanceOfExpression)) {
333 removeParentheses(body, ignoreClarifyingParentheses);
334 } else {
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();
375 if (rhs != null) {
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);
440 if (rhs != null) {
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)) {
510 return true;
512 final PsiType parentType = parentBinaryExpression.getType();
513 if (parentType == null) {
514 return true;
516 final PsiType childType = childBinaryExpression.getType();
517 if (!parentType.equals(childType)) {
518 return true;
520 if (PsiTreeUtil.isAncestor(parentBinaryExpression.getROperand(),
521 expression, false)) {
522 if (!isCommutativeBinaryOperator(parentOperator)) {
523 return true;
526 return false;
527 } else if (expression instanceof PsiConditionalExpression) {
528 if (PsiTreeUtil.isAncestor(parentBinaryExpression.getROperand(),
529 expression, false)) {
530 return true;
533 } else if (parentExpression instanceof PsiPrefixExpression) {
534 if (expression instanceof PsiBinaryExpression) {
535 return true;
538 return false;