varargs formal parameters inaccessible: extend for non-parameterized methods (IDEA...
[idea/community.git] / java / java-analysis-impl / src / com / intellij / codeInsight / daemon / impl / analysis / HighlightMethodUtil.java
1 /*
2  * Copyright 2000-2015 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.codeInsight.daemon.impl.analysis;
17
18 import com.intellij.codeInsight.ExceptionUtil;
19 import com.intellij.codeInsight.daemon.DaemonBundle;
20 import com.intellij.codeInsight.daemon.JavaErrorMessages;
21 import com.intellij.codeInsight.daemon.impl.HighlightInfo;
22 import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
23 import com.intellij.codeInsight.daemon.impl.quickfix.*;
24 import com.intellij.codeInsight.intention.IntentionAction;
25 import com.intellij.codeInsight.intention.QuickFixFactory;
26 import com.intellij.codeInspection.LocalQuickFixOnPsiElementAsIntentionAdapter;
27 import com.intellij.openapi.application.ApplicationManager;
28 import com.intellij.openapi.project.IndexNotReadyException;
29 import com.intellij.openapi.projectRoots.JavaSdkVersion;
30 import com.intellij.openapi.util.Comparing;
31 import com.intellij.openapi.util.Ref;
32 import com.intellij.openapi.util.TextRange;
33 import com.intellij.openapi.util.text.StringUtil;
34 import com.intellij.openapi.vfs.VirtualFile;
35 import com.intellij.pom.java.LanguageLevel;
36 import com.intellij.psi.*;
37 import com.intellij.psi.impl.PsiSuperMethodImplUtil;
38 import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
39 import com.intellij.psi.infos.CandidateInfo;
40 import com.intellij.psi.infos.MethodCandidateInfo;
41 import com.intellij.psi.util.*;
42 import com.intellij.refactoring.util.RefactoringChangeUtil;
43 import com.intellij.ui.ColorUtil;
44 import com.intellij.util.containers.MostlySingularMultiMap;
45 import com.intellij.util.ui.UIUtil;
46 import com.intellij.xml.util.XmlStringUtil;
47 import org.intellij.lang.annotations.Language;
48 import org.jetbrains.annotations.NonNls;
49 import org.jetbrains.annotations.NotNull;
50 import org.jetbrains.annotations.Nullable;
51
52 import java.text.MessageFormat;
53 import java.util.ArrayList;
54 import java.util.Collection;
55 import java.util.List;
56
57 /**
58  * Highlight method problems
59  *
60  * @author cdr
61  * Date: Aug 14, 2002
62  */
63 public class HighlightMethodUtil {
64   private static final QuickFixFactory QUICK_FIX_FACTORY = QuickFixFactory.getInstance();
65   private static final String MISMATCH_COLOR = UIUtil.isUnderDarcula() ? "ff6464" : "red";
66
67   private HighlightMethodUtil() { }
68
69   static String createClashMethodMessage(PsiMethod method1, PsiMethod method2, boolean showContainingClasses) {
70     @NonNls String pattern = showContainingClasses ? "clash.methods.message.show.classes" : "clash.methods.message";
71     return JavaErrorMessages.message(pattern,
72                                      JavaHighlightUtil.formatMethod(method1),
73                                      JavaHighlightUtil.formatMethod(method2),
74                                      HighlightUtil.formatClass(method1.getContainingClass()),
75                                      HighlightUtil.formatClass(method2.getContainingClass()));
76   }
77
78   static HighlightInfo checkMethodWeakerPrivileges(@NotNull MethodSignatureBackedByPsiMethod methodSignature,
79                                                    @NotNull List<HierarchicalMethodSignature> superMethodSignatures,
80                                                    boolean includeRealPositionInfo,
81                                                    @NotNull PsiFile containingFile) {
82     PsiMethod method = methodSignature.getMethod();
83     PsiModifierList modifierList = method.getModifierList();
84     if (modifierList.hasModifierProperty(PsiModifier.PUBLIC)) return null;
85     int accessLevel = PsiUtil.getAccessLevel(modifierList);
86     String accessModifier = PsiUtil.getAccessModifier(accessLevel);
87     for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) {
88       PsiMethod superMethod = superMethodSignature.getMethod();
89       if (method.hasModifierProperty(PsiModifier.ABSTRACT) && !MethodSignatureUtil.isSuperMethod(superMethod, method)) continue;
90       if (!PsiUtil.isAccessible(containingFile.getProject(), superMethod, method, null)) continue;
91       if (!includeRealPositionInfo && MethodSignatureUtil.isSuperMethod(superMethod, method)) continue;
92       HighlightInfo info = isWeaker(method, modifierList, accessModifier, accessLevel, superMethod, includeRealPositionInfo);
93       if (info != null) return info;
94     }
95     return null;
96   }
97
98   private static HighlightInfo isWeaker(final PsiMethod method, final PsiModifierList modifierList, final String accessModifier, final int accessLevel,
99                                         final PsiMethod superMethod,
100                                         final boolean includeRealPositionInfo) {
101     int superAccessLevel = PsiUtil.getAccessLevel(superMethod.getModifierList());
102     if (accessLevel < superAccessLevel) {
103       String description = JavaErrorMessages.message("weaker.privileges",
104                                             createClashMethodMessage(method, superMethod, true),
105                                             accessModifier,
106                                             PsiUtil.getAccessModifier(superAccessLevel));
107       TextRange textRange;
108       if (includeRealPositionInfo) {
109         if (modifierList.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
110           textRange = method.getNameIdentifier().getTextRange();
111         }
112         else {
113           PsiElement keyword = PsiUtil.findModifierInList(modifierList, accessModifier);
114           textRange = keyword.getTextRange();
115         }
116       }
117       else {
118         textRange = TextRange.EMPTY_RANGE;
119       }
120       HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
121       QuickFixAction.registerQuickFixAction(highlightInfo,
122                                             QUICK_FIX_FACTORY.createModifierListFix(method, PsiUtil.getAccessModifier(superAccessLevel), true, false));
123       return highlightInfo;
124     }
125     return null;
126   }
127
128
129   static HighlightInfo checkMethodIncompatibleReturnType(@NotNull MethodSignatureBackedByPsiMethod methodSignature,
130                                                          @NotNull List<HierarchicalMethodSignature> superMethodSignatures,
131                                                          boolean includeRealPositionInfo) {
132     return checkMethodIncompatibleReturnType(methodSignature, superMethodSignatures, includeRealPositionInfo, null);
133   }
134
135   static HighlightInfo checkMethodIncompatibleReturnType(@NotNull MethodSignatureBackedByPsiMethod methodSignature,
136                                                          @NotNull List<HierarchicalMethodSignature> superMethodSignatures,
137                                                          boolean includeRealPositionInfo,
138                                                          @Nullable TextRange textRange) {
139     PsiMethod method = methodSignature.getMethod();
140     PsiType returnType = methodSignature.getSubstitutor().substitute(method.getReturnType());
141     PsiClass aClass = method.getContainingClass();
142     if (aClass == null) return null;
143     for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) {
144       PsiMethod superMethod = superMethodSignature.getMethod();
145       PsiType declaredReturnType = superMethod.getReturnType();
146       PsiType superReturnType = declaredReturnType;
147       if (superMethodSignature.isRaw()) superReturnType = TypeConversionUtil.erasure(declaredReturnType);
148       if (returnType == null || superReturnType == null || method == superMethod) continue;
149       PsiClass superClass = superMethod.getContainingClass();
150       if (superClass == null) continue;
151       TextRange toHighlight = textRange != null ? textRange
152                                           : includeRealPositionInfo ? method.getReturnTypeElement().getTextRange() : TextRange.EMPTY_RANGE;
153       HighlightInfo highlightInfo = checkSuperMethodSignature(superMethod, superMethodSignature, superReturnType, method, methodSignature,
154                                                               returnType, JavaErrorMessages.message("incompatible.return.type"),
155                                                               toHighlight, PsiUtil.getLanguageLevel(aClass));
156       if (highlightInfo != null) return highlightInfo;
157     }
158
159     return null;
160   }
161
162   private static HighlightInfo checkSuperMethodSignature(@NotNull PsiMethod superMethod,
163                                                          @NotNull MethodSignatureBackedByPsiMethod superMethodSignature,
164                                                          PsiType superReturnType,
165                                                          @NotNull PsiMethod method,
166                                                          @NotNull MethodSignatureBackedByPsiMethod methodSignature,
167                                                          @NotNull PsiType returnType,
168                                                          @NotNull String detailMessage,
169                                                          @NotNull TextRange range,
170                                                          @NotNull LanguageLevel languageLevel) {
171     if (superReturnType == null) return null;
172     if ("clone".equals(method.getName())) {
173       final PsiClass containingClass = method.getContainingClass();
174       final PsiClass superContainingClass = superMethod.getContainingClass();
175       if (containingClass != null && superContainingClass != null && containingClass.isInterface() && !superContainingClass.isInterface()) {
176         return null;
177       }
178     }
179
180     PsiType substitutedSuperReturnType;
181     final boolean isJdk15 = languageLevel.isAtLeast(LanguageLevel.JDK_1_5);
182     if (isJdk15 && !superMethodSignature.isRaw() && superMethodSignature.equals(methodSignature)) { //see 8.4.5
183       PsiSubstitutor unifyingSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature,
184                                                                                                   superMethodSignature);
185       substitutedSuperReturnType = unifyingSubstitutor == null
186                                    ? superReturnType
187                                    : unifyingSubstitutor.substitute(superReturnType);
188     }
189     else {
190       substitutedSuperReturnType = TypeConversionUtil.erasure(superMethodSignature.getSubstitutor().substitute(superReturnType));
191     }
192
193     if (returnType.equals(substitutedSuperReturnType)) return null;
194     if (!(returnType instanceof PsiPrimitiveType) && substitutedSuperReturnType.getDeepComponentType() instanceof PsiClassType) {
195       if (isJdk15 && TypeConversionUtil.isAssignable(substitutedSuperReturnType, returnType)) {
196         return null;
197       }
198     }
199
200     return createIncompatibleReturnTypeMessage(method, superMethod, substitutedSuperReturnType, returnType, detailMessage, range);
201   }
202
203   private static HighlightInfo createIncompatibleReturnTypeMessage(@NotNull PsiMethod method,
204                                                                    @NotNull PsiMethod superMethod,
205                                                                    @NotNull PsiType substitutedSuperReturnType,
206                                                                    @NotNull PsiType returnType,
207                                                                    @NotNull String detailMessage,
208                                                                    @NotNull TextRange textRange) {
209     String description = MessageFormat.format("{0}; {1}", createClashMethodMessage(method, superMethod, true), detailMessage);
210     HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(
211       description).create();
212     QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createMethodReturnFix(method, substitutedSuperReturnType, false));
213     QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createSuperMethodReturnFix(superMethod, returnType));
214
215     return errorResult;
216   }
217
218
219   static HighlightInfo checkMethodOverridesFinal(MethodSignatureBackedByPsiMethod methodSignature,
220                                                  List<HierarchicalMethodSignature> superMethodSignatures) {
221     PsiMethod method = methodSignature.getMethod();
222     for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) {
223       PsiMethod superMethod = superMethodSignature.getMethod();
224       HighlightInfo info = checkSuperMethodIsFinal(method, superMethod);
225       if (info != null) return info;
226     }
227     return null;
228   }
229
230   private static HighlightInfo checkSuperMethodIsFinal(PsiMethod method, PsiMethod superMethod) {
231     // strange things happen when super method is from Object and method from interface
232     if (superMethod.hasModifierProperty(PsiModifier.FINAL)) {
233       String description = JavaErrorMessages.message("final.method.override",
234                                                  JavaHighlightUtil.formatMethod(method),
235                                                  JavaHighlightUtil.formatMethod(superMethod),
236                                                  HighlightUtil.formatClass(superMethod.getContainingClass()));
237       TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method);
238       HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
239       QuickFixAction.registerQuickFixAction(errorResult,
240                                             QUICK_FIX_FACTORY.createModifierListFix(superMethod, PsiModifier.FINAL, false, true));
241       return errorResult;
242     }
243     return null;
244   }
245
246   static HighlightInfo checkMethodIncompatibleThrows(MethodSignatureBackedByPsiMethod methodSignature,
247                                                             List<HierarchicalMethodSignature> superMethodSignatures,
248                                                             boolean includeRealPositionInfo, PsiClass analyzedClass) {
249     PsiMethod method = methodSignature.getMethod();
250     PsiClass aClass = method.getContainingClass();
251     if (aClass == null) return null;
252     PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(aClass, analyzedClass, PsiSubstitutor.EMPTY);
253     PsiClassType[] exceptions = method.getThrowsList().getReferencedTypes();
254     PsiJavaCodeReferenceElement[] referenceElements;
255     List<PsiElement> exceptionContexts;
256     if (includeRealPositionInfo) {
257       exceptionContexts = new ArrayList<PsiElement>();
258       referenceElements = method.getThrowsList().getReferenceElements();
259     }
260     else {
261       exceptionContexts = null;
262       referenceElements = null;
263     }
264     List<PsiClassType> checkedExceptions = new ArrayList<PsiClassType>();
265     for (int i = 0; i < exceptions.length; i++) {
266       PsiClassType exception = exceptions[i];
267       if (!ExceptionUtil.isUncheckedException(exception)) {
268         checkedExceptions.add(exception);
269         if (includeRealPositionInfo && i < referenceElements.length) {
270           PsiJavaCodeReferenceElement exceptionRef = referenceElements[i];
271           exceptionContexts.add(exceptionRef);
272         }
273       }
274     }
275     for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) {
276       PsiMethod superMethod = superMethodSignature.getMethod();
277       int index = getExtraExceptionNum(methodSignature, superMethodSignature, checkedExceptions, superSubstitutor);
278       if (index != -1) {
279         if (aClass.isInterface()) {
280           final PsiClass superContainingClass = superMethod.getContainingClass();
281           if (superContainingClass != null && !superContainingClass.isInterface()) continue;
282           if (superContainingClass != null && !aClass.isInheritor(superContainingClass, true)) continue;
283         }
284         PsiClassType exception = checkedExceptions.get(index);
285         String description = JavaErrorMessages.message("overridden.method.does.not.throw",
286                                                    createClashMethodMessage(method, superMethod, true),
287                                                    JavaHighlightUtil.formatType(exception));
288         TextRange textRange;
289         if (includeRealPositionInfo) {
290           PsiElement exceptionContext = exceptionContexts.get(index);
291           textRange = exceptionContext.getTextRange();
292         }
293         else {
294           textRange = TextRange.EMPTY_RANGE;
295         }
296         HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
297         QuickFixAction.registerQuickFixAction(errorResult, new LocalQuickFixOnPsiElementAsIntentionAdapter(QUICK_FIX_FACTORY.createMethodThrowsFix(method, exception, false, false)));
298         QuickFixAction.registerQuickFixAction(errorResult, new LocalQuickFixOnPsiElementAsIntentionAdapter(QUICK_FIX_FACTORY.createMethodThrowsFix(superMethod, exception, true, true)));
299         return errorResult;
300       }
301     }
302     return null;
303   }
304
305   // return number of exception  which was not declared in super method or -1
306   private static int getExtraExceptionNum(final MethodSignature methodSignature,
307                                           final MethodSignatureBackedByPsiMethod superSignature,
308                                           List<PsiClassType> checkedExceptions, PsiSubstitutor substitutorForDerivedClass) {
309     PsiMethod superMethod = superSignature.getMethod();
310     PsiSubstitutor substitutorForMethod = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, superSignature);
311     for (int i = 0; i < checkedExceptions.size(); i++) {
312       final PsiClassType checkedEx = checkedExceptions.get(i);
313       final PsiType substituted = substitutorForMethod != null ? substitutorForMethod.substitute(checkedEx) : TypeConversionUtil.erasure(checkedEx);
314       PsiType exception = substitutorForDerivedClass.substitute(substituted);
315       if (!isMethodThrows(superMethod, substitutorForMethod, exception, substitutorForDerivedClass)) {
316         return i;
317       }
318     }
319     return -1;
320   }
321
322   private static boolean isMethodThrows(PsiMethod method, @Nullable PsiSubstitutor substitutorForMethod, PsiType exception, PsiSubstitutor substitutorForDerivedClass) {
323     PsiClassType[] thrownExceptions = method.getThrowsList().getReferencedTypes();
324     for (PsiClassType thrownException1 : thrownExceptions) {
325       PsiType thrownException = substitutorForMethod != null ? substitutorForMethod.substitute(thrownException1) : TypeConversionUtil.erasure(thrownException1);
326       thrownException = substitutorForDerivedClass.substitute(thrownException);
327       if (TypeConversionUtil.isAssignable(thrownException, exception)) return true;
328     }
329     return false;
330   }
331
332   @Nullable
333   static HighlightInfo checkMethodCall(@NotNull PsiMethodCallExpression methodCall,
334                                        @NotNull PsiResolveHelper resolveHelper,
335                                        @NotNull LanguageLevel languageLevel,
336                                        @NotNull JavaSdkVersion javaSdkVersion) {
337     PsiExpressionList list = methodCall.getArgumentList();
338     PsiReferenceExpression referenceToMethod = methodCall.getMethodExpression();
339     JavaResolveResult[] results = referenceToMethod.multiResolve(true);
340     JavaResolveResult resolveResult = results.length == 1 ? results[0] : JavaResolveResult.EMPTY;
341     PsiElement resolved = resolveResult.getElement();
342
343     boolean isDummy = isDummyConstructorCall(methodCall, resolveHelper, list, referenceToMethod);
344     if (isDummy) return null;
345     HighlightInfo highlightInfo;
346
347     final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
348     if (resolved instanceof PsiMethod && resolveResult.isValidResult()) {
349       TextRange fixRange = getFixRange(methodCall);
350       highlightInfo = HighlightUtil.checkUnhandledExceptions(methodCall, fixRange);
351       if (highlightInfo == null) {
352         final String invalidCallMessage = 
353           LambdaUtil.getInvalidQualifier4StaticInterfaceMethodMessage((PsiMethod)resolved, methodCall.getMethodExpression(), resolveResult.getCurrentFileResolveScope(), languageLevel);
354         if (invalidCallMessage != null) {
355           highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(invalidCallMessage).range(fixRange).create();
356           if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
357             QuickFixAction.registerQuickFixAction(highlightInfo, new IncreaseLanguageLevelFix(LanguageLevel.JDK_1_8));
358           }
359         } else {
360           highlightInfo = GenericsHighlightUtil.checkInferredIntersections(substitutor, fixRange);
361         }
362         
363         if (highlightInfo == null) {
364           highlightInfo = checkVarargParameterErasureToBeAccessible((MethodCandidateInfo)resolveResult, methodCall);
365         }
366       }
367     }
368     else {
369       PsiMethod resolvedMethod = null;
370       MethodCandidateInfo candidateInfo = null;
371       if (resolveResult instanceof MethodCandidateInfo) {
372         candidateInfo = (MethodCandidateInfo)resolveResult;
373         resolvedMethod = candidateInfo.getElement();
374       }
375
376       if (!resolveResult.isAccessible() || !resolveResult.isStaticsScopeCorrect()) {
377         highlightInfo = null;
378       }
379       else if (candidateInfo != null && !candidateInfo.isApplicable()) {
380         if (candidateInfo.isTypeArgumentsApplicable()) {
381           String methodName = HighlightMessageUtil.getSymbolName(resolved, substitutor);
382           PsiElement parent = resolved.getParent();
383           String containerName = parent == null ? "" : HighlightMessageUtil.getSymbolName(parent, substitutor);
384           String argTypes = buildArgTypesList(list);
385           String description = JavaErrorMessages.message("wrong.method.arguments", methodName, containerName, argTypes);
386           final Ref<PsiElement> elementToHighlight = new Ref<PsiElement>(list);
387           String toolTip;
388           if (parent instanceof PsiClass && !ApplicationManager.getApplication().isUnitTestMode()) {
389             toolTip = buildOneLineMismatchDescription(list, candidateInfo, elementToHighlight);
390             if (toolTip == null) {
391               toolTip = createMismatchedArgumentsHtmlTooltip(candidateInfo, list);
392             }
393           }
394           else {
395             toolTip = description;
396           }
397           PsiElement element = elementToHighlight.get();
398           int navigationShift = element instanceof PsiExpressionList ? +1 : 0; // argument list starts with paren which there is no need to highlight
399           highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element)
400             .description(description).escapedToolTip(toolTip).navigationShift(navigationShift).create();
401           if (highlightInfo != null) {
402             registerMethodCallIntentions(highlightInfo, methodCall, list, resolveHelper);
403             registerMethodReturnFixAction(highlightInfo, candidateInfo, methodCall);
404           }
405         }
406         else {
407           PsiReferenceExpression methodExpression = methodCall.getMethodExpression();
408           PsiReferenceParameterList typeArgumentList = methodCall.getTypeArgumentList();
409           if (typeArgumentList.getTypeArguments().length == 0 && resolvedMethod.hasTypeParameters()) {
410             highlightInfo = GenericsHighlightUtil.checkInferredTypeArguments(resolvedMethod, methodCall, substitutor);
411           }
412           else {
413             highlightInfo = GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, methodExpression, substitutor, javaSdkVersion);
414           }
415         }
416       }
417       else {
418         String description = JavaErrorMessages.message("method.call.expected");
419         highlightInfo =
420           HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(methodCall).descriptionAndTooltip(description).create();
421         if (resolved instanceof PsiClass) {
422           QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createInsertNewFix(methodCall, (PsiClass)resolved));
423         }
424         else {
425           TextRange range = getFixRange(methodCall);
426           QuickFixAction.registerQuickFixAction(highlightInfo, range, QUICK_FIX_FACTORY.createCreateMethodFromUsageFix(methodCall));
427           QuickFixAction.registerQuickFixAction(highlightInfo, range, QUICK_FIX_FACTORY.createCreateAbstractMethodFromUsageFix(methodCall));
428           QuickFixAction.registerQuickFixAction(highlightInfo, range, QUICK_FIX_FACTORY.createCreatePropertyFromUsageFix(methodCall));
429         }
430       }
431     }
432     if (highlightInfo == null) {
433       highlightInfo = GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, referenceToMethod, substitutor,
434                                                                                      javaSdkVersion);
435     }
436     return highlightInfo;
437   }
438
439   private static void registerMethodReturnFixAction(HighlightInfo highlightInfo,
440                                                     MethodCandidateInfo candidate,
441                                                     PsiCall methodCall) {
442     if (methodCall.getParent() instanceof PsiReturnStatement) {
443       final PsiMethod containerMethod = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class, true, PsiLambdaExpression.class);
444       if (containerMethod != null) {
445         final PsiMethod method = candidate.getElement();
446         final PsiExpression methodCallCopy =
447           JavaPsiFacade.getElementFactory(method.getProject()).createExpressionFromText(methodCall.getText(), methodCall);
448         PsiType methodCallTypeByArgs = methodCallCopy.getType();
449         //ensure type params are not included
450         methodCallTypeByArgs = JavaPsiFacade.getElementFactory(method.getProject())
451           .createRawSubstitutor(method).substitute(methodCallTypeByArgs);
452         QuickFixAction.registerQuickFixAction(highlightInfo, 
453                                               getFixRange(methodCall),
454                                               QUICK_FIX_FACTORY.createMethodReturnFix(containerMethod, methodCallTypeByArgs, true));
455       }
456     }
457   }
458
459   private static String buildOneLineMismatchDescription(@NotNull PsiExpressionList list,
460                                                         @NotNull MethodCandidateInfo candidateInfo,
461                                                         @NotNull Ref<PsiElement> elementToHighlight) {
462     final PsiExpression[] expressions = list.getExpressions();
463     final PsiMethod resolvedMethod = candidateInfo.getElement();
464     final PsiSubstitutor substitutor = candidateInfo.getSubstitutor();
465     final PsiParameter[] parameters = resolvedMethod.getParameterList().getParameters();
466     if (expressions.length == parameters.length && parameters.length > 1) {
467       int idx = -1;
468       for (int i = 0; i < expressions.length; i++) {
469         PsiExpression expression = expressions[i];
470         if (!TypeConversionUtil.areTypesAssignmentCompatible(substitutor.substitute(parameters[i].getType()), expression)) {
471           if (idx != -1) {
472             idx = -1;
473             break;
474           }
475           else {
476             idx = i;
477           }
478         }
479       }
480
481       if (idx > -1) {
482         final PsiExpression wrongArg = expressions[idx];
483         final PsiType argType = wrongArg.getType();
484         if (argType != null) {
485           elementToHighlight.set(wrongArg);
486           final String message = JavaErrorMessages
487             .message("incompatible.call.types", idx + 1, substitutor.substitute(parameters[idx].getType()).getCanonicalText(), argType.getCanonicalText());
488
489           return XmlStringUtil.wrapInHtml("<body>" + XmlStringUtil.escapeString(message) +
490                                           " <a href=\"#assignment/" + XmlStringUtil.escapeString(createMismatchedArgumentsHtmlTooltip(candidateInfo, list)) + "\"" +
491                                           (UIUtil.isUnderDarcula() ? " color=\"7AB4C9\" " : "") +
492                                           ">" + DaemonBundle.message("inspection.extended.description") + "</a></body>");
493         }
494       }
495     }
496     return null;
497   }
498
499   static boolean isDummyConstructorCall(PsiMethodCallExpression methodCall,
500                                         PsiResolveHelper resolveHelper,
501                                         PsiExpressionList list,
502                                         PsiReferenceExpression referenceToMethod) {
503     boolean isDummy = false;
504     boolean isThisOrSuper = referenceToMethod.getReferenceNameElement() instanceof PsiKeyword;
505     if (isThisOrSuper) {
506       // super(..) or this(..)
507       if (list.getExpressions().length == 0) { // implicit ctr call
508         CandidateInfo[] candidates = resolveHelper.getReferencedMethodCandidates(methodCall, true);
509         if (candidates.length == 1 && !candidates[0].getElement().isPhysical()) {
510           isDummy = true;// dummy constructor
511         }
512       }
513     }
514     return isDummy;
515   }
516
517   @Nullable
518   static HighlightInfo checkAmbiguousMethodCallIdentifier(@NotNull PsiReferenceExpression referenceToMethod,
519                                                 @NotNull JavaResolveResult[] resolveResults,
520                                                 @NotNull PsiExpressionList list,
521                                                 final PsiElement element,
522                                                 @NotNull JavaResolveResult resolveResult,
523                                                 @NotNull PsiMethodCallExpression methodCall,
524                                                 @NotNull PsiResolveHelper resolveHelper) {
525     MethodCandidateInfo methodCandidate1 = null;
526     MethodCandidateInfo methodCandidate2 = null;
527     for (JavaResolveResult result : resolveResults) {
528       if (!(result instanceof MethodCandidateInfo)) continue;
529       MethodCandidateInfo candidate = (MethodCandidateInfo)result;
530       if (candidate.isApplicable() && !candidate.getElement().isConstructor()) {
531         if (methodCandidate1 == null) {
532           methodCandidate1 = candidate;
533         }
534         else {
535           methodCandidate2 = candidate;
536           break;
537         }
538       }
539     }
540     MethodCandidateInfo[] candidates = toMethodCandidates(resolveResults);
541
542     HighlightInfoType highlightInfoType = HighlightInfoType.ERROR;
543     if (methodCandidate2 != null) {
544       return null;
545     }
546     String description;
547     PsiElement elementToHighlight;
548     if (element != null && !resolveResult.isAccessible()) {
549       description = HighlightUtil.buildProblemWithAccessDescription(referenceToMethod, resolveResult);
550       elementToHighlight = referenceToMethod.getReferenceNameElement();
551     }
552     else if (element != null && !resolveResult.isStaticsScopeCorrect()) {
553       final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(referenceToMethod);
554       final String staticInterfaceMethodMessage = 
555         element instanceof PsiMethod 
556         ? LambdaUtil.getInvalidQualifier4StaticInterfaceMethodMessage((PsiMethod)element, referenceToMethod, 
557                                                                       resolveResult.getCurrentFileResolveScope(), languageLevel) 
558         : null;
559       description = staticInterfaceMethodMessage != null 
560                     ? staticInterfaceMethodMessage 
561                     : HighlightUtil.buildProblemWithStaticDescription(element);
562       elementToHighlight = referenceToMethod.getReferenceNameElement();
563     }
564     else {
565       String methodName = referenceToMethod.getReferenceName() + buildArgTypesList(list);
566       description = JavaErrorMessages.message("cannot.resolve.method", methodName);
567       if (candidates.length == 0) {
568         elementToHighlight = referenceToMethod.getReferenceNameElement();
569         highlightInfoType = HighlightInfoType.WRONG_REF;
570       }
571       else {
572         return null;
573       }
574     }
575     String toolTip = XmlStringUtil.escapeString(description);
576     HighlightInfo info =
577       HighlightInfo.newHighlightInfo(highlightInfoType).range(elementToHighlight).description(description).escapedToolTip(toolTip).create();
578     registerMethodCallIntentions(info, methodCall, list, resolveHelper);
579     if (element != null && !resolveResult.isStaticsScopeCorrect()) {
580       HighlightUtil.registerStaticProblemQuickFixAction(element, info, referenceToMethod);
581     }
582
583     TextRange fixRange = getFixRange(elementToHighlight);
584     CastMethodArgumentFix.REGISTRAR.registerCastActions(candidates, methodCall, info, fixRange);
585     WrapArrayToArraysAsListFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange);
586     PermuteArgumentsFix.registerFix(info, methodCall, candidates, fixRange);
587     WrapExpressionFix.registerWrapAction(candidates, list.getExpressions(), info);
588     registerChangeParameterClassFix(methodCall, list, info);
589     return info;
590   }
591
592   @Nullable
593   static HighlightInfo checkAmbiguousMethodCallArguments(@NotNull PsiReferenceExpression referenceToMethod,
594                                                          @NotNull JavaResolveResult[] resolveResults,
595                                                          @NotNull PsiExpressionList list,
596                                                          final PsiElement element,
597                                                          @NotNull JavaResolveResult resolveResult,
598                                                          @NotNull PsiMethodCallExpression methodCall,
599                                                          @NotNull PsiResolveHelper resolveHelper, 
600                                                          @NotNull PsiElement elementToHighlight) {
601     MethodCandidateInfo methodCandidate1 = null;
602     MethodCandidateInfo methodCandidate2 = null;
603     for (JavaResolveResult result : resolveResults) {
604       if (!(result instanceof MethodCandidateInfo)) continue;
605       MethodCandidateInfo candidate = (MethodCandidateInfo)result;
606       if (candidate.isApplicable() && !candidate.getElement().isConstructor()) {
607         if (methodCandidate1 == null) {
608           methodCandidate1 = candidate;
609         }
610         else {
611           methodCandidate2 = candidate;
612           break;
613         }
614       }
615     }
616     MethodCandidateInfo[] candidates = toMethodCandidates(resolveResults);
617
618     String description;
619     String toolTip;
620     HighlightInfoType highlightInfoType = HighlightInfoType.ERROR;
621     if (methodCandidate2 != null) {
622       PsiMethod element1 = methodCandidate1.getElement();
623       String m1 = PsiFormatUtil.formatMethod(element1,
624                                              methodCandidate1.getSubstitutor(),
625                                              PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_NAME |
626                                              PsiFormatUtilBase.SHOW_PARAMETERS,
627                                              PsiFormatUtilBase.SHOW_TYPE);
628       PsiMethod element2 = methodCandidate2.getElement();
629       String m2 = PsiFormatUtil.formatMethod(element2,
630                                              methodCandidate2.getSubstitutor(),
631                                              PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_NAME |
632                                              PsiFormatUtilBase.SHOW_PARAMETERS,
633                                              PsiFormatUtilBase.SHOW_TYPE);
634       VirtualFile virtualFile1 = PsiUtilCore.getVirtualFile(element1);
635       VirtualFile virtualFile2 = PsiUtilCore.getVirtualFile(element2);
636       if (!Comparing.equal(virtualFile1, virtualFile2)) {
637         if (virtualFile1 != null) m1 += " (In " + virtualFile1.getPresentableUrl() + ")";
638         if (virtualFile2 != null) m2 += " (In " + virtualFile2.getPresentableUrl() + ")";
639       }
640       description = JavaErrorMessages.message("ambiguous.method.call", m1, m2);
641       toolTip = createAmbiguousMethodHtmlTooltip(new MethodCandidateInfo[]{methodCandidate1, methodCandidate2});
642     }
643     else {
644       if (element != null && !resolveResult.isAccessible()) {
645         return null;
646       }
647       if (element != null && !resolveResult.isStaticsScopeCorrect()) {
648         return null;
649       }
650       String methodName = referenceToMethod.getReferenceName() + buildArgTypesList(list);
651       description = JavaErrorMessages.message("cannot.resolve.method", methodName);
652       if (candidates.length == 0) {
653         return null;
654       }
655       toolTip = XmlStringUtil.escapeString(description);
656     }
657     HighlightInfo info =
658       HighlightInfo.newHighlightInfo(highlightInfoType).range(elementToHighlight).description(description).escapedToolTip(toolTip).create();
659     if (methodCandidate2 == null) {
660       registerMethodCallIntentions(info, methodCall, list, resolveHelper);
661     }
662     if (!resolveResult.isAccessible() && resolveResult.isStaticsScopeCorrect() && methodCandidate2 != null) {
663       HighlightUtil.registerAccessQuickFixAction((PsiMember)element, referenceToMethod, info, resolveResult.getCurrentFileResolveScope());
664     }
665     if (element != null && !resolveResult.isStaticsScopeCorrect()) {
666       HighlightUtil.registerStaticProblemQuickFixAction(element, info, referenceToMethod);
667     }
668
669     TextRange fixRange = getFixRange(elementToHighlight);
670     CastMethodArgumentFix.REGISTRAR.registerCastActions(candidates, methodCall, info, fixRange);
671     WrapArrayToArraysAsListFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange);
672     PermuteArgumentsFix.registerFix(info, methodCall, candidates, fixRange);
673     WrapExpressionFix.registerWrapAction(candidates, list.getExpressions(), info);
674     registerChangeParameterClassFix(methodCall, list, info);
675     return info;
676   }
677
678   @NotNull
679   private static MethodCandidateInfo[] toMethodCandidates(@NotNull JavaResolveResult[] resolveResults) {
680     List<MethodCandidateInfo> candidateList = new ArrayList<MethodCandidateInfo>(resolveResults.length);
681
682     for (JavaResolveResult result : resolveResults) {
683       if (!(result instanceof MethodCandidateInfo)) continue;
684       MethodCandidateInfo candidate = (MethodCandidateInfo)result;
685       if (candidate.isAccessible()) candidateList.add(candidate);
686     }
687     return candidateList.toArray(new MethodCandidateInfo[candidateList.size()]);
688   }
689
690   private static void registerMethodCallIntentions(@Nullable HighlightInfo highlightInfo,
691                                                    PsiMethodCallExpression methodCall,
692                                                    PsiExpressionList list,
693                                                    PsiResolveHelper resolveHelper) {
694     TextRange fixRange = getFixRange(methodCall);
695     QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.createCreateMethodFromUsageFix(methodCall));
696     QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.createCreateAbstractMethodFromUsageFix(methodCall));
697     QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.createCreateConstructorFromSuperFix(methodCall));
698     QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.createCreateConstructorFromThisFix(methodCall));
699     QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.createCreatePropertyFromUsageFix(methodCall));
700     QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.createCreateGetterSetterPropertyFromUsageFix(methodCall));
701     CandidateInfo[] methodCandidates = resolveHelper.getReferencedMethodCandidates(methodCall, false);
702     CastMethodArgumentFix.REGISTRAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange);
703     PermuteArgumentsFix.registerFix(highlightInfo, methodCall, methodCandidates, fixRange);
704     AddTypeArgumentsFix.REGISTRAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange);
705     WrapArrayToArraysAsListFix.REGISTAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange);
706     registerMethodAccessLevelIntentions(methodCandidates, methodCall, list, highlightInfo);
707     registerChangeMethodSignatureFromUsageIntentions(methodCandidates, list, highlightInfo, fixRange);
708     RemoveRedundantArgumentsFix.registerIntentions(methodCandidates, list, highlightInfo, fixRange);
709     ConvertDoubleToFloatFix.registerIntentions(methodCandidates, list, highlightInfo, fixRange);
710     WrapExpressionFix.registerWrapAction(methodCandidates, list.getExpressions(), highlightInfo);
711     registerChangeParameterClassFix(methodCall, list, highlightInfo);
712     if (methodCandidates.length == 0) {
713       QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.createStaticImportMethodFix(methodCall));
714       QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.addMethodQualifierFix(methodCall));
715     }
716     for (IntentionAction action : QUICK_FIX_FACTORY.getVariableTypeFromCallFixes(methodCall, list)) {
717       QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, action);
718     }
719     QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.createReplaceAddAllArrayToCollectionFix(methodCall));
720     QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.createSurroundWithArrayFix(methodCall, null));
721     QualifyThisArgumentFix.registerQuickFixAction(methodCandidates, methodCall, highlightInfo, fixRange);
722
723     CandidateInfo[] candidates = resolveHelper.getReferencedMethodCandidates(methodCall, true);
724     ChangeStringLiteralToCharInMethodCallFix.registerFixes(candidates, methodCall, highlightInfo);
725   }
726
727   private static void registerMethodAccessLevelIntentions(CandidateInfo[] methodCandidates,
728                                                           PsiMethodCallExpression methodCall,
729                                                           PsiExpressionList exprList,
730                                                           HighlightInfo highlightInfo) {
731     for (CandidateInfo methodCandidate : methodCandidates) {
732       PsiMethod method = (PsiMethod)methodCandidate.getElement();
733       if (!methodCandidate.isAccessible() && PsiUtil.isApplicable(method, methodCandidate.getSubstitutor(), exprList)) {
734         HighlightUtil.registerAccessQuickFixAction(method, methodCall.getMethodExpression(), highlightInfo, methodCandidate.getCurrentFileResolveScope());
735       }
736     }
737   }
738
739   @NotNull
740   private static String createAmbiguousMethodHtmlTooltip(MethodCandidateInfo[] methodCandidates) {
741     return JavaErrorMessages.message("ambiguous.method.html.tooltip",
742                                      Integer.valueOf(methodCandidates[0].getElement().getParameterList().getParametersCount() + 2),
743                                      createAmbiguousMethodHtmlTooltipMethodRow(methodCandidates[0]),
744                                      getContainingClassName(methodCandidates[0]),
745                                      createAmbiguousMethodHtmlTooltipMethodRow(methodCandidates[1]),
746                                      getContainingClassName(methodCandidates[1]));
747   }
748
749   private static String getContainingClassName(final MethodCandidateInfo methodCandidate) {
750     PsiMethod method = methodCandidate.getElement();
751     PsiClass containingClass = method.getContainingClass();
752     return containingClass == null ? method.getContainingFile().getName() : HighlightUtil.formatClass(containingClass, false);
753   }
754
755   @Language("HTML")
756   private static String createAmbiguousMethodHtmlTooltipMethodRow(final MethodCandidateInfo methodCandidate) {
757     PsiMethod method = methodCandidate.getElement();
758     PsiParameter[] parameters = method.getParameterList().getParameters();
759     PsiSubstitutor substitutor = methodCandidate.getSubstitutor();
760     @NonNls @Language("HTML") String ms = "<td><b>" + method.getName() + "</b></td>";
761
762     for (int j = 0; j < parameters.length; j++) {
763       PsiParameter parameter = parameters[j];
764       PsiType type = substitutor.substitute(parameter.getType());
765       ms += "<td><b>" + (j == 0 ? "(" : "") +
766             XmlStringUtil.escapeString(type.getPresentableText())
767             + (j == parameters.length - 1 ? ")" : ",") + "</b></td>";
768     }
769     if (parameters.length == 0) {
770       ms += "<td><b>()</b></td>";
771     }
772     return ms;
773   }
774
775   private static String createMismatchedArgumentsHtmlTooltip(MethodCandidateInfo info, PsiExpressionList list) {
776     PsiMethod method = info.getElement();
777     PsiSubstitutor substitutor = info.getSubstitutor();
778     PsiClass aClass = method.getContainingClass();
779     PsiParameter[] parameters = method.getParameterList().getParameters();
780     String methodName = method.getName();
781     return createMismatchedArgumentsHtmlTooltip(list, parameters, methodName, substitutor, aClass);
782   }
783
784   private static String createShortMismatchedArgumentsHtmlTooltip(PsiExpressionList list,
785                                                              PsiParameter[] parameters,
786                                                              String methodName,
787                                                              PsiSubstitutor substitutor,
788                                                              PsiClass aClass) {
789     PsiExpression[] expressions = list.getExpressions();
790     int cols = Math.max(parameters.length, expressions.length);
791
792     @Language("HTML")
793     @NonNls String parensizedName = methodName + (parameters.length == 0 ? "(&nbsp;)&nbsp;" : "");
794     final String errorMessage = InferenceSession.getInferenceErrorMessage(list.getParent());
795     return JavaErrorMessages.message(
796       "argument.mismatch.html.tooltip",
797       Integer.valueOf(cols - parameters.length + 1), parensizedName,
798       HighlightUtil.formatClass(aClass, false),
799       createMismatchedArgsHtmlTooltipParamsRow(parameters, substitutor, expressions),
800       createMismatchedArgsHtmlTooltipArgumentsRow(expressions, parameters, substitutor, cols),
801       errorMessage != null ? "<br/>reason: " + XmlStringUtil.escapeString(errorMessage).replaceAll("\n", "<br/>") : ""
802     );
803   }
804
805   private static String esctrim(@NotNull String s) {
806     return XmlStringUtil.escapeString(trimNicely(s));
807   }
808
809   private static String trimNicely(String s) {
810     if (s.length() <= 40) return s;
811
812     List<TextRange> wordIndices = StringUtil.getWordIndicesIn(s);
813     if (wordIndices.size() > 2) {
814       int firstWordEnd = wordIndices.get(0).getEndOffset();
815
816       // try firstWord...remainder
817       for (int i = 1; i<wordIndices.size();i++) {
818         int stringLength = firstWordEnd + s.length() - wordIndices.get(i).getStartOffset();
819         if (stringLength <= 40) {
820           return s.substring(0, firstWordEnd) + "..." + s.substring(wordIndices.get(i).getStartOffset());
821         }
822       }
823     }
824     // maybe one last word will fit?
825     if (!wordIndices.isEmpty() && s.length() - wordIndices.get(wordIndices.size()-1).getStartOffset() <= 40) {
826       return "..." + s.substring(wordIndices.get(wordIndices.size()-1).getStartOffset());
827     }
828
829     return StringUtil.last(s, 40, true).toString();
830   }
831
832   private static String createMismatchedArgumentsHtmlTooltip(PsiExpressionList list,
833                                                              PsiParameter[] parameters,
834                                                              String methodName,
835                                                              PsiSubstitutor substitutor,
836                                                              PsiClass aClass) {
837     return Math.max(parameters.length, list.getExpressions().length) <= 2
838            ? createShortMismatchedArgumentsHtmlTooltip(list, parameters, methodName, substitutor, aClass)
839            : createLongMismatchedArgumentsHtmlTooltip(list, parameters, methodName, substitutor, aClass);
840   }
841
842   @SuppressWarnings("StringContatenationInLoop")
843   @Language("HTML")
844   private static String createLongMismatchedArgumentsHtmlTooltip(PsiExpressionList list,
845                                                              PsiParameter[] parameters,
846                                                              String methodName,
847                                                              PsiSubstitutor substitutor,
848                                                              PsiClass aClass) {
849     PsiExpression[] expressions = list.getExpressions();
850
851     @SuppressWarnings("NonConstantStringShouldBeStringBuffer") @NonNls
852     String s = "<html><body><table border=0>" +
853                "<tr><td colspan=3>" +
854                "<nobr><b>" + methodName + "()</b> in <b>" + HighlightUtil.formatClass(aClass, false) +"</b> cannot be applied to:</nobr>" +
855                "</td></tr>"+
856                "<tr><td colspan=2 align=left>Expected<br>Parameters:</td><td align=left>Actual<br>Arguments:</td></tr>"+
857                "<tr><td colspan=3><hr></td></tr>"
858       ;
859
860     for (int i = 0; i < Math.max(parameters.length,expressions.length); i++) {
861       PsiParameter parameter = i < parameters.length ? parameters[i] : null;
862       PsiExpression expression = i < expressions.length ? expressions[i] : null;
863       boolean showShort = showShortType(i, parameters, expressions, substitutor);
864       @NonNls String mismatchColor = showShort ? null : UIUtil.isUnderDarcula() ? "FF6B68" : "red";
865
866       s += "<tr" + (i % 2 == 0 ? " style='background-color: #"
867                                  + (UIUtil.isUnderDarcula() ? ColorUtil.toHex(ColorUtil.shift(UIUtil.getToolTipBackground(), 1.1)) : "eeeeee")
868                                  + "'" : "") + ">";
869       s += "<td><b><nobr>";
870       if (parameter != null) {
871         String name = parameter.getName();
872         if (name != null) {
873           s += esctrim(name) +":";
874         }
875       }
876       s += "</nobr></b></td>";
877
878       s += "<td><b><nobr>";
879       if (parameter != null) {
880         PsiType type = substitutor.substitute(parameter.getType());
881         s +=  "<font " + (mismatchColor == null ? "" : "color=" + mismatchColor) + ">" +
882               esctrim(showShort ? type.getPresentableText() : JavaHighlightUtil.formatType(type))
883               + "</font>"
884               ;
885       }
886       s += "</nobr></b></td>";
887
888       s += "<td><b><nobr>";
889       if (expression != null) {
890         PsiType type = expression.getType();
891         s += "<font " + (mismatchColor == null ? "" : "color='" + mismatchColor + "'") + ">" +
892                esctrim(expression.getText()) + "&nbsp;&nbsp;"+
893               (mismatchColor == null || type == null || type == PsiType.NULL ? "" : "("+esctrim(JavaHighlightUtil.formatType(type))+")")
894               + "</font>"
895               ;
896
897       }
898       s += "</nobr></b></td>";
899
900       s += "</tr>";
901     }
902
903     s+= "</table>";
904     final String errorMessage = InferenceSession.getInferenceErrorMessage(list.getParent());
905     if (errorMessage != null) {
906       s+= "reason: "; 
907       s += XmlStringUtil.escapeString(errorMessage).replaceAll("\n", "<br/>");
908     }
909     s+= "</body></html>";
910     return s;
911   }
912
913   @SuppressWarnings("StringContatenationInLoop")
914   @Language("HTML")
915   private static String createMismatchedArgsHtmlTooltipArgumentsRow(final PsiExpression[] expressions, final PsiParameter[] parameters,
916                                                                       final PsiSubstitutor substitutor, final int cols) {
917     @Language("HTML")
918
919     @NonNls String ms = "";
920     for (int i = 0; i < expressions.length; i++) {
921       PsiExpression expression = expressions[i];
922       PsiType type = expression.getType();
923
924       boolean showShort = showShortType(i, parameters, expressions, substitutor);
925       @NonNls String mismatchColor = showShort ? null : MISMATCH_COLOR;
926       ms += "<td> " + "<b><nobr>" + (i == 0 ? "(" : "")
927             + "<font " + (showShort ? "" : "color=" + mismatchColor) + ">" +
928             XmlStringUtil.escapeString(showShort ? type.getPresentableText() : JavaHighlightUtil.formatType(type))
929             + "</font>"
930             + (i == expressions.length - 1 ? ")" : ",") + "</nobr></b></td>";
931     }
932     for (int i = expressions.length; i < cols + 1; i++) {
933       ms += "<td>" + (i == 0 ? "<b>()</b>" : "") +
934             "&nbsp;</td>";
935     }
936     return ms;
937   }
938
939   @SuppressWarnings("StringContatenationInLoop")
940   @Language("HTML")
941   private static String createMismatchedArgsHtmlTooltipParamsRow(final PsiParameter[] parameters,
942                                                                  final PsiSubstitutor substitutor,
943                                                                  final PsiExpression[] expressions) {
944     @NonNls String ms = "";
945     for (int i = 0; i < parameters.length; i++) {
946       PsiParameter parameter = parameters[i];
947       PsiType type = substitutor.substitute(parameter.getType());
948       ms += "<td><b><nobr>" + (i == 0 ? "(" : "") +
949             XmlStringUtil.escapeString(showShortType(i, parameters, expressions, substitutor)
950                                  ? type.getPresentableText()
951                                  : JavaHighlightUtil.formatType(type))
952             + (i == parameters.length - 1 ? ")" : ",") + "</nobr></b></td>";
953     }
954     return ms;
955   }
956
957   private static boolean showShortType(int i,
958                                        PsiParameter[] parameters,
959                                        PsiExpression[] expressions,
960                                        PsiSubstitutor substitutor) {
961     PsiExpression expression = i < expressions.length ? expressions[i] : null;
962     if (expression == null) return true;
963     PsiType paramType = i < parameters.length && parameters[i] != null
964                         ? substitutor.substitute(parameters[i].getType())
965                         : null;
966     PsiType expressionType = expression.getType();
967     return paramType != null && expressionType != null && TypeConversionUtil.isAssignable(paramType, expressionType);
968   }
969
970
971   static HighlightInfo checkMethodMustHaveBody(PsiMethod method, PsiClass aClass) {
972     HighlightInfo errorResult = null;
973     if (method.getBody() == null
974         && !method.hasModifierProperty(PsiModifier.ABSTRACT)
975         && !method.hasModifierProperty(PsiModifier.NATIVE)
976         && aClass != null
977         && !aClass.isInterface()
978         && !PsiUtilCore.hasErrorElementChild(method)) {
979       int start = method.getModifierList().getTextRange().getStartOffset();
980       int end = method.getTextRange().getEndOffset();
981
982       String description = JavaErrorMessages.message("missing.method.body");
983       errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(start, end).descriptionAndTooltip(description).create();
984       if (HighlightUtil.getIncompatibleModifier(PsiModifier.ABSTRACT, method.getModifierList()) == null) {
985         QuickFixAction.registerQuickFixAction(errorResult,
986                                               QUICK_FIX_FACTORY.createModifierListFix(method, PsiModifier.ABSTRACT, true, false));
987       }
988       QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createAddMethodBodyFix(method));
989     }
990     return errorResult;
991   }
992
993
994   static HighlightInfo checkAbstractMethodInConcreteClass(PsiMethod method, PsiElement elementToHighlight) {
995     HighlightInfo errorResult = null;
996     PsiClass aClass = method.getContainingClass();
997     if (method.hasModifierProperty(PsiModifier.ABSTRACT)
998         && aClass != null
999         && !aClass.hasModifierProperty(PsiModifier.ABSTRACT)
1000         && !aClass.isEnum()
1001         && !PsiUtilCore.hasErrorElementChild(method)) {
1002       String description = JavaErrorMessages.message("abstract.method.in.non.abstract.class");
1003       errorResult =
1004         HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(elementToHighlight).descriptionAndTooltip(description).create();
1005       if (method.getBody() != null) {
1006         QuickFixAction.registerQuickFixAction(errorResult,
1007                                               QUICK_FIX_FACTORY.createModifierListFix(method, PsiModifier.ABSTRACT, false, false));
1008       }
1009       QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createAddMethodBodyFix(method));
1010       QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createModifierListFix(aClass, PsiModifier.ABSTRACT, true, false));
1011     }
1012     return errorResult;
1013   }
1014
1015
1016   static HighlightInfo checkConstructorName(PsiMethod method) {
1017     String methodName = method.getName();
1018     PsiClass aClass = method.getContainingClass();
1019     HighlightInfo errorResult = null;
1020
1021     if (aClass != null) {
1022       String className = aClass instanceof PsiAnonymousClass ? null : aClass.getName();
1023       if (className == null || !Comparing.strEqual(methodName, className)) {
1024         PsiElement element = method.getNameIdentifier();
1025         String description = JavaErrorMessages.message("missing.return.type");
1026         errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create();
1027         if (className != null) {
1028           QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createRenameElementFix(method, className));
1029         }
1030       }
1031     }
1032     return errorResult;
1033   }
1034
1035   @Nullable
1036   static HighlightInfo checkDuplicateMethod(PsiClass aClass,
1037                                             @NotNull PsiMethod method,
1038                                             @NotNull MostlySingularMultiMap<MethodSignature, PsiMethod> duplicateMethods) {
1039     if (aClass == null || method instanceof ExternallyDefinedPsiElement) return null;
1040     MethodSignature methodSignature = method.getSignature(PsiSubstitutor.EMPTY);
1041     int methodCount = 1;
1042     List<PsiMethod> methods = (List<PsiMethod>)duplicateMethods.get(methodSignature);
1043     if (methods.size() > 1) {
1044       methodCount++;
1045     }
1046
1047     if (methodCount == 1 && aClass.isEnum() &&
1048         GenericsHighlightUtil.isEnumSyntheticMethod(methodSignature, aClass.getProject())) {
1049       methodCount++;
1050     }
1051     if (methodCount > 1) {
1052       String description = JavaErrorMessages.message("duplicate.method",
1053                                                  JavaHighlightUtil.formatMethod(method),
1054                                                  HighlightUtil.formatClass(aClass));
1055       TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method);
1056       return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).
1057         range(method, textRange.getStartOffset(), textRange.getEndOffset()).
1058         descriptionAndTooltip(description).create();
1059     }
1060     return null;
1061   }
1062
1063   @Nullable
1064   static HighlightInfo checkMethodCanHaveBody(@NotNull PsiMethod method, @NotNull LanguageLevel languageLevel) {
1065     PsiClass aClass = method.getContainingClass();
1066     boolean hasNoBody = method.getBody() == null;
1067     boolean isInterface = aClass != null && aClass.isInterface();
1068     boolean isExtension = method.hasModifierProperty(PsiModifier.DEFAULT);
1069     boolean isStatic = method.hasModifierProperty(PsiModifier.STATIC);
1070     boolean isPrivate = method.hasModifierProperty(PsiModifier.PRIVATE);
1071
1072     final List<IntentionAction> additionalFixes = new ArrayList<IntentionAction>();
1073     String description = null;
1074     if (hasNoBody) {
1075       if (isExtension) {
1076         description = JavaErrorMessages.message("extension.method.should.have.a.body");
1077         additionalFixes.add(QUICK_FIX_FACTORY.createAddMethodBodyFix(method));
1078       }
1079       else if (isInterface && isStatic && languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
1080         description = "Static methods in interfaces should have a body";
1081       }
1082     }
1083     else if (isInterface) {
1084       if (!isExtension && !isStatic && !isPrivate) {
1085         description = JavaErrorMessages.message("interface.methods.cannot.have.body");
1086         if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
1087           additionalFixes.add(QUICK_FIX_FACTORY.createModifierListFix(method, PsiModifier.DEFAULT, true, false));
1088           additionalFixes.add(QUICK_FIX_FACTORY.createModifierListFix(method, PsiModifier.STATIC, true, false));
1089         }
1090       }
1091     }
1092     else if (isExtension) {
1093       description = JavaErrorMessages.message("extension.method.in.class");
1094     }
1095     else if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
1096       description = JavaErrorMessages.message("abstract.methods.cannot.have.a.body");
1097     }
1098     else if (method.hasModifierProperty(PsiModifier.NATIVE)) {
1099       description = JavaErrorMessages.message("native.methods.cannot.have.a.body");
1100     }
1101     if (description == null) return null;
1102
1103     TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method);
1104     HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
1105     if (!hasNoBody) {
1106       QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createDeleteMethodBodyFix(method));
1107     }
1108     if (method.hasModifierProperty(PsiModifier.ABSTRACT) && !isInterface) {
1109       QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createModifierListFix(method, PsiModifier.ABSTRACT, false, false));
1110     }
1111     for (IntentionAction intentionAction : additionalFixes) {
1112       QuickFixAction.registerQuickFixAction(info, intentionAction);
1113     }
1114     return info;
1115   }
1116
1117   @Nullable
1118   static HighlightInfo checkConstructorCallMustBeFirstStatement(@NotNull PsiMethodCallExpression methodCall) {
1119     if (!RefactoringChangeUtil.isSuperOrThisMethodCall(methodCall)) return null;
1120     PsiElement codeBlock = methodCall.getParent().getParent();
1121     if (codeBlock instanceof PsiCodeBlock
1122         && codeBlock.getParent() instanceof PsiMethod
1123         && ((PsiMethod)codeBlock.getParent()).isConstructor()) {
1124       PsiElement prevSibling = methodCall.getParent().getPrevSibling();
1125       while (true) {
1126         if (prevSibling == null) return null;
1127         if (prevSibling instanceof PsiStatement) break;
1128         prevSibling = prevSibling.getPrevSibling();
1129       }
1130     }
1131     PsiReferenceExpression expression = methodCall.getMethodExpression();
1132     String message = JavaErrorMessages.message("constructor.call.must.be.first.statement", expression.getText() + "()");
1133     return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(methodCall).descriptionAndTooltip(message).create();
1134   }
1135
1136
1137   static HighlightInfo checkSuperAbstractMethodDirectCall(@NotNull PsiMethodCallExpression methodCallExpression) {
1138     PsiReferenceExpression expression = methodCallExpression.getMethodExpression();
1139     if (!(expression.getQualifierExpression() instanceof PsiSuperExpression)) return null;
1140     PsiMethod method = methodCallExpression.resolveMethod();
1141     if (method != null && method.hasModifierProperty(PsiModifier.ABSTRACT)) {
1142       String message = JavaErrorMessages.message("direct.abstract.method.access", JavaHighlightUtil.formatMethod(method));
1143       return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(methodCallExpression).descriptionAndTooltip(message).create();
1144     }
1145     return null;
1146   }
1147
1148
1149   static HighlightInfo checkConstructorCallsBaseClassConstructor(PsiMethod constructor,
1150                                                                         RefCountHolder refCountHolder,
1151                                                                         PsiResolveHelper resolveHelper) {
1152     if (!constructor.isConstructor()) return null;
1153     PsiClass aClass = constructor.getContainingClass();
1154     if (aClass == null) return null;
1155     if (aClass.isEnum()) return null;
1156     PsiCodeBlock body = constructor.getBody();
1157     if (body == null) return null;
1158
1159     // check whether constructor call super(...) or this(...)
1160     PsiElement element = new PsiMatcherImpl(body)
1161       .firstChild(PsiMatchers.hasClass(PsiExpressionStatement.class))
1162       .firstChild(PsiMatchers.hasClass(PsiMethodCallExpression.class))
1163       .firstChild(PsiMatchers.hasClass(PsiReferenceExpression.class))
1164       .firstChild(PsiMatchers.hasClass(PsiKeyword.class))
1165       .getElement();
1166     if (element != null) return null;
1167     TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(constructor);
1168     PsiClassType[] handledExceptions = constructor.getThrowsList().getReferencedTypes();
1169     HighlightInfo info = HighlightClassUtil.checkBaseClassDefaultConstructorProblem(aClass, refCountHolder, resolveHelper, textRange, handledExceptions);
1170     if (info != null) {
1171       QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createInsertSuperFix(constructor));
1172       QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createAddDefaultConstructorFix(aClass.getSuperClass()));
1173     }
1174     return info;
1175   }
1176
1177
1178   /**
1179    * @return error if static method overrides instance method or
1180    *         instance method overrides static. see JLS 8.4.6.1, 8.4.6.2
1181    */
1182   static HighlightInfo checkStaticMethodOverride(@NotNull PsiMethod method,@NotNull PsiFile containingFile) {
1183     // constructors are not members and therefor don't override class methods
1184     if (method.isConstructor()) {
1185       return null;
1186     }
1187
1188     PsiClass aClass = method.getContainingClass();
1189     if (aClass == null) return null;
1190     final HierarchicalMethodSignature methodSignature = PsiSuperMethodImplUtil.getHierarchicalMethodSignature(method);
1191     final List<HierarchicalMethodSignature> superSignatures = methodSignature.getSuperSignatures();
1192     if (superSignatures.isEmpty()) {
1193       return null;
1194     }
1195
1196     boolean isStatic = method.hasModifierProperty(PsiModifier.STATIC);
1197     for (HierarchicalMethodSignature signature : superSignatures) {
1198       final PsiMethod superMethod = signature.getMethod();
1199       final PsiClass superClass = superMethod.getContainingClass();
1200       if (superClass == null) continue;
1201       final HighlightInfo highlightInfo = checkStaticMethodOverride(aClass, method, isStatic, superClass, superMethod,containingFile);
1202       if (highlightInfo != null) {
1203         return highlightInfo;
1204       }
1205     }
1206     return null;
1207   }
1208
1209   private static HighlightInfo checkStaticMethodOverride(PsiClass aClass, PsiMethod method, boolean isMethodStatic, PsiClass superClass, PsiMethod superMethod,@NotNull PsiFile containingFile) {
1210     if (superMethod == null) return null;
1211     PsiManager manager = containingFile.getManager();
1212     PsiModifierList superModifierList = superMethod.getModifierList();
1213     PsiModifierList modifierList = method.getModifierList();
1214     if (superModifierList.hasModifierProperty(PsiModifier.PRIVATE)) return null;
1215     if (superModifierList.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)
1216         && !JavaPsiFacade.getInstance(manager.getProject()).arePackagesTheSame(aClass, superClass)) {
1217       return null;
1218     }
1219     boolean isSuperMethodStatic = superModifierList.hasModifierProperty(PsiModifier.STATIC);
1220     if (isMethodStatic != isSuperMethodStatic) {
1221       TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method);
1222       @NonNls final String messageKey = isMethodStatic
1223                                 ? "static.method.cannot.override.instance.method"
1224                                 : "instance.method.cannot.override.static.method";
1225
1226       String description = JavaErrorMessages.message(messageKey,
1227                                                  JavaHighlightUtil.formatMethod(method),
1228                                                  HighlightUtil.formatClass(aClass),
1229                                                  JavaHighlightUtil.formatMethod(superMethod),
1230                                                  HighlightUtil.formatClass(superClass));
1231
1232       HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
1233       if (!isSuperMethodStatic || HighlightUtil.getIncompatibleModifier(PsiModifier.STATIC, modifierList) == null) {
1234         QuickFixAction.registerQuickFixAction(info,
1235                                               QUICK_FIX_FACTORY.createModifierListFix(method, PsiModifier.STATIC, isSuperMethodStatic, false));
1236       }
1237       if (manager.isInProject(superMethod) &&
1238           (!isMethodStatic || HighlightUtil.getIncompatibleModifier(PsiModifier.STATIC, superModifierList) == null)) {
1239         QuickFixAction.registerQuickFixAction(info,
1240                                               QUICK_FIX_FACTORY.createModifierListFix(superMethod, PsiModifier.STATIC, isMethodStatic, true));
1241       }
1242       return info;
1243     }
1244
1245     if (isMethodStatic) {
1246       if (superClass.isInterface()) return null;
1247       int accessLevel = PsiUtil.getAccessLevel(modifierList);
1248       String accessModifier = PsiUtil.getAccessModifier(accessLevel);
1249       HighlightInfo info = isWeaker(method, modifierList, accessModifier, accessLevel, superMethod, true);
1250       if (info != null) return info;
1251       info = checkSuperMethodIsFinal(method, superMethod);
1252       if (info != null) return info;
1253     }
1254     return null;
1255   }
1256
1257   private static HighlightInfo checkInterfaceInheritedMethodsReturnTypes(@NotNull List<? extends MethodSignatureBackedByPsiMethod> superMethodSignatures,
1258                                                                          @NotNull LanguageLevel languageLevel) {
1259     if (superMethodSignatures.size() < 2) return null;
1260     MethodSignatureBackedByPsiMethod returnTypeSubstitutable = superMethodSignatures.get(0);
1261     for (int i = 1; i < superMethodSignatures.size(); i++) {
1262       PsiMethod currentMethod = returnTypeSubstitutable.getMethod();
1263       PsiType currentType = returnTypeSubstitutable.getSubstitutor().substitute(currentMethod.getReturnType());
1264
1265       MethodSignatureBackedByPsiMethod otherSuperSignature = superMethodSignatures.get(i);
1266       PsiMethod otherSuperMethod = otherSuperSignature.getMethod();
1267       PsiType otherSuperReturnType = otherSuperSignature.getSubstitutor().substitute(otherSuperMethod.getReturnType());
1268
1269       PsiSubstitutor unifyingSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(returnTypeSubstitutable,
1270                                                                                                   otherSuperSignature);
1271       if (unifyingSubstitutor != null) {
1272         otherSuperReturnType = unifyingSubstitutor.substitute(otherSuperReturnType);
1273         currentType = unifyingSubstitutor.substitute(currentType);
1274       }
1275
1276       if (otherSuperReturnType == null || currentType == null || otherSuperReturnType.equals(currentType)) continue;
1277
1278       if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5)) {
1279         //http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8 Example 8.1.5-3
1280         if (!(otherSuperReturnType instanceof PsiPrimitiveType || currentType instanceof PsiPrimitiveType)) {
1281           if (otherSuperReturnType.isAssignableFrom(currentType)) continue;
1282           if (currentType.isAssignableFrom(otherSuperReturnType)) {
1283             returnTypeSubstitutable = otherSuperSignature;
1284             continue;
1285           }
1286         }
1287         if (currentMethod.getTypeParameters().length > 0 && JavaGenericsUtil.isRawToGeneric(currentType, otherSuperReturnType)) continue;
1288       }
1289       return createIncompatibleReturnTypeMessage(currentMethod, otherSuperMethod, otherSuperReturnType,
1290                                                  currentType, JavaErrorMessages.message("unrelated.overriding.methods.return.types"),
1291                                                  TextRange.EMPTY_RANGE);
1292     }
1293     return null;
1294   }
1295
1296   static HighlightInfo checkOverrideEquivalentInheritedMethods(PsiClass aClass, PsiFile containingFile, @NotNull LanguageLevel languageLevel) {
1297     String description = null;
1298     final Collection<HierarchicalMethodSignature> visibleSignatures = aClass.getVisibleSignatures();
1299     PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(aClass.getProject()).getResolveHelper();
1300     Ultimate:
1301     for (HierarchicalMethodSignature signature : visibleSignatures) {
1302       PsiMethod method = signature.getMethod();
1303       if (!resolveHelper.isAccessible(method, aClass, null)) continue;
1304       List<HierarchicalMethodSignature> superSignatures = signature.getSuperSignatures();
1305
1306       boolean allAbstracts = method.hasModifierProperty(PsiModifier.ABSTRACT);
1307       final PsiClass containingClass = method.getContainingClass();
1308       if (aClass.equals(containingClass)) continue; //to be checked at method level
1309
1310       if (aClass.isInterface() && !containingClass.isInterface()) continue;
1311       HighlightInfo highlightInfo;
1312       if (allAbstracts) {
1313         superSignatures = new ArrayList<HierarchicalMethodSignature>(superSignatures);
1314         superSignatures.add(signature);
1315         highlightInfo = checkInterfaceInheritedMethodsReturnTypes(superSignatures, languageLevel);
1316       }
1317       else {
1318         highlightInfo = checkMethodIncompatibleReturnType(signature, superSignatures, false);
1319       }
1320       if (highlightInfo != null) description = highlightInfo.getDescription();
1321
1322       if (method.hasModifierProperty(PsiModifier.STATIC)) {
1323         for (HierarchicalMethodSignature superSignature : superSignatures) {
1324           PsiMethod superMethod = superSignature.getMethod();
1325           if (!superMethod.hasModifierProperty(PsiModifier.STATIC)) {
1326             description = JavaErrorMessages.message("static.method.cannot.override.instance.method",
1327                                                          JavaHighlightUtil.formatMethod(method),
1328                                                          HighlightUtil.formatClass(containingClass),
1329                                                          JavaHighlightUtil.formatMethod(superMethod),
1330                                                          HighlightUtil.formatClass(superMethod.getContainingClass()));
1331             break Ultimate;
1332           }
1333         }
1334         continue;
1335       }
1336
1337       if (description == null) {
1338         highlightInfo = checkMethodIncompatibleThrows(signature, superSignatures, false, aClass);
1339         if (highlightInfo != null) description = highlightInfo.getDescription();
1340       }
1341
1342       if (description == null) {
1343         highlightInfo = checkMethodWeakerPrivileges(signature, superSignatures, false, containingFile);
1344         if (highlightInfo != null) description = highlightInfo.getDescription();
1345       }
1346
1347       if (description != null) break;
1348     }
1349
1350
1351     if (description != null) {
1352       // show error info at the class level
1353       TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass);
1354       return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
1355     }
1356     return null;
1357   }
1358
1359
1360   static HighlightInfo checkConstructorHandleSuperClassExceptions(PsiMethod method) {
1361     if (!method.isConstructor()) {
1362       return null;
1363     }
1364     PsiCodeBlock body = method.getBody();
1365     PsiStatement[] statements = body == null ? null : body.getStatements();
1366     if (statements == null) return null;
1367
1368     // if we have unhandled exception inside method body, we could not have been called here,
1369     // so the only problem it can catch here is with super ctr only
1370     Collection<PsiClassType> unhandled = ExceptionUtil.collectUnhandledExceptions(method, method.getContainingClass());
1371     if (unhandled.isEmpty()) return null;
1372     String description = HighlightUtil.getUnhandledExceptionsDescriptor(unhandled);
1373     TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method);
1374     HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
1375     for (PsiClassType exception : unhandled) {
1376       QuickFixAction.registerQuickFixAction(highlightInfo, new LocalQuickFixOnPsiElementAsIntentionAdapter(QUICK_FIX_FACTORY.createMethodThrowsFix(method, exception, true, false)));
1377     }
1378     return highlightInfo;
1379   }
1380
1381
1382   static HighlightInfo checkRecursiveConstructorInvocation(@NotNull PsiMethod method) {
1383     if (HighlightControlFlowUtil.isRecursivelyCalledConstructor(method)) {
1384       TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method);
1385       String description = JavaErrorMessages.message("recursive.constructor.invocation");
1386       return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
1387     }
1388     return null;
1389   }
1390
1391   @NotNull
1392   public static TextRange getFixRange(@NotNull PsiElement element) {
1393     TextRange range = element.getTextRange();
1394     int start = range.getStartOffset();
1395     int end = range.getEndOffset();
1396
1397     PsiElement nextSibling = element.getNextSibling();
1398     if (nextSibling instanceof PsiJavaToken && ((PsiJavaToken)nextSibling).getTokenType() == JavaTokenType.SEMICOLON) {
1399       return new TextRange(start, end + 1);
1400     }
1401     return range;
1402   }
1403
1404
1405   static void checkNewExpression(@NotNull PsiNewExpression expression,
1406                                  PsiType type,
1407                                  @NotNull HighlightInfoHolder holder,
1408                                  @NotNull JavaSdkVersion javaSdkVersion) {
1409     if (!(type instanceof PsiClassType)) return;
1410     PsiClassType.ClassResolveResult typeResult = ((PsiClassType)type).resolveGenerics();
1411     PsiClass aClass = typeResult.getElement();
1412     if (aClass == null) return;
1413     if (aClass instanceof PsiAnonymousClass) {
1414       type = ((PsiAnonymousClass)aClass).getBaseClassType();
1415       typeResult = ((PsiClassType)type).resolveGenerics();
1416       aClass = typeResult.getElement();
1417       if (aClass == null) return;
1418     }
1419
1420     PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
1421     checkConstructorCall(typeResult, expression, type, classReference, holder, javaSdkVersion);
1422   }
1423
1424
1425   static void checkConstructorCall(@NotNull PsiClassType.ClassResolveResult typeResolveResult,
1426                                    @NotNull PsiConstructorCall constructorCall,
1427                                    @NotNull PsiType type,
1428                                    PsiJavaCodeReferenceElement classReference,
1429                                    @NotNull HighlightInfoHolder holder,
1430                                    @NotNull JavaSdkVersion javaSdkVersion) {
1431     PsiExpressionList list = constructorCall.getArgumentList();
1432     if (list == null) return;
1433     PsiClass aClass = typeResolveResult.getElement();
1434     if (aClass == null) return;
1435     final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(holder.getProject()).getResolveHelper();
1436     PsiClass accessObjectClass = null;
1437     if (constructorCall instanceof PsiNewExpression) {
1438       PsiExpression qualifier = ((PsiNewExpression)constructorCall).getQualifier();
1439       if (qualifier != null) {
1440         accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass(qualifier).getElement();
1441       }
1442     }
1443     if (classReference != null && !resolveHelper.isAccessible(aClass, constructorCall, accessObjectClass)) {
1444       String description = HighlightUtil.buildProblemWithAccessDescription(classReference, typeResolveResult);
1445       PsiElement element = classReference.getReferenceNameElement();
1446       HighlightInfo info =
1447         HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create();
1448       HighlightUtil.registerAccessQuickFixAction(aClass, classReference, info, null);
1449       holder.add(info);
1450       return;
1451     }
1452     PsiMethod[] constructors = aClass.getConstructors();
1453
1454     if (constructors.length == 0) {
1455       if (list.getExpressions().length != 0) {
1456         String constructorName = aClass.getName();
1457         String argTypes = buildArgTypesList(list);
1458         String description = JavaErrorMessages.message("wrong.constructor.arguments", constructorName+"()", argTypes);
1459         String tooltip = createMismatchedArgumentsHtmlTooltip(list, PsiParameter.EMPTY_ARRAY, constructorName, PsiSubstitutor.EMPTY, aClass);
1460         HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list).description(description).escapedToolTip(tooltip).navigationShift(+1).create();
1461         QuickFixAction.registerQuickFixAction(info, constructorCall.getTextRange(), QUICK_FIX_FACTORY.createCreateConstructorFromCallFix(constructorCall));
1462         if (classReference != null) {
1463           ConstructorParametersFixer.registerFixActions(classReference, constructorCall, info,getFixRange(list));
1464         }
1465         holder.add(info);
1466         return;
1467       }
1468       if (classReference != null && aClass.hasModifierProperty(PsiModifier.PROTECTED) && callingProtectedConstructorFromDerivedClass(constructorCall, aClass)) {
1469         holder.add(buildAccessProblem(classReference, typeResolveResult, aClass));
1470       } else if (aClass.isInterface() && constructorCall instanceof PsiNewExpression) {
1471         final PsiReferenceParameterList typeArgumentList = ((PsiNewExpression)constructorCall).getTypeArgumentList();
1472         if (typeArgumentList.getTypeArguments().length > 0) {
1473           holder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeArgumentList)
1474             .descriptionAndTooltip("Anonymous class implements interface; cannot have type arguments").create());
1475         }
1476       }
1477     }
1478     else {
1479       PsiElement place = list;
1480       if (constructorCall instanceof PsiNewExpression) {
1481         final PsiAnonymousClass anonymousClass = ((PsiNewExpression)constructorCall).getAnonymousClass();
1482         if (anonymousClass != null) place = anonymousClass;
1483       }
1484
1485       JavaResolveResult[] results = resolveHelper.multiResolveConstructor((PsiClassType)type, list, place);
1486       MethodCandidateInfo result = null;
1487       if (results.length == 1) result = (MethodCandidateInfo)results[0];
1488
1489       PsiMethod constructor = result == null ? null : result.getElement();
1490
1491       boolean applicable = true;
1492       try {
1493         applicable = constructor != null && result.isApplicable();
1494       }
1495       catch (IndexNotReadyException e) {
1496         // ignore
1497       }
1498
1499       PsiElement infoElement = list.getTextLength() > 0 ? list : constructorCall;
1500       if (constructor == null) {
1501         String name = aClass.getName();
1502         name += buildArgTypesList(list);
1503         String description = JavaErrorMessages.message("cannot.resolve.constructor", name);
1504         HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list).descriptionAndTooltip(description).navigationShift(+1).create();
1505         WrapExpressionFix.registerWrapAction(results, list.getExpressions(), info);
1506         registerFixesOnInvalidConstructorCall(constructorCall, classReference, list, aClass, constructors, results, infoElement, info);
1507         holder.add(info);
1508       }
1509       else {
1510         if (classReference != null && (!result.isAccessible() ||
1511                                        constructor.hasModifierProperty(PsiModifier.PROTECTED) && callingProtectedConstructorFromDerivedClass(constructorCall, aClass))) {
1512           holder.add(buildAccessProblem(classReference, result, constructor));
1513         }
1514         else if (!applicable) {
1515           String constructorName = HighlightMessageUtil.getSymbolName(constructor, result.getSubstitutor());
1516           String containerName = HighlightMessageUtil.getSymbolName(constructor.getContainingClass(), result.getSubstitutor());
1517           String argTypes = buildArgTypesList(list);
1518           String description = JavaErrorMessages.message("wrong.method.arguments", constructorName, containerName, argTypes);
1519           String toolTip = createMismatchedArgumentsHtmlTooltip(result, list);
1520           
1521           HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(infoElement).description(description).escapedToolTip(toolTip).navigationShift(+1).create();
1522           if (info != null) {
1523             registerFixesOnInvalidConstructorCall(constructorCall, classReference, list, aClass, constructors, results, infoElement, info);
1524             registerMethodReturnFixAction(info, result, constructorCall);
1525             holder.add(info);
1526           }
1527         }
1528         else {
1529           if (constructorCall instanceof PsiNewExpression) {
1530             PsiReferenceParameterList typeArgumentList = ((PsiNewExpression)constructorCall).getTypeArgumentList();
1531             HighlightInfo info = GenericsHighlightUtil.checkReferenceTypeArgumentList(constructor, typeArgumentList, result.getSubstitutor(), false, javaSdkVersion);
1532             if (info != null) {
1533               holder.add(info);
1534             }
1535           }
1536         }
1537       }
1538       
1539       if (result != null && !holder.hasErrorResults()) {
1540         holder.add(checkVarargParameterErasureToBeAccessible(result, constructorCall));
1541       }
1542     }
1543   }
1544
1545   /**
1546    * If the compile-time declaration is applicable by variable arity invocation,
1547    * then where the last formal parameter type of the invocation type of the method is Fn[], 
1548    * it is a compile-time error if the type which is the erasure of Fn is not accessible at the point of invocation.
1549    */
1550   private static HighlightInfo checkVarargParameterErasureToBeAccessible(MethodCandidateInfo info, PsiCall place) {
1551     final PsiMethod method = info.getElement();
1552     if (info.isVarargs() || method.isVarArgs() && !PsiUtil.isLanguageLevel8OrHigher(place)) {
1553       final PsiParameter[] parameters = method.getParameterList().getParameters();
1554       final PsiType componentType = ((PsiEllipsisType)parameters[parameters.length - 1].getType()).getComponentType();
1555       final PsiType substitutedTypeErasure = TypeConversionUtil.erasure(info.getSubstitutor().substitute(componentType));
1556       final PsiClass targetClass = PsiUtil.resolveClassInClassTypeOnly(substitutedTypeErasure);
1557       if (targetClass != null && !PsiUtil.isAccessible(targetClass, place, null)) {
1558         final PsiExpressionList argumentList = place.getArgumentList();
1559         return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
1560           .descriptionAndTooltip("Formal varargs element type " +
1561                                  PsiFormatUtil.formatClass(targetClass, PsiFormatUtilBase.SHOW_FQ_NAME) +
1562                                  " is inaccessible here")
1563           .range(argumentList != null ? argumentList : place)
1564           .create();
1565       }
1566     }
1567     return null;
1568   }
1569
1570   private static void registerFixesOnInvalidConstructorCall(PsiConstructorCall constructorCall,
1571                                                             PsiJavaCodeReferenceElement classReference,
1572                                                             PsiExpressionList list,
1573                                                             PsiClass aClass,
1574                                                             PsiMethod[] constructors,
1575                                                             JavaResolveResult[] results, PsiElement infoElement, HighlightInfo info) {
1576     QuickFixAction
1577       .registerQuickFixAction(info, constructorCall.getTextRange(), QUICK_FIX_FACTORY.createCreateConstructorFromCallFix(constructorCall));
1578     if (classReference != null) {
1579       ConstructorParametersFixer.registerFixActions(classReference, constructorCall, info, getFixRange(infoElement));
1580       ChangeTypeArgumentsFix.registerIntentions(results, list, info, aClass);
1581       ConvertDoubleToFloatFix.registerIntentions(results, list, info, null);
1582     }
1583     registerChangeMethodSignatureFromUsageIntentions(results, list, info, null);
1584     PermuteArgumentsFix.registerFix(info, constructorCall, toMethodCandidates(results), getFixRange(list));
1585     registerChangeParameterClassFix(constructorCall, list, info);
1586     QuickFixAction.registerQuickFixAction(info, getFixRange(list), QUICK_FIX_FACTORY.createSurroundWithArrayFix(constructorCall,null));
1587     ChangeStringLiteralToCharInMethodCallFix.registerFixes(constructors, constructorCall, info);
1588   }
1589
1590   private static HighlightInfo buildAccessProblem(@NotNull PsiJavaCodeReferenceElement classReference, JavaResolveResult result, PsiMember elementToFix) {
1591     String description = HighlightUtil.buildProblemWithAccessDescription(classReference, result);
1592     HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(classReference).descriptionAndTooltip(
1593       description).navigationShift(+1).create();
1594     if (result.isStaticsScopeCorrect()) {
1595       HighlightUtil.registerAccessQuickFixAction(elementToFix, classReference, info, result.getCurrentFileResolveScope());
1596     }
1597     return info;
1598   }
1599
1600   private static boolean callingProtectedConstructorFromDerivedClass(PsiConstructorCall place, PsiClass constructorClass) {
1601     if (constructorClass == null) return false;
1602     // indirect instantiation via anonymous class is ok
1603     if (place instanceof PsiNewExpression && ((PsiNewExpression)place).getAnonymousClass() != null) return false;
1604     PsiElement curElement = place;
1605     PsiClass containingClass = constructorClass.getContainingClass();
1606     while (true) {
1607       PsiClass aClass = PsiTreeUtil.getParentOfType(curElement, PsiClass.class);
1608       if (aClass == null) return false;
1609       curElement = aClass;
1610       if ((aClass.isInheritor(constructorClass, true) || containingClass != null && aClass.isInheritor(containingClass, true))
1611           && !JavaPsiFacade.getInstance(aClass.getProject()).arePackagesTheSame(aClass, constructorClass)) {
1612         return true;
1613       }
1614     }
1615   }
1616
1617   private static String buildArgTypesList(PsiExpressionList list) {
1618     StringBuilder builder = new StringBuilder();
1619     builder.append("(");
1620     PsiExpression[] args = list.getExpressions();
1621     for (int i = 0; i < args.length; i++) {
1622       if (i > 0) {
1623         builder.append(", ");
1624       }
1625       PsiType argType = args[i].getType();
1626       builder.append(argType != null ? JavaHighlightUtil.formatType(argType) : "?");
1627     }
1628     builder.append(")");
1629     return builder.toString();
1630   }
1631
1632   private static void registerChangeParameterClassFix(@NotNull PsiCall methodCall,
1633                                                       @NotNull PsiExpressionList list,
1634                                                       HighlightInfo highlightInfo) {
1635     final JavaResolveResult result = methodCall.resolveMethodGenerics();
1636     PsiMethod method = (PsiMethod)result.getElement();
1637     final PsiSubstitutor substitutor = result.getSubstitutor();
1638     PsiExpression[] expressions = list.getExpressions();
1639     if (method == null) return;
1640     final PsiParameter[] parameters = method.getParameterList().getParameters();
1641     if (parameters.length != expressions.length) return;
1642     for (int i = 0; i < expressions.length; i++) {
1643       final PsiExpression expression = expressions[i];
1644       final PsiParameter parameter = parameters[i];
1645       final PsiType expressionType = expression.getType();
1646       final PsiType parameterType = substitutor.substitute(parameter.getType());
1647       if (expressionType == null || expressionType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(expressionType) || expressionType instanceof PsiArrayType) continue;
1648       if (parameterType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(parameterType) || parameterType instanceof PsiArrayType) continue;
1649       if (parameterType.isAssignableFrom(expressionType)) continue;
1650       PsiClass parameterClass = PsiUtil.resolveClassInType(parameterType);
1651       PsiClass expressionClass = PsiUtil.resolveClassInType(expressionType);
1652       if (parameterClass == null || expressionClass == null) continue;
1653       if (expressionClass instanceof PsiAnonymousClass) continue;
1654       if (parameterClass.isInheritor(expressionClass, true)) continue;
1655       QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createChangeParameterClassFix(expressionClass, (PsiClassType)parameterType));
1656     }
1657   }
1658
1659   private static void registerChangeMethodSignatureFromUsageIntentions(@NotNull JavaResolveResult[] candidates,
1660                                                                        @NotNull PsiExpressionList list,
1661                                                                        @Nullable HighlightInfo highlightInfo,
1662                                                                        TextRange fixRange) {
1663     if (candidates.length == 0) return;
1664     PsiExpression[] expressions = list.getExpressions();
1665     for (JavaResolveResult candidate : candidates) {
1666       registerChangeMethodSignatureFromUsageIntention(expressions, highlightInfo, fixRange, candidate, list);
1667     }
1668   }
1669
1670   private static void registerChangeMethodSignatureFromUsageIntention(@NotNull PsiExpression[] expressions,
1671                                                                       @Nullable HighlightInfo highlightInfo,
1672                                                                       TextRange fixRange,
1673                                                                       @NotNull JavaResolveResult candidate,
1674                                                                       @NotNull PsiElement context) {
1675     if (!candidate.isStaticsScopeCorrect()) return;
1676     PsiMethod method = (PsiMethod)candidate.getElement();
1677     PsiSubstitutor substitutor = candidate.getSubstitutor();
1678     if (method != null && context.getManager().isInProject(method)) {
1679       IntentionAction fix = QUICK_FIX_FACTORY.createChangeMethodSignatureFromUsageFix(method, expressions, substitutor, context, false, 2);
1680       QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, fix);
1681       IntentionAction f2 = QUICK_FIX_FACTORY.createChangeMethodSignatureFromUsageReverseOrderFix(method, expressions, substitutor, context,
1682                                                                                                  false, 2);
1683       QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, f2);
1684     }
1685   }
1686 }