use hashmap implementation from java.util
[idea/community.git] / java / openapi / src / com / intellij / psi / util / RedundantCastUtil.java
1 /*
2  * Copyright 2000-2011 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.psi.util;
17
18 import com.intellij.codeInsight.AnnotationUtil;
19 import com.intellij.openapi.diagnostic.Logger;
20 import com.intellij.openapi.util.Comparing;
21 import com.intellij.openapi.util.Ref;
22 import com.intellij.psi.*;
23 import com.intellij.psi.codeStyle.CodeStyleManager;
24 import com.intellij.psi.tree.IElementType;
25 import com.intellij.util.ArrayUtil;
26 import com.intellij.util.IncorrectOperationException;
27 import org.jetbrains.annotations.NotNull;
28 import org.jetbrains.annotations.Nullable;
29
30 import java.util.*;
31
32 /**
33  * @author max
34  * Date: Mar 24, 2002
35  */
36 public class RedundantCastUtil {
37   private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.redundantCast.RedundantCastUtil");
38
39   private RedundantCastUtil() { }
40
41   @NotNull
42   public static List<PsiTypeCastExpression> getRedundantCastsInside(PsiElement where) {
43     MyCollectingVisitor visitor = new MyCollectingVisitor();
44     if (where instanceof PsiEnumConstant) {
45       where.accept(visitor);
46     } else {
47       where.acceptChildren(visitor);
48     }
49     return new ArrayList<PsiTypeCastExpression>(visitor.myFoundCasts);
50   }
51
52   public static boolean isCastRedundant (PsiTypeCastExpression typeCast) {
53     PsiElement parent = typeCast.getParent();
54     while(parent instanceof PsiParenthesizedExpression) parent = parent.getParent();
55     if (parent instanceof PsiExpressionList) parent = parent.getParent();
56     if (parent instanceof PsiReferenceExpression) parent = parent.getParent();
57     MyIsRedundantVisitor visitor = new MyIsRedundantVisitor(false);
58     parent.accept(visitor);
59     return visitor.isRedundant;
60   }
61
62   @Nullable
63   private static PsiExpression deparenthesizeExpression(PsiExpression arg) {
64     while (arg instanceof PsiParenthesizedExpression) arg = ((PsiParenthesizedExpression) arg).getExpression();
65     return arg;
66   }
67
68   private static class MyCollectingVisitor extends MyIsRedundantVisitor {
69     private final Set<PsiTypeCastExpression> myFoundCasts = new HashSet<PsiTypeCastExpression>();
70
71     private MyCollectingVisitor() {
72       super(true);
73     }
74
75     @Override public void visitReferenceExpression(PsiReferenceExpression expression) {
76       expression.acceptChildren(this);
77     }
78
79     @Override public void visitClass(PsiClass aClass) {
80       // avoid multiple visit
81     }
82
83     @Override public void visitMethod(PsiMethod method) {
84       // avoid multiple visit
85     }
86
87     @Override public void visitField(PsiField field) {
88       // avoid multiple visit
89     }
90
91     @Override
92     protected void addToResults(@NotNull PsiTypeCastExpression typeCast){
93       if (!isTypeCastSemantical(typeCast)) {
94         myFoundCasts.add(typeCast);
95       }
96     }
97   }
98
99   private static class MyIsRedundantVisitor extends JavaRecursiveElementVisitor {
100     private boolean isRedundant = false;
101     private final boolean myRecursive;
102
103     private MyIsRedundantVisitor(final boolean recursive) {
104       myRecursive = recursive;
105     }
106
107     @Override
108     public void visitElement(final PsiElement element) {
109       if (myRecursive) {
110         super.visitElement(element);
111       }
112     }
113
114     protected void addToResults(@NotNull PsiTypeCastExpression typeCast){
115       if (!isTypeCastSemantical(typeCast)) {
116         isRedundant = true;
117       }
118     }
119
120     @Override public void visitAssignmentExpression(PsiAssignmentExpression expression) {
121       processPossibleTypeCast(expression.getRExpression(), expression.getLExpression().getType());
122       super.visitAssignmentExpression(expression);
123     }
124
125     @Override public void visitVariable(PsiVariable variable) {
126       processPossibleTypeCast(variable.getInitializer(), variable.getType());
127       super.visitVariable(variable);
128     }
129
130     @Override public void visitReturnStatement(PsiReturnStatement statement) {
131       final PsiMethod method = PsiTreeUtil.getParentOfType(statement, PsiMethod.class);
132       if (method != null) {
133         final PsiType returnType = method.getReturnType();
134         final PsiExpression returnValue = statement.getReturnValue();
135         if (returnValue != null) {
136           processPossibleTypeCast(returnValue, returnType);
137         }
138       }
139       super.visitReturnStatement(statement);
140     }
141
142     @Override
143     public void visitPolyadicExpression(PsiPolyadicExpression expression) {
144       IElementType tokenType = expression.getOperationTokenType();
145       PsiExpression[] operands = expression.getOperands();
146       if (operands.length >= 2) {
147         PsiType lType = operands[0].getType();
148         processBinaryExpressionOperand(deparenthesizeExpression(operands[0]), operands[1].getType(), tokenType);
149         for (int i = 1; i < operands.length; i++) {
150           PsiExpression operand = deparenthesizeExpression(operands[i]);
151           if (operand == null) continue;
152           processBinaryExpressionOperand(operand, lType, tokenType);
153           lType = TypeConversionUtil.calcTypeForBinaryExpression(lType, operand.getType(), tokenType, true);
154         }
155       }
156       super.visitPolyadicExpression(expression);
157     }
158
159     private void processBinaryExpressionOperand(final PsiExpression operand,
160                                                 final PsiType otherType,
161                                                 final IElementType binaryToken) {
162       if (operand instanceof PsiTypeCastExpression) {
163         PsiTypeCastExpression typeCast = (PsiTypeCastExpression)operand;
164         PsiExpression toCast = typeCast.getOperand();
165         if (toCast != null && TypeConversionUtil.isBinaryOperatorApplicable(binaryToken, toCast.getType(), otherType, false)) {
166           addToResults(typeCast);
167         }
168       }
169     }
170
171     private void processPossibleTypeCast(PsiExpression rExpr, @Nullable PsiType lType) {
172       rExpr = deparenthesizeExpression(rExpr);
173       if (rExpr instanceof PsiTypeCastExpression) {
174         PsiExpression castOperand = ((PsiTypeCastExpression)rExpr).getOperand();
175         if (castOperand != null) {
176           PsiType operandType = castOperand.getType();
177           if (operandType != null) {
178             if (lType != null && TypeConversionUtil.isAssignable(lType, operandType, false)) {
179               addToResults((PsiTypeCastExpression)rExpr);
180             }
181           }
182         }
183       }
184     }
185
186     @Override public void visitMethodCallExpression(PsiMethodCallExpression expression) {
187       processCall(expression);
188
189       checkForVirtual(expression);
190       super.visitMethodCallExpression(expression);
191     }
192
193     private void checkForVirtual(PsiMethodCallExpression methodCall) {
194       PsiReferenceExpression methodExpr = methodCall.getMethodExpression();
195       PsiExpression qualifier = methodExpr.getQualifierExpression();
196       if (!(qualifier instanceof PsiParenthesizedExpression)) return;
197       PsiExpression operand = ((PsiParenthesizedExpression)qualifier).getExpression();
198       if (!(operand instanceof PsiTypeCastExpression)) return;
199       PsiTypeCastExpression typeCast = (PsiTypeCastExpression)operand;
200       PsiExpression castOperand = typeCast.getOperand();
201       if (castOperand == null) return;
202
203       PsiType type = castOperand.getType();
204       if (type == null) return;
205       if (type instanceof PsiPrimitiveType) return;
206
207       final JavaResolveResult resolveResult = methodExpr.advancedResolve(false);
208       PsiMethod targetMethod = (PsiMethod)resolveResult.getElement();
209       if (targetMethod == null) return;
210       if (targetMethod.hasModifierProperty(PsiModifier.STATIC)) return;
211
212       try {
213         PsiManager manager = methodExpr.getManager();
214         PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
215
216         PsiMethodCallExpression newCall = (PsiMethodCallExpression)factory.createExpressionFromText(methodCall.getText(), methodCall);
217         PsiExpression newQualifier = newCall.getMethodExpression().getQualifierExpression();
218         PsiExpression newOperand = ((PsiTypeCastExpression)((PsiParenthesizedExpression)newQualifier).getExpression()).getOperand();
219         newQualifier.replace(newOperand);
220
221         final JavaResolveResult newResult = newCall.getMethodExpression().advancedResolve(false);
222         if (!newResult.isValidResult()) return;
223         final PsiMethod newTargetMethod = (PsiMethod)newResult.getElement();
224         final PsiType newReturnType = newResult.getSubstitutor().substitute(newTargetMethod.getReturnType());
225         final PsiType oldReturnType = resolveResult.getSubstitutor().substitute(targetMethod.getReturnType());
226         if (Comparing.equal(newReturnType, oldReturnType)) {
227           if (newTargetMethod.equals(targetMethod) ||
228               (newTargetMethod.getSignature(newResult.getSubstitutor()).equals(targetMethod.getSignature(resolveResult.getSubstitutor())) &&
229                !(newTargetMethod.isDeprecated() && !targetMethod.isDeprecated()) &&  // see SCR11555, SCR14559
230                areThrownExceptionsCompatible(targetMethod, newTargetMethod))) {
231             addToResults(typeCast);
232           }
233         }
234       }
235       catch (IncorrectOperationException ignore) { }
236     }
237
238     private static boolean areThrownExceptionsCompatible(final PsiMethod targetMethod, final PsiMethod newTargetMethod) {
239       final PsiClassType[] oldThrowsTypes = targetMethod.getThrowsList().getReferencedTypes();
240       final PsiClassType[] newThrowsTypes = newTargetMethod.getThrowsList().getReferencedTypes();
241       for (final PsiClassType throwsType : newThrowsTypes) {
242         if (!isExceptionThrown(throwsType, oldThrowsTypes)) return false;
243       }
244       return true;
245     }
246
247     private static boolean isExceptionThrown(PsiClassType exceptionType, PsiClassType[] thrownTypes) {
248       for (final PsiClassType type : thrownTypes) {
249         if (type.equals(exceptionType)) return true;
250       }
251       return false;
252     }
253
254     @Override public void visitNewExpression(PsiNewExpression expression) {
255       processCall(expression);
256       super.visitNewExpression(expression);
257     }
258
259     @Override
260     public void visitEnumConstant(PsiEnumConstant enumConstant) {
261       processCall(enumConstant);
262       super.visitEnumConstant(enumConstant);
263     }
264
265     @Override public void visitReferenceExpression(PsiReferenceExpression expression) {
266       //expression.acceptChildren(this);
267     }
268
269     private void processCall(PsiCall expression){
270       PsiExpressionList argumentList = expression.getArgumentList();
271       if (argumentList == null) return;
272       PsiExpression[] args = argumentList.getExpressions();
273       PsiMethod oldMethod = expression.resolveMethod();
274       if (oldMethod == null) return;
275       PsiParameter[] parameters = oldMethod.getParameterList().getParameters();
276
277       try {
278         for (int i = 0; i < args.length; i++) {
279           final PsiExpression arg = deparenthesizeExpression(args[i]);
280           if (arg instanceof PsiTypeCastExpression) {
281             PsiTypeCastExpression cast = (PsiTypeCastExpression)arg;
282             if (i == args.length - 1 && args.length == parameters.length && parameters[i].isVarArgs()) {
283               //do not mark cast to resolve ambiguity for calling varargs method with inexact argument
284               continue;
285             }
286             PsiCall newCall = (PsiCall) expression.copy();
287             final PsiExpressionList argList = newCall.getArgumentList();
288             LOG.assertTrue(argList != null);
289             PsiExpression[] newArgs = argList.getExpressions();
290             PsiTypeCastExpression castExpression = (PsiTypeCastExpression) deparenthesizeExpression(newArgs[i]);
291             PsiExpression castOperand = castExpression.getOperand();
292             if (castOperand == null) return;
293             castExpression.replace(castOperand);
294             if (newCall instanceof PsiEnumConstant) {
295               // do this manually, because PsiEnumConstantImpl.resolveMethodGenerics() will assert (no containing class for the copy)
296               final PsiEnumConstant enumConstant = (PsiEnumConstant)expression;
297               PsiClass containingClass = enumConstant.getContainingClass();
298               final JavaPsiFacade facade = JavaPsiFacade.getInstance(enumConstant.getProject());
299               final PsiClassType type = facade.getElementFactory().createType(containingClass);
300               final JavaResolveResult newResult = facade.getResolveHelper().resolveConstructor(type, newCall.getArgumentList(), enumConstant);
301               if (oldMethod.equals(newResult.getElement()) && newResult.isValidResult()) {
302                 addToResults(cast);
303               }
304             } else {
305               final JavaResolveResult newResult = newCall.resolveMethodGenerics();
306               if (oldMethod.equals(newResult.getElement()) && newResult.isValidResult() &&
307                 Comparing.equal(((PsiCallExpression)newCall).getType(), ((PsiCallExpression)expression).getType())) {
308                 addToResults(cast);
309               }
310             }
311           }
312         }
313       }
314       catch (IncorrectOperationException e) {
315         return;
316       }
317
318       for (PsiExpression arg : args) {
319         if (arg instanceof PsiTypeCastExpression) {
320           PsiExpression castOperand = ((PsiTypeCastExpression)arg).getOperand();
321           if (castOperand != null) {
322             castOperand.accept(this);
323           }
324         }
325         else {
326           arg.accept(this);
327         }
328       }
329     }
330
331     @Override public void visitTypeCastExpression(PsiTypeCastExpression typeCast) {
332       PsiExpression operand = typeCast.getOperand();
333       if (operand == null) return;
334
335       PsiElement expr = deparenthesizeExpression(operand);
336
337       if (expr instanceof PsiTypeCastExpression) {
338         PsiTypeElement typeElement = ((PsiTypeCastExpression)expr).getCastType();
339         if (typeElement == null) return;
340         PsiType castType = typeElement.getType();
341         final PsiExpression innerOperand = ((PsiTypeCastExpression)expr).getOperand();
342         final PsiType operandType = innerOperand != null ? innerOperand.getType() : null;
343         final PsiType topCastType = typeCast.getType();
344         if (!(castType instanceof PsiPrimitiveType)) {
345           if (operandType != null && topCastType != null && TypeConversionUtil.areTypesConvertible(operandType, topCastType)) {
346             addToResults((PsiTypeCastExpression)expr);
347           }
348         } else if (PsiPrimitiveType.getUnboxedType(operandType) == topCastType) {
349           addToResults((PsiTypeCastExpression)expr);
350         }
351       }
352       else {
353         PsiElement parent = typeCast.getParent();
354         if (parent instanceof PsiConditionalExpression) {
355           //branches need to be of the same type
356           if (!Comparing.equal(operand.getType(), ((PsiConditionalExpression)parent).getType())) {
357             if (!PsiUtil.isLanguageLevel5OrHigher(typeCast)) {
358               return;
359             }
360             if (!checkResolveAfterRemoveCast(parent)) return;
361           }
362         } else if (parent instanceof PsiSynchronizedStatement && (expr instanceof PsiExpression && ((PsiExpression)expr).getType() instanceof PsiPrimitiveType)) {
363           return;
364         }
365         processAlreadyHasTypeCast(typeCast);
366       }
367       super.visitTypeCastExpression(typeCast);
368     }
369
370     private static boolean checkResolveAfterRemoveCast(PsiElement parent) {
371       PsiElement grandPa = parent.getParent();
372       if (grandPa instanceof PsiExpressionList) {
373         PsiExpression[] expressions = ((PsiExpressionList)grandPa).getExpressions();
374         int idx = ArrayUtil.find(expressions, parent);
375         PsiElement grandGrandPa = grandPa.getParent();
376         if (grandGrandPa instanceof PsiCall) {
377           PsiElement resolve = ((PsiCall)grandGrandPa).resolveMethod();
378           if (resolve instanceof PsiMethod) {
379             PsiCall expression = (PsiCall)grandGrandPa.copy();
380             PsiExpressionList argumentList = expression.getArgumentList();
381             LOG.assertTrue(argumentList != null);
382             PsiExpression toReplace = argumentList.getExpressions()[idx];
383             if (toReplace instanceof PsiConditionalExpression) {
384               PsiExpression thenExpression = ((PsiConditionalExpression)toReplace).getThenExpression();
385               PsiExpression elseExpression = ((PsiConditionalExpression)toReplace).getElseExpression();
386               if (thenExpression instanceof PsiTypeCastExpression) {
387                 final PsiExpression thenOperand = ((PsiTypeCastExpression)thenExpression).getOperand();
388                 if (thenOperand != null) {
389                   thenExpression.replace(thenOperand);
390                 }
391               } else if (elseExpression instanceof PsiTypeCastExpression) {
392                 final PsiExpression elseOperand = ((PsiTypeCastExpression)elseExpression).getOperand();
393                 if (elseOperand != null) {
394                   elseExpression.replace(elseOperand);
395                 }
396               }
397             }
398             if (expression.resolveMethod() != resolve) {
399               return false;
400             }
401           }
402         }
403       }
404       return true;
405     }
406
407     private void processAlreadyHasTypeCast(PsiTypeCastExpression typeCast){
408       PsiElement parent = typeCast.getParent();
409       while(parent instanceof PsiParenthesizedExpression) parent = parent.getParent();
410       if (parent instanceof PsiExpressionList) return; // do not replace in arg lists - should be handled by parent
411       if (parent instanceof PsiReturnStatement) return;
412       if (parent instanceof PsiTypeCastExpression) return;
413
414       if (isTypeCastSemantical(typeCast)) return;
415
416       PsiTypeElement typeElement = typeCast.getCastType();
417       if (typeElement == null) return;
418       PsiType castTo = typeElement.getType();
419       PsiType opType = typeCast.getOperand().getType();
420       if (opType == null) return;
421       if (parent instanceof PsiReferenceExpression) {
422         if (castTo instanceof PsiClassType && opType instanceof PsiPrimitiveType) return; //explicit boxing
423         //Check accessibility
424         if (opType instanceof PsiClassType) {
425           final PsiReferenceExpression refExpression = (PsiReferenceExpression)parent;
426           PsiElement element = refExpression.resolve();
427           if (!(element instanceof PsiMember)) return;
428           PsiClass accessClass = ((PsiClassType)opType).resolve();
429           if (accessClass == null) return;
430           if (!JavaPsiFacade.getInstance(parent.getProject()).getResolveHelper().isAccessible((PsiMember)element, typeCast, accessClass)) return;
431           if (!isCastRedundantInRefExpression(refExpression, typeCast.getOperand())) return;
432         }
433       }
434
435       if (someWhereAtTheLeftSideOfAssignment(parent)) {
436         if (TypeConversionUtil.isAssignable(opType, castTo, false)) {
437           addToResults(typeCast);
438         }
439       }
440       else {
441         if (TypeConversionUtil.isAssignable(castTo, opType, false)) {
442           addToResults(typeCast);
443         }
444       }
445     }
446
447     private static boolean someWhereAtTheLeftSideOfAssignment(PsiElement element) {
448       PsiAssignmentExpression assignment = PsiTreeUtil.getParentOfType(element, PsiAssignmentExpression.class, false, PsiMember.class);
449       if (assignment == null) return false;
450       PsiExpression lExpression = assignment.getLExpression();
451       return PsiTreeUtil.isAncestor(lExpression, element, false);
452     }
453   }
454
455   private static boolean isCastRedundantInRefExpression (final PsiReferenceExpression refExpression, final PsiExpression castOperand) {
456     final PsiElement resolved = refExpression.resolve();
457     final Ref<Boolean> result = new Ref<Boolean>(Boolean.FALSE);
458     CodeStyleManager.getInstance(refExpression.getProject()).performActionWithFormatterDisabled(new Runnable() {
459       @Override
460       public void run() {
461         try {
462           final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(refExpression.getProject()).getElementFactory();
463           final PsiExpression copyExpression = elementFactory.createExpressionFromText(refExpression.getText(), refExpression);
464           if (copyExpression instanceof PsiReferenceExpression) {
465             final PsiReferenceExpression copy = (PsiReferenceExpression)copyExpression;
466             final PsiExpression qualifier = copy.getQualifierExpression();
467             if (qualifier != null) {
468               qualifier.replace(castOperand);
469               result.set(Boolean.valueOf(copy.resolve() == resolved));
470             }
471           }
472         }
473         catch (IncorrectOperationException ignore) { }
474       }
475     });
476     return result.get().booleanValue();
477   }
478
479   public static boolean isTypeCastSemantical(PsiTypeCastExpression typeCast) {
480     PsiExpression operand = typeCast.getOperand();
481     if (operand == null) return false;
482
483     if (isInPolymorphicCall(typeCast)) return true;
484
485     PsiType opType = operand.getType();
486     PsiTypeElement typeElement = typeCast.getCastType();
487     if (typeElement == null) return false;
488
489     PsiType castType = typeElement.getType();
490     if (castType instanceof PsiPrimitiveType) {
491       if (opType instanceof PsiPrimitiveType) {
492         return !opType.equals(castType); // let's suppose all not equal primitive casts are necessary
493       }
494       final PsiPrimitiveType unboxedOpType = PsiPrimitiveType.getUnboxedType(opType);
495       if (unboxedOpType != null && !unboxedOpType.equals(castType) ) {
496         return true;
497       }
498     }
499     else if (castType instanceof PsiClassType && ((PsiClassType)castType).hasParameters()) {
500       if (opType instanceof PsiClassType && ((PsiClassType)opType).isRaw()) return true;
501     } else if (castType instanceof PsiClassType && ((PsiClassType)castType).isRaw()) {
502       if (opType instanceof PsiClassType && ((PsiClassType)opType).hasParameters()) return true;
503     }
504
505     PsiElement parent = typeCast.getParent();
506     while(parent instanceof PsiParenthesizedExpression) parent = parent.getParent();
507
508     if (parent instanceof PsiBinaryExpression) {
509       PsiBinaryExpression expression = (PsiBinaryExpression)parent;
510       PsiExpression firstOperand = expression.getLOperand();
511       PsiExpression otherOperand = expression.getROperand();
512       if (PsiTreeUtil.isAncestor(otherOperand, typeCast, false)) {
513         PsiExpression temp = otherOperand;
514         otherOperand = firstOperand;
515         firstOperand = temp;
516       }
517       if (firstOperand != null && otherOperand != null && wrapperCastChangeSemantics(firstOperand, otherOperand, operand)) {
518         return true;
519       }
520     }
521     return false;
522   }
523
524   private static boolean wrapperCastChangeSemantics(PsiExpression operand, PsiExpression otherOperand, PsiExpression toCast) {
525     boolean isPrimitiveComparisonWithCast = TypeConversionUtil.isPrimitiveAndNotNull(operand.getType()) ||
526                                             TypeConversionUtil.isPrimitiveAndNotNull(otherOperand.getType());
527     boolean isPrimitiveComparisonWithoutCast = TypeConversionUtil.isPrimitiveAndNotNull(toCast.getType()) ||
528                                                TypeConversionUtil.isPrimitiveAndNotNull(otherOperand.getType());
529     // wrapper casted to primitive vs wrapper comparison
530     return isPrimitiveComparisonWithCast != isPrimitiveComparisonWithoutCast;
531   }
532
533   // see http://download.java.net/jdk7/docs/api/java/lang/invoke/MethodHandle.html#sigpoly
534   public static boolean isInPolymorphicCall(final PsiTypeCastExpression typeCast) {
535     if (!PsiUtil.isLanguageLevel7OrHigher(typeCast)) return false;
536
537     // return type
538     final PsiExpression operand = typeCast.getOperand();
539     if (operand instanceof PsiMethodCallExpression) {
540       if (isPolymorphicMethod((PsiMethodCallExpression)operand)) return true;
541     }
542
543     // argument type
544     final PsiElement exprList = typeCast.getParent();
545     if (exprList instanceof PsiExpressionList) {
546       final PsiElement methodCall = exprList.getParent();
547       if (methodCall instanceof PsiMethodCallExpression) {
548         if (isPolymorphicMethod((PsiMethodCallExpression)methodCall)) return true;
549       }
550     }
551
552     return false;
553   }
554
555   private static boolean isPolymorphicMethod(PsiMethodCallExpression expression) {
556     final PsiElement method = expression.getMethodExpression().resolve();
557     return method instanceof PsiMethod &&
558            AnnotationUtil.isAnnotated((PsiMethod)method, CommonClassNames.JAVA_LANG_INVOKE_MH_POLYMORPHIC, false, true);
559   }
560 }