IDEADEV-32886 (quickfix of "Unnecessary Parentheses" inspection removes too many...
[fedora-idea.git] / plugins / InspectionGadgets / src / com / siyeh / ig / psiutils / ParenthesesUtils.java
blob7ab4092f1addaaf70fdf33f3b14bca89e49e2d61
1 /*
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;
26 import java.util.Map;
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);
55 static {
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);
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 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();
256 if (body == null) {
257 parenthesizedExpression.delete();
258 return;
260 final PsiElement parent = parenthesizedExpression.getParent();
261 if(!(parent instanceof PsiExpression)){
262 final PsiExpression newExpression =
263 (PsiExpression) parenthesizedExpression.replace(body);
264 removeParentheses(newExpression, ignoreClarifyingParentheses);
265 return;
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);
306 return;
309 if (ignoreClarifyingParentheses) {
310 if (parentOperator.equals(bodyOperator)) {
311 removeParentheses(body, ignoreClarifyingParentheses);
313 } else {
314 final PsiExpression newExpression = (PsiExpression)
315 parenthesizedExpression.replace(body);
316 removeParentheses(newExpression,
317 ignoreClarifyingParentheses);
319 } else{
320 final PsiExpression newExpression =
321 (PsiExpression) parenthesizedExpression.replace(body);
322 removeParentheses(newExpression, ignoreClarifyingParentheses);
324 } else {
325 if (ignoreClarifyingParentheses &&
326 parent instanceof PsiBinaryExpression &&
327 (body instanceof PsiBinaryExpression ||
328 body instanceof PsiInstanceOfExpression)) {
329 removeParentheses(body, ignoreClarifyingParentheses);
330 } else {
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();
371 if (rhs != null) {
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);
436 if (rhs != null) {
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)) {
499 return true;
501 final PsiType parentType =
502 parentBinaryExpression.getType();
503 if (parentType == null) {
504 return true;
506 final PsiType childType = childBinaryExpression.getType();
507 if (!parentType.equals(childType)) {
508 return true;
510 if (parentBinaryExpression.getROperand() == expression) {
511 if (!isCommutativeBinaryOperator(
512 childOperator)) {
513 return true;
516 return false;
518 return false;