2 * Copyright 2000-2015 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.codeInsight.daemon.impl.analysis;
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;
52 import java.text.MessageFormat;
53 import java.util.ArrayList;
54 import java.util.Collection;
55 import java.util.List;
58 * Highlight method problems
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";
67 private HighlightMethodUtil() { }
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()));
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;
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),
106 PsiUtil.getAccessModifier(superAccessLevel));
108 if (includeRealPositionInfo) {
109 if (modifierList.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
110 textRange = method.getNameIdentifier().getTextRange();
113 PsiElement keyword = PsiUtil.findModifierInList(modifierList, accessModifier);
114 textRange = keyword.getTextRange();
118 textRange = TextRange.EMPTY_RANGE;
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;
129 static HighlightInfo checkMethodIncompatibleReturnType(@NotNull MethodSignatureBackedByPsiMethod methodSignature,
130 @NotNull List<HierarchicalMethodSignature> superMethodSignatures,
131 boolean includeRealPositionInfo) {
132 return checkMethodIncompatibleReturnType(methodSignature, superMethodSignatures, includeRealPositionInfo, null);
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;
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()) {
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
187 : unifyingSubstitutor.substitute(superReturnType);
190 substitutedSuperReturnType = TypeConversionUtil.erasure(superMethodSignature.getSubstitutor().substitute(superReturnType));
193 if (returnType.equals(substitutedSuperReturnType)) return null;
194 if (!(returnType instanceof PsiPrimitiveType) && substitutedSuperReturnType.getDeepComponentType() instanceof PsiClassType) {
195 if (isJdk15 && TypeConversionUtil.isAssignable(substitutedSuperReturnType, returnType)) {
200 return createIncompatibleReturnTypeMessage(method, superMethod, substitutedSuperReturnType, returnType, detailMessage, range);
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));
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;
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));
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();
261 exceptionContexts = null;
262 referenceElements = null;
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);
275 for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) {
276 PsiMethod superMethod = superMethodSignature.getMethod();
277 int index = getExtraExceptionNum(methodSignature, superMethodSignature, checkedExceptions, superSubstitutor);
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;
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));
289 if (includeRealPositionInfo) {
290 PsiElement exceptionContext = exceptionContexts.get(index);
291 textRange = exceptionContext.getTextRange();
294 textRange = TextRange.EMPTY_RANGE;
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)));
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)) {
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;
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();
343 boolean isDummy = isDummyConstructorCall(methodCall, resolveHelper, list, referenceToMethod);
344 if (isDummy) return null;
345 HighlightInfo highlightInfo;
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));
360 highlightInfo = GenericsHighlightUtil.checkInferredIntersections(substitutor, fixRange);
363 if (highlightInfo == null) {
364 highlightInfo = checkVarargParameterErasureToBeAccessible((MethodCandidateInfo)resolveResult, methodCall);
369 PsiMethod resolvedMethod = null;
370 MethodCandidateInfo candidateInfo = null;
371 if (resolveResult instanceof MethodCandidateInfo) {
372 candidateInfo = (MethodCandidateInfo)resolveResult;
373 resolvedMethod = candidateInfo.getElement();
376 if (!resolveResult.isAccessible() || !resolveResult.isStaticsScopeCorrect()) {
377 highlightInfo = null;
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);
388 if (parent instanceof PsiClass && !ApplicationManager.getApplication().isUnitTestMode()) {
389 toolTip = buildOneLineMismatchDescription(list, candidateInfo, elementToHighlight);
390 if (toolTip == null) {
391 toolTip = createMismatchedArgumentsHtmlTooltip(candidateInfo, list);
395 toolTip = description;
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);
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);
413 highlightInfo = GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, methodExpression, substitutor, javaSdkVersion);
418 String description = JavaErrorMessages.message("method.call.expected");
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));
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));
432 if (highlightInfo == null) {
433 highlightInfo = GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, referenceToMethod, substitutor,
436 return highlightInfo;
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));
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) {
468 for (int i = 0; i < expressions.length; i++) {
469 PsiExpression expression = expressions[i];
470 if (!TypeConversionUtil.areTypesAssignmentCompatible(substitutor.substitute(parameters[i].getType()), expression)) {
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());
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>");
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;
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
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;
535 methodCandidate2 = candidate;
540 MethodCandidateInfo[] candidates = toMethodCandidates(resolveResults);
542 HighlightInfoType highlightInfoType = HighlightInfoType.ERROR;
543 if (methodCandidate2 != null) {
547 PsiElement elementToHighlight;
548 if (element != null && !resolveResult.isAccessible()) {
549 description = HighlightUtil.buildProblemWithAccessDescription(referenceToMethod, resolveResult);
550 elementToHighlight = referenceToMethod.getReferenceNameElement();
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)
559 description = staticInterfaceMethodMessage != null
560 ? staticInterfaceMethodMessage
561 : HighlightUtil.buildProblemWithStaticDescription(element);
562 elementToHighlight = referenceToMethod.getReferenceNameElement();
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;
575 String toolTip = XmlStringUtil.escapeString(description);
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);
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);
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;
611 methodCandidate2 = candidate;
616 MethodCandidateInfo[] candidates = toMethodCandidates(resolveResults);
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() + ")";
640 description = JavaErrorMessages.message("ambiguous.method.call", m1, m2);
641 toolTip = createAmbiguousMethodHtmlTooltip(new MethodCandidateInfo[]{methodCandidate1, methodCandidate2});
644 if (element != null && !resolveResult.isAccessible()) {
647 if (element != null && !resolveResult.isStaticsScopeCorrect()) {
650 String methodName = referenceToMethod.getReferenceName() + buildArgTypesList(list);
651 description = JavaErrorMessages.message("cannot.resolve.method", methodName);
652 if (candidates.length == 0) {
655 toolTip = XmlStringUtil.escapeString(description);
658 HighlightInfo.newHighlightInfo(highlightInfoType).range(elementToHighlight).description(description).escapedToolTip(toolTip).create();
659 if (methodCandidate2 == null) {
660 registerMethodCallIntentions(info, methodCall, list, resolveHelper);
662 if (!resolveResult.isAccessible() && resolveResult.isStaticsScopeCorrect() && methodCandidate2 != null) {
663 HighlightUtil.registerAccessQuickFixAction((PsiMember)element, referenceToMethod, info, resolveResult.getCurrentFileResolveScope());
665 if (element != null && !resolveResult.isStaticsScopeCorrect()) {
666 HighlightUtil.registerStaticProblemQuickFixAction(element, info, referenceToMethod);
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);
679 private static MethodCandidateInfo[] toMethodCandidates(@NotNull JavaResolveResult[] resolveResults) {
680 List<MethodCandidateInfo> candidateList = new ArrayList<MethodCandidateInfo>(resolveResults.length);
682 for (JavaResolveResult result : resolveResults) {
683 if (!(result instanceof MethodCandidateInfo)) continue;
684 MethodCandidateInfo candidate = (MethodCandidateInfo)result;
685 if (candidate.isAccessible()) candidateList.add(candidate);
687 return candidateList.toArray(new MethodCandidateInfo[candidateList.size()]);
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));
716 for (IntentionAction action : QUICK_FIX_FACTORY.getVariableTypeFromCallFixes(methodCall, list)) {
717 QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, action);
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);
723 CandidateInfo[] candidates = resolveHelper.getReferencedMethodCandidates(methodCall, true);
724 ChangeStringLiteralToCharInMethodCallFix.registerFixes(candidates, methodCall, highlightInfo);
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());
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]));
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);
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>";
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>";
769 if (parameters.length == 0) {
770 ms += "<td><b>()</b></td>";
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);
784 private static String createShortMismatchedArgumentsHtmlTooltip(PsiExpressionList list,
785 PsiParameter[] parameters,
787 PsiSubstitutor substitutor,
789 PsiExpression[] expressions = list.getExpressions();
790 int cols = Math.max(parameters.length, expressions.length);
793 @NonNls String parensizedName = methodName + (parameters.length == 0 ? "( ) " : "");
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/>") : ""
805 private static String esctrim(@NotNull String s) {
806 return XmlStringUtil.escapeString(trimNicely(s));
809 private static String trimNicely(String s) {
810 if (s.length() <= 40) return s;
812 List<TextRange> wordIndices = StringUtil.getWordIndicesIn(s);
813 if (wordIndices.size() > 2) {
814 int firstWordEnd = wordIndices.get(0).getEndOffset();
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());
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());
829 return StringUtil.last(s, 40, true).toString();
832 private static String createMismatchedArgumentsHtmlTooltip(PsiExpressionList list,
833 PsiParameter[] parameters,
835 PsiSubstitutor substitutor,
837 return Math.max(parameters.length, list.getExpressions().length) <= 2
838 ? createShortMismatchedArgumentsHtmlTooltip(list, parameters, methodName, substitutor, aClass)
839 : createLongMismatchedArgumentsHtmlTooltip(list, parameters, methodName, substitutor, aClass);
842 @SuppressWarnings("StringContatenationInLoop")
844 private static String createLongMismatchedArgumentsHtmlTooltip(PsiExpressionList list,
845 PsiParameter[] parameters,
847 PsiSubstitutor substitutor,
849 PsiExpression[] expressions = list.getExpressions();
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>" +
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>"
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";
866 s += "<tr" + (i % 2 == 0 ? " style='background-color: #"
867 + (UIUtil.isUnderDarcula() ? ColorUtil.toHex(ColorUtil.shift(UIUtil.getToolTipBackground(), 1.1)) : "eeeeee")
869 s += "<td><b><nobr>";
870 if (parameter != null) {
871 String name = parameter.getName();
873 s += esctrim(name) +":";
876 s += "</nobr></b></td>";
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))
886 s += "</nobr></b></td>";
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()) + " "+
893 (mismatchColor == null || type == null || type == PsiType.NULL ? "" : "("+esctrim(JavaHighlightUtil.formatType(type))+")")
898 s += "</nobr></b></td>";
904 final String errorMessage = InferenceSession.getInferenceErrorMessage(list.getParent());
905 if (errorMessage != null) {
907 s += XmlStringUtil.escapeString(errorMessage).replaceAll("\n", "<br/>");
909 s+= "</body></html>";
913 @SuppressWarnings("StringContatenationInLoop")
915 private static String createMismatchedArgsHtmlTooltipArgumentsRow(final PsiExpression[] expressions, final PsiParameter[] parameters,
916 final PsiSubstitutor substitutor, final int cols) {
919 @NonNls String ms = "";
920 for (int i = 0; i < expressions.length; i++) {
921 PsiExpression expression = expressions[i];
922 PsiType type = expression.getType();
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))
930 + (i == expressions.length - 1 ? ")" : ",") + "</nobr></b></td>";
932 for (int i = expressions.length; i < cols + 1; i++) {
933 ms += "<td>" + (i == 0 ? "<b>()</b>" : "") +
939 @SuppressWarnings("StringContatenationInLoop")
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>";
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())
966 PsiType expressionType = expression.getType();
967 return paramType != null && expressionType != null && TypeConversionUtil.isAssignable(paramType, expressionType);
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)
977 && !aClass.isInterface()
978 && !PsiUtilCore.hasErrorElementChild(method)) {
979 int start = method.getModifierList().getTextRange().getStartOffset();
980 int end = method.getTextRange().getEndOffset();
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));
988 QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createAddMethodBodyFix(method));
994 static HighlightInfo checkAbstractMethodInConcreteClass(PsiMethod method, PsiElement elementToHighlight) {
995 HighlightInfo errorResult = null;
996 PsiClass aClass = method.getContainingClass();
997 if (method.hasModifierProperty(PsiModifier.ABSTRACT)
999 && !aClass.hasModifierProperty(PsiModifier.ABSTRACT)
1001 && !PsiUtilCore.hasErrorElementChild(method)) {
1002 String description = JavaErrorMessages.message("abstract.method.in.non.abstract.class");
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));
1009 QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createAddMethodBodyFix(method));
1010 QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createModifierListFix(aClass, PsiModifier.ABSTRACT, true, false));
1016 static HighlightInfo checkConstructorName(PsiMethod method) {
1017 String methodName = method.getName();
1018 PsiClass aClass = method.getContainingClass();
1019 HighlightInfo errorResult = null;
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));
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) {
1047 if (methodCount == 1 && aClass.isEnum() &&
1048 GenericsHighlightUtil.isEnumSyntheticMethod(methodSignature, aClass.getProject())) {
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();
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);
1072 final List<IntentionAction> additionalFixes = new ArrayList<IntentionAction>();
1073 String description = null;
1076 description = JavaErrorMessages.message("extension.method.should.have.a.body");
1077 additionalFixes.add(QUICK_FIX_FACTORY.createAddMethodBodyFix(method));
1079 else if (isInterface && isStatic && languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
1080 description = "Static methods in interfaces should have a body";
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));
1092 else if (isExtension) {
1093 description = JavaErrorMessages.message("extension.method.in.class");
1095 else if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
1096 description = JavaErrorMessages.message("abstract.methods.cannot.have.a.body");
1098 else if (method.hasModifierProperty(PsiModifier.NATIVE)) {
1099 description = JavaErrorMessages.message("native.methods.cannot.have.a.body");
1101 if (description == null) return null;
1103 TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method);
1104 HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
1106 QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createDeleteMethodBodyFix(method));
1108 if (method.hasModifierProperty(PsiModifier.ABSTRACT) && !isInterface) {
1109 QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createModifierListFix(method, PsiModifier.ABSTRACT, false, false));
1111 for (IntentionAction intentionAction : additionalFixes) {
1112 QuickFixAction.registerQuickFixAction(info, intentionAction);
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();
1126 if (prevSibling == null) return null;
1127 if (prevSibling instanceof PsiStatement) break;
1128 prevSibling = prevSibling.getPrevSibling();
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();
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();
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;
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))
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);
1171 QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createInsertSuperFix(constructor));
1172 QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createAddDefaultConstructorFix(aClass.getSuperClass()));
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
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()) {
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()) {
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;
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)) {
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";
1226 String description = JavaErrorMessages.message(messageKey,
1227 JavaHighlightUtil.formatMethod(method),
1228 HighlightUtil.formatClass(aClass),
1229 JavaHighlightUtil.formatMethod(superMethod),
1230 HighlightUtil.formatClass(superClass));
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));
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));
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;
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());
1265 MethodSignatureBackedByPsiMethod otherSuperSignature = superMethodSignatures.get(i);
1266 PsiMethod otherSuperMethod = otherSuperSignature.getMethod();
1267 PsiType otherSuperReturnType = otherSuperSignature.getSubstitutor().substitute(otherSuperMethod.getReturnType());
1269 PsiSubstitutor unifyingSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(returnTypeSubstitutable,
1270 otherSuperSignature);
1271 if (unifyingSubstitutor != null) {
1272 otherSuperReturnType = unifyingSubstitutor.substitute(otherSuperReturnType);
1273 currentType = unifyingSubstitutor.substitute(currentType);
1276 if (otherSuperReturnType == null || currentType == null || otherSuperReturnType.equals(currentType)) continue;
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;
1287 if (currentMethod.getTypeParameters().length > 0 && JavaGenericsUtil.isRawToGeneric(currentType, otherSuperReturnType)) continue;
1289 return createIncompatibleReturnTypeMessage(currentMethod, otherSuperMethod, otherSuperReturnType,
1290 currentType, JavaErrorMessages.message("unrelated.overriding.methods.return.types"),
1291 TextRange.EMPTY_RANGE);
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();
1301 for (HierarchicalMethodSignature signature : visibleSignatures) {
1302 PsiMethod method = signature.getMethod();
1303 if (!resolveHelper.isAccessible(method, aClass, null)) continue;
1304 List<HierarchicalMethodSignature> superSignatures = signature.getSuperSignatures();
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
1310 if (aClass.isInterface() && !containingClass.isInterface()) continue;
1311 HighlightInfo highlightInfo;
1313 superSignatures = new ArrayList<HierarchicalMethodSignature>(superSignatures);
1314 superSignatures.add(signature);
1315 highlightInfo = checkInterfaceInheritedMethodsReturnTypes(superSignatures, languageLevel);
1318 highlightInfo = checkMethodIncompatibleReturnType(signature, superSignatures, false);
1320 if (highlightInfo != null) description = highlightInfo.getDescription();
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()));
1337 if (description == null) {
1338 highlightInfo = checkMethodIncompatibleThrows(signature, superSignatures, false, aClass);
1339 if (highlightInfo != null) description = highlightInfo.getDescription();
1342 if (description == null) {
1343 highlightInfo = checkMethodWeakerPrivileges(signature, superSignatures, false, containingFile);
1344 if (highlightInfo != null) description = highlightInfo.getDescription();
1347 if (description != null) break;
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();
1360 static HighlightInfo checkConstructorHandleSuperClassExceptions(PsiMethod method) {
1361 if (!method.isConstructor()) {
1364 PsiCodeBlock body = method.getBody();
1365 PsiStatement[] statements = body == null ? null : body.getStatements();
1366 if (statements == null) return null;
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)));
1378 return highlightInfo;
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();
1392 public static TextRange getFixRange(@NotNull PsiElement element) {
1393 TextRange range = element.getTextRange();
1394 int start = range.getStartOffset();
1395 int end = range.getEndOffset();
1397 PsiElement nextSibling = element.getNextSibling();
1398 if (nextSibling instanceof PsiJavaToken && ((PsiJavaToken)nextSibling).getTokenType() == JavaTokenType.SEMICOLON) {
1399 return new TextRange(start, end + 1);
1405 static void checkNewExpression(@NotNull PsiNewExpression expression,
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;
1420 PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
1421 checkConstructorCall(typeResult, expression, type, classReference, holder, javaSdkVersion);
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();
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);
1452 PsiMethod[] constructors = aClass.getConstructors();
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));
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());
1479 PsiElement place = list;
1480 if (constructorCall instanceof PsiNewExpression) {
1481 final PsiAnonymousClass anonymousClass = ((PsiNewExpression)constructorCall).getAnonymousClass();
1482 if (anonymousClass != null) place = anonymousClass;
1485 JavaResolveResult[] results = resolveHelper.multiResolveConstructor((PsiClassType)type, list, place);
1486 MethodCandidateInfo result = null;
1487 if (results.length == 1) result = (MethodCandidateInfo)results[0];
1489 PsiMethod constructor = result == null ? null : result.getElement();
1491 boolean applicable = true;
1493 applicable = constructor != null && result.isApplicable();
1495 catch (IndexNotReadyException e) {
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);
1510 if (classReference != null && (!result.isAccessible() ||
1511 constructor.hasModifierProperty(PsiModifier.PROTECTED) && callingProtectedConstructorFromDerivedClass(constructorCall, aClass))) {
1512 holder.add(buildAccessProblem(classReference, result, constructor));
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);
1521 HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(infoElement).description(description).escapedToolTip(toolTip).navigationShift(+1).create();
1523 registerFixesOnInvalidConstructorCall(constructorCall, classReference, list, aClass, constructors, results, infoElement, info);
1524 registerMethodReturnFixAction(info, result, constructorCall);
1529 if (constructorCall instanceof PsiNewExpression) {
1530 PsiReferenceParameterList typeArgumentList = ((PsiNewExpression)constructorCall).getTypeArgumentList();
1531 HighlightInfo info = GenericsHighlightUtil.checkReferenceTypeArgumentList(constructor, typeArgumentList, result.getSubstitutor(), false, javaSdkVersion);
1539 if (result != null && !holder.hasErrorResults()) {
1540 holder.add(checkVarargParameterErasureToBeAccessible(result, constructorCall));
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.
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 if (method.hasTypeParameters()) {
1554 final PsiParameter[] parameters = method.getParameterList().getParameters();
1555 final PsiType componentType = ((PsiEllipsisType)parameters[parameters.length - 1].getType()).getComponentType();
1556 final PsiClass classOfComponent = PsiUtil.resolveClassInClassTypeOnly(componentType);
1557 if (classOfComponent instanceof PsiTypeParameter) {
1558 final PsiType substitutedTypeErasure = TypeConversionUtil.erasure(info.getSubstitutor().substitute(componentType));
1559 final PsiClass targetClass = PsiUtil.resolveClassInClassTypeOnly(substitutedTypeErasure);
1560 if (targetClass != null && !PsiUtil.isAccessible(targetClass, place, null)) {
1561 final PsiExpressionList argumentList = place.getArgumentList();
1562 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
1563 .descriptionAndTooltip("Formal varargs element type " +
1564 PsiFormatUtil.formatClass(targetClass, PsiFormatUtilBase.SHOW_FQ_NAME) +
1565 " is inaccessible here")
1566 .range(argumentList != null ? argumentList : place)
1575 private static void registerFixesOnInvalidConstructorCall(PsiConstructorCall constructorCall,
1576 PsiJavaCodeReferenceElement classReference,
1577 PsiExpressionList list,
1579 PsiMethod[] constructors,
1580 JavaResolveResult[] results, PsiElement infoElement, HighlightInfo info) {
1582 .registerQuickFixAction(info, constructorCall.getTextRange(), QUICK_FIX_FACTORY.createCreateConstructorFromCallFix(constructorCall));
1583 if (classReference != null) {
1584 ConstructorParametersFixer.registerFixActions(classReference, constructorCall, info, getFixRange(infoElement));
1585 ChangeTypeArgumentsFix.registerIntentions(results, list, info, aClass);
1586 ConvertDoubleToFloatFix.registerIntentions(results, list, info, null);
1588 registerChangeMethodSignatureFromUsageIntentions(results, list, info, null);
1589 PermuteArgumentsFix.registerFix(info, constructorCall, toMethodCandidates(results), getFixRange(list));
1590 registerChangeParameterClassFix(constructorCall, list, info);
1591 QuickFixAction.registerQuickFixAction(info, getFixRange(list), QUICK_FIX_FACTORY.createSurroundWithArrayFix(constructorCall,null));
1592 ChangeStringLiteralToCharInMethodCallFix.registerFixes(constructors, constructorCall, info);
1595 private static HighlightInfo buildAccessProblem(@NotNull PsiJavaCodeReferenceElement classReference, JavaResolveResult result, PsiMember elementToFix) {
1596 String description = HighlightUtil.buildProblemWithAccessDescription(classReference, result);
1597 HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(classReference).descriptionAndTooltip(
1598 description).navigationShift(+1).create();
1599 if (result.isStaticsScopeCorrect()) {
1600 HighlightUtil.registerAccessQuickFixAction(elementToFix, classReference, info, result.getCurrentFileResolveScope());
1605 private static boolean callingProtectedConstructorFromDerivedClass(PsiConstructorCall place, PsiClass constructorClass) {
1606 if (constructorClass == null) return false;
1607 // indirect instantiation via anonymous class is ok
1608 if (place instanceof PsiNewExpression && ((PsiNewExpression)place).getAnonymousClass() != null) return false;
1609 PsiElement curElement = place;
1610 PsiClass containingClass = constructorClass.getContainingClass();
1612 PsiClass aClass = PsiTreeUtil.getParentOfType(curElement, PsiClass.class);
1613 if (aClass == null) return false;
1614 curElement = aClass;
1615 if ((aClass.isInheritor(constructorClass, true) || containingClass != null && aClass.isInheritor(containingClass, true))
1616 && !JavaPsiFacade.getInstance(aClass.getProject()).arePackagesTheSame(aClass, constructorClass)) {
1622 private static String buildArgTypesList(PsiExpressionList list) {
1623 StringBuilder builder = new StringBuilder();
1624 builder.append("(");
1625 PsiExpression[] args = list.getExpressions();
1626 for (int i = 0; i < args.length; i++) {
1628 builder.append(", ");
1630 PsiType argType = args[i].getType();
1631 builder.append(argType != null ? JavaHighlightUtil.formatType(argType) : "?");
1633 builder.append(")");
1634 return builder.toString();
1637 private static void registerChangeParameterClassFix(@NotNull PsiCall methodCall,
1638 @NotNull PsiExpressionList list,
1639 HighlightInfo highlightInfo) {
1640 final JavaResolveResult result = methodCall.resolveMethodGenerics();
1641 PsiMethod method = (PsiMethod)result.getElement();
1642 final PsiSubstitutor substitutor = result.getSubstitutor();
1643 PsiExpression[] expressions = list.getExpressions();
1644 if (method == null) return;
1645 final PsiParameter[] parameters = method.getParameterList().getParameters();
1646 if (parameters.length != expressions.length) return;
1647 for (int i = 0; i < expressions.length; i++) {
1648 final PsiExpression expression = expressions[i];
1649 final PsiParameter parameter = parameters[i];
1650 final PsiType expressionType = expression.getType();
1651 final PsiType parameterType = substitutor.substitute(parameter.getType());
1652 if (expressionType == null || expressionType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(expressionType) || expressionType instanceof PsiArrayType) continue;
1653 if (parameterType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(parameterType) || parameterType instanceof PsiArrayType) continue;
1654 if (parameterType.isAssignableFrom(expressionType)) continue;
1655 PsiClass parameterClass = PsiUtil.resolveClassInType(parameterType);
1656 PsiClass expressionClass = PsiUtil.resolveClassInType(expressionType);
1657 if (parameterClass == null || expressionClass == null) continue;
1658 if (expressionClass instanceof PsiAnonymousClass) continue;
1659 if (parameterClass.isInheritor(expressionClass, true)) continue;
1660 QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createChangeParameterClassFix(expressionClass, (PsiClassType)parameterType));
1664 private static void registerChangeMethodSignatureFromUsageIntentions(@NotNull JavaResolveResult[] candidates,
1665 @NotNull PsiExpressionList list,
1666 @Nullable HighlightInfo highlightInfo,
1667 TextRange fixRange) {
1668 if (candidates.length == 0) return;
1669 PsiExpression[] expressions = list.getExpressions();
1670 for (JavaResolveResult candidate : candidates) {
1671 registerChangeMethodSignatureFromUsageIntention(expressions, highlightInfo, fixRange, candidate, list);
1675 private static void registerChangeMethodSignatureFromUsageIntention(@NotNull PsiExpression[] expressions,
1676 @Nullable HighlightInfo highlightInfo,
1678 @NotNull JavaResolveResult candidate,
1679 @NotNull PsiElement context) {
1680 if (!candidate.isStaticsScopeCorrect()) return;
1681 PsiMethod method = (PsiMethod)candidate.getElement();
1682 PsiSubstitutor substitutor = candidate.getSubstitutor();
1683 if (method != null && context.getManager().isInProject(method)) {
1684 IntentionAction fix = QUICK_FIX_FACTORY.createChangeMethodSignatureFromUsageFix(method, expressions, substitutor, context, false, 2);
1685 QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, fix);
1686 IntentionAction f2 = QUICK_FIX_FACTORY.createChangeMethodSignatureFromUsageReverseOrderFix(method, expressions, substitutor, context,
1688 QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, f2);