From cb20ba1cbb58b7f933b73ea77d85991e687216ef Mon Sep 17 00:00:00 2001 From: UNV Date: Fri, 2 May 2025 01:40:14 +0300 Subject: [PATCH 1/2] Reformatting users of EP_NAME. --- .../impl/analysis/HighlightMethodUtil.java | 4221 +++++++++-------- .../impl/analysis/HighlightVisitorImpl.java | 3816 ++++++++------- .../util/RefactoringChangeUtil.java | 243 +- 3 files changed, 4387 insertions(+), 3893 deletions(-) diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 2fa75a89d5..639e9054cf 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -73,2112 +73,2373 @@ * Date: Aug 14, 2002 */ public class HighlightMethodUtil { - private static final Logger LOG = Logger.getInstance(HighlightMethodUtil.class); - - private HighlightMethodUtil() { - } - - public static String createClashMethodMessage(PsiMethod method1, PsiMethod method2, boolean showContainingClasses) { - @NonNls String pattern = showContainingClasses ? "clash.methods.message.show.classes" : "clash.methods.message"; - return JavaErrorBundle.message(pattern, - JavaHighlightUtil.formatMethod(method1), - JavaHighlightUtil.formatMethod(method2), - HighlightUtil.formatClass(method1.getContainingClass()), - HighlightUtil.formatClass(method2.getContainingClass())); - } - - public static HighlightInfo checkMethodWeakerPrivileges(@Nonnull MethodSignatureBackedByPsiMethod methodSignature, - @Nonnull List superMethodSignatures, - boolean includeRealPositionInfo, - @Nonnull PsiFile containingFile) { - PsiMethod method = methodSignature.getMethod(); - PsiModifierList modifierList = method.getModifierList(); - if (modifierList.hasModifierProperty(PsiModifier.PUBLIC)) { - return null; - } - int accessLevel = PsiUtil.getAccessLevel(modifierList); - String accessModifier = PsiUtil.getAccessModifier(accessLevel); - for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) { - PsiMethod superMethod = superMethodSignature.getMethod(); - if (method.hasModifierProperty(PsiModifier.ABSTRACT) && !MethodSignatureUtil.isSuperMethod(superMethod, method)) { - continue; - } - if (!PsiUtil.isAccessible(containingFile.getProject(), superMethod, method, null)) { - continue; - } - if (!includeRealPositionInfo && MethodSignatureUtil.isSuperMethod(superMethod, method)) { - continue; - } - HighlightInfo info = isWeaker(method, modifierList, accessModifier, accessLevel, superMethod, includeRealPositionInfo); - if (info != null) { - return info; - } - } - return null; - } - - private static HighlightInfo isWeaker(final PsiMethod method, - final PsiModifierList modifierList, - final String accessModifier, - final int accessLevel, - final PsiMethod superMethod, - final boolean includeRealPositionInfo) { - int superAccessLevel = PsiUtil.getAccessLevel(superMethod.getModifierList()); - if (accessLevel < superAccessLevel) { - String description = JavaErrorBundle.message("weaker.privileges", - createClashMethodMessage(method, superMethod, true), - VisibilityUtil.toPresentableText(accessModifier), - PsiUtil - .getAccessModifier(superAccessLevel)); - TextRange textRange; - if (includeRealPositionInfo) { - PsiElement keyword = PsiUtil.findModifierInList(modifierList, accessModifier); - if (keyword == null) { - // in case of package-private or some crazy third-party plugin where some access modifier implied even if it's absent - textRange = method.getNameIdentifier().getTextRange(); + private static final Logger LOG = Logger.getInstance(HighlightMethodUtil.class); + + private HighlightMethodUtil() { + } + + public static String createClashMethodMessage(PsiMethod method1, PsiMethod method2, boolean showContainingClasses) { + @NonNls String pattern = showContainingClasses ? "clash.methods.message.show.classes" : "clash.methods.message"; + return JavaErrorBundle.message( + pattern, + JavaHighlightUtil.formatMethod(method1), + JavaHighlightUtil.formatMethod(method2), + HighlightUtil.formatClass(method1.getContainingClass()), + HighlightUtil.formatClass(method2.getContainingClass()) + ); + } + + public static HighlightInfo checkMethodWeakerPrivileges( + @Nonnull MethodSignatureBackedByPsiMethod methodSignature, + @Nonnull List superMethodSignatures, + boolean includeRealPositionInfo, + @Nonnull PsiFile containingFile + ) { + PsiMethod method = methodSignature.getMethod(); + PsiModifierList modifierList = method.getModifierList(); + if (modifierList.hasModifierProperty(PsiModifier.PUBLIC)) { + return null; } - else { - textRange = keyword.getTextRange(); - } - } - else { - textRange = TextRange.EMPTY_RANGE; - } - HighlightInfo highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance() - .createModifierListFix(method, - PsiUtil.getAccessModifier(superAccessLevel), - true, - false)); - return highlightInfo; - } - return null; - } - - - public static HighlightInfo checkMethodIncompatibleReturnType(@Nonnull MethodSignatureBackedByPsiMethod methodSignature, - @Nonnull List superMethodSignatures, - boolean includeRealPositionInfo) { - return checkMethodIncompatibleReturnType(methodSignature, superMethodSignatures, includeRealPositionInfo, null); - } - - public static HighlightInfo checkMethodIncompatibleReturnType(@Nonnull MethodSignatureBackedByPsiMethod methodSignature, - @Nonnull List superMethodSignatures, - boolean includeRealPositionInfo, - @Nullable TextRange textRange) { - PsiMethod method = methodSignature.getMethod(); - PsiType returnType = methodSignature.getSubstitutor().substitute(method.getReturnType()); - PsiClass aClass = method.getContainingClass(); - if (aClass == null) { - return null; - } - for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) { - PsiMethod superMethod = superMethodSignature.getMethod(); - PsiType declaredReturnType = superMethod.getReturnType(); - PsiType superReturnType = declaredReturnType; - if (superMethodSignature.isRaw()) { - superReturnType = TypeConversionUtil.erasure(declaredReturnType); - } - if (returnType == null || superReturnType == null || method == superMethod) { - continue; - } - PsiClass superClass = superMethod.getContainingClass(); - if (superClass == null) { - continue; - } - TextRange toHighlight = - textRange != null ? textRange : includeRealPositionInfo ? method.getReturnTypeElement().getTextRange() : TextRange.EMPTY_RANGE; - HighlightInfo highlightInfo = checkSuperMethodSignature(superMethod, - superMethodSignature, - superReturnType, - method, - methodSignature, - returnType, - JavaErrorBundle.message("incompatible" + - ".return.type"), - toHighlight, - PsiUtil.getLanguageLevel(aClass)); - if (highlightInfo != null) { - return highlightInfo; - } + int accessLevel = PsiUtil.getAccessLevel(modifierList); + String accessModifier = PsiUtil.getAccessModifier(accessLevel); + for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) { + PsiMethod superMethod = superMethodSignature.getMethod(); + if (method.hasModifierProperty(PsiModifier.ABSTRACT) && !MethodSignatureUtil.isSuperMethod(superMethod, method)) { + continue; + } + if (!PsiUtil.isAccessible(containingFile.getProject(), superMethod, method, null)) { + continue; + } + if (!includeRealPositionInfo && MethodSignatureUtil.isSuperMethod(superMethod, method)) { + continue; + } + HighlightInfo info = isWeaker(method, modifierList, accessModifier, accessLevel, superMethod, includeRealPositionInfo); + if (info != null) { + return info; + } + } + return null; } - return null; - } - - private static HighlightInfo checkSuperMethodSignature(@Nonnull PsiMethod superMethod, - @Nonnull MethodSignatureBackedByPsiMethod superMethodSignature, - PsiType superReturnType, - @Nonnull PsiMethod method, - @Nonnull MethodSignatureBackedByPsiMethod methodSignature, - @Nonnull PsiType returnType, - @Nonnull String detailMessage, - @Nonnull TextRange range, - @Nonnull LanguageLevel languageLevel) { - if (superReturnType == null) { - return null; - } - final PsiClass superContainingClass = superMethod.getContainingClass(); - if (superContainingClass != null && JavaClassNames.JAVA_LANG_OBJECT.equals(superContainingClass.getQualifiedName()) && !superMethod.hasModifierProperty( - PsiModifier.PUBLIC)) { - final PsiClass containingClass = method.getContainingClass(); - if (containingClass != null && containingClass.isInterface() && !superContainingClass.isInterface()) { + private static HighlightInfo isWeaker( + final PsiMethod method, + final PsiModifierList modifierList, + final String accessModifier, + final int accessLevel, + final PsiMethod superMethod, + final boolean includeRealPositionInfo + ) { + int superAccessLevel = PsiUtil.getAccessLevel(superMethod.getModifierList()); + if (accessLevel < superAccessLevel) { + String description = JavaErrorBundle.message( + "weaker.privileges", + createClashMethodMessage(method, superMethod, true), + VisibilityUtil.toPresentableText(accessModifier), + PsiUtil.getAccessModifier(superAccessLevel) + ); + TextRange textRange; + if (includeRealPositionInfo) { + PsiElement keyword = PsiUtil.findModifierInList(modifierList, accessModifier); + if (keyword == null) { + // in case of package-private or some crazy third-party plugin where some access modifier implied even if it's absent + textRange = method.getNameIdentifier().getTextRange(); + } + else { + textRange = keyword.getTextRange(); + } + } + else { + textRange = TextRange.EMPTY_RANGE; + } + HighlightInfo highlightInfo = + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + QuickFixAction.registerQuickFixAction( + highlightInfo, + QuickFixFactory.getInstance().createModifierListFix( + method, + PsiUtil.getAccessModifier(superAccessLevel), + true, + false + ) + ); + return highlightInfo; + } return null; - } } - PsiType substitutedSuperReturnType; - final boolean isJdk15 = languageLevel.isAtLeast(LanguageLevel.JDK_1_5); - if (isJdk15 && !superMethodSignature.isRaw() && superMethodSignature.equals(methodSignature)) { //see 8.4.5 - PsiSubstitutor unifyingSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, superMethodSignature); - substitutedSuperReturnType = unifyingSubstitutor == null ? superReturnType : unifyingSubstitutor.substitute(superReturnType); - } - else { - substitutedSuperReturnType = TypeConversionUtil.erasure(superMethodSignature.getSubstitutor().substitute(superReturnType)); - } - if (returnType.equals(substitutedSuperReturnType)) { - return null; + public static HighlightInfo checkMethodIncompatibleReturnType( + @Nonnull MethodSignatureBackedByPsiMethod methodSignature, + @Nonnull List superMethodSignatures, + boolean includeRealPositionInfo + ) { + return checkMethodIncompatibleReturnType(methodSignature, superMethodSignatures, includeRealPositionInfo, null); } - if (!(returnType instanceof PsiPrimitiveType) && substitutedSuperReturnType.getDeepComponentType() instanceof PsiClassType) { - if (isJdk15 && TypeConversionUtil.isAssignable(substitutedSuperReturnType, returnType)) { + + public static HighlightInfo checkMethodIncompatibleReturnType( + @Nonnull MethodSignatureBackedByPsiMethod methodSignature, + @Nonnull List superMethodSignatures, + boolean includeRealPositionInfo, + @Nullable TextRange textRange + ) { + PsiMethod method = methodSignature.getMethod(); + PsiType returnType = methodSignature.getSubstitutor().substitute(method.getReturnType()); + PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return null; + } + for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) { + PsiMethod superMethod = superMethodSignature.getMethod(); + PsiType declaredReturnType = superMethod.getReturnType(); + PsiType superReturnType = declaredReturnType; + if (superMethodSignature.isRaw()) { + superReturnType = TypeConversionUtil.erasure(declaredReturnType); + } + if (returnType == null || superReturnType == null || method == superMethod) { + continue; + } + PsiClass superClass = superMethod.getContainingClass(); + if (superClass == null) { + continue; + } + TextRange toHighlight = textRange != null ? textRange + : includeRealPositionInfo ? method.getReturnTypeElement().getTextRange() : TextRange.EMPTY_RANGE; + HighlightInfo highlightInfo = checkSuperMethodSignature( + superMethod, + superMethodSignature, + superReturnType, + method, + methodSignature, + returnType, + JavaErrorBundle.message("incompatible.return.type"), + toHighlight, + PsiUtil.getLanguageLevel(aClass) + ); + if (highlightInfo != null) { + return highlightInfo; + } + } + return null; - } } - return createIncompatibleReturnTypeMessage(method, superMethod, substitutedSuperReturnType, returnType, detailMessage, range); - } - - private static HighlightInfo createIncompatibleReturnTypeMessage(@Nonnull PsiMethod method, - @Nonnull PsiMethod superMethod, - @Nonnull PsiType substitutedSuperReturnType, - @Nonnull PsiType returnType, - @Nonnull String detailMessage, - @Nonnull TextRange textRange) { - String description = MessageFormat.format("{0}; {1}", createClashMethodMessage(method, superMethod, true), detailMessage); - HighlightInfo errorResult = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance() - .createMethodReturnFix(method, substitutedSuperReturnType, false)); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createSuperMethodReturnFix(superMethod, returnType)); - final PsiClass returnClass = PsiUtil.resolveClassInClassTypeOnly(returnType); - if (returnClass != null && substitutedSuperReturnType instanceof PsiClassType) { - QuickFixAction.registerQuickFixAction(errorResult, - QuickFixFactory.getInstance() - .createChangeParameterClassFix(returnClass, - (PsiClassType)substitutedSuperReturnType)); - } + private static HighlightInfo checkSuperMethodSignature( + @Nonnull PsiMethod superMethod, + @Nonnull MethodSignatureBackedByPsiMethod superMethodSignature, + PsiType superReturnType, + @Nonnull PsiMethod method, + @Nonnull MethodSignatureBackedByPsiMethod methodSignature, + @Nonnull PsiType returnType, + @Nonnull String detailMessage, + @Nonnull TextRange range, + @Nonnull LanguageLevel languageLevel + ) { + if (superReturnType == null) { + return null; + } + final PsiClass superContainingClass = superMethod.getContainingClass(); + if (superContainingClass != null + && JavaClassNames.JAVA_LANG_OBJECT.equals(superContainingClass.getQualifiedName()) + && !superMethod.hasModifierProperty(PsiModifier.PUBLIC)) { + final PsiClass containingClass = method.getContainingClass(); + if (containingClass != null && containingClass.isInterface() && !superContainingClass.isInterface()) { + return null; + } + } - return errorResult; - } + PsiType substitutedSuperReturnType; + final boolean isJdk15 = languageLevel.isAtLeast(LanguageLevel.JDK_1_5); + if (isJdk15 && !superMethodSignature.isRaw() && superMethodSignature.equals(methodSignature)) { //see 8.4.5 + PsiSubstitutor unifyingSubstitutor = + MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, superMethodSignature); + substitutedSuperReturnType = unifyingSubstitutor == null ? superReturnType : unifyingSubstitutor.substitute(superReturnType); + } + else { + substitutedSuperReturnType = TypeConversionUtil.erasure(superMethodSignature.getSubstitutor().substitute(superReturnType)); + } + if (returnType.equals(substitutedSuperReturnType)) { + return null; + } + if (!(returnType instanceof PsiPrimitiveType) && substitutedSuperReturnType.getDeepComponentType() instanceof PsiClassType) { + if (isJdk15 && TypeConversionUtil.isAssignable(substitutedSuperReturnType, returnType)) { + return null; + } + } - public static HighlightInfo checkMethodOverridesFinal(MethodSignatureBackedByPsiMethod methodSignature, - List superMethodSignatures) { - PsiMethod method = methodSignature.getMethod(); - for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) { - PsiMethod superMethod = superMethodSignature.getMethod(); - HighlightInfo info = checkSuperMethodIsFinal(method, superMethod); - if (info != null) { - return info; - } + return createIncompatibleReturnTypeMessage(method, superMethod, substitutedSuperReturnType, returnType, detailMessage, range); } - return null; - } - - private static HighlightInfo checkSuperMethodIsFinal(PsiMethod method, PsiMethod superMethod) { - // strange things happen when super method is from Object and method from interface - if (superMethod.hasModifierProperty(PsiModifier.FINAL)) { - String description = JavaErrorBundle.message("final.method.override", - JavaHighlightUtil.formatMethod(method), - JavaHighlightUtil.formatMethod(superMethod), - HighlightUtil.formatClass - (superMethod.getContainingClass())); - TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); - HighlightInfo errorResult = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance() - .createModifierListFix(superMethod, - PsiModifier.FINAL, - false, - true)); - return errorResult; - } - return null; - } - - public static HighlightInfo checkMethodIncompatibleThrows(MethodSignatureBackedByPsiMethod methodSignature, - List superMethodSignatures, - boolean includeRealPositionInfo, - PsiClass analyzedClass) { - PsiMethod method = methodSignature.getMethod(); - PsiClass aClass = method.getContainingClass(); - if (aClass == null) { - return null; - } - PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(aClass, analyzedClass, PsiSubstitutor.EMPTY); - PsiClassType[] exceptions = method.getThrowsList().getReferencedTypes(); - PsiJavaCodeReferenceElement[] referenceElements; - List exceptionContexts; - if (includeRealPositionInfo) { - exceptionContexts = new ArrayList<>(); - referenceElements = method.getThrowsList().getReferenceElements(); + + private static HighlightInfo createIncompatibleReturnTypeMessage( + @Nonnull PsiMethod method, + @Nonnull PsiMethod superMethod, + @Nonnull PsiType substitutedSuperReturnType, + @Nonnull PsiType returnType, + @Nonnull String detailMessage, + @Nonnull TextRange textRange + ) { + String description = MessageFormat.format("{0}; {1}", createClashMethodMessage(method, superMethod, true), detailMessage); + HighlightInfo errorResult = + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance() + .createMethodReturnFix(method, substitutedSuperReturnType, false)); + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createSuperMethodReturnFix(superMethod, returnType) + ); + final PsiClass returnClass = PsiUtil.resolveClassInClassTypeOnly(returnType); + if (returnClass != null && substitutedSuperReturnType instanceof PsiClassType) { + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createChangeParameterClassFix( + returnClass, + (PsiClassType)substitutedSuperReturnType + ) + ); + } + + return errorResult; } - else { - exceptionContexts = null; - referenceElements = null; + + public static HighlightInfo checkMethodOverridesFinal( + MethodSignatureBackedByPsiMethod methodSignature, + List superMethodSignatures + ) { + PsiMethod method = methodSignature.getMethod(); + for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) { + PsiMethod superMethod = superMethodSignature.getMethod(); + HighlightInfo info = checkSuperMethodIsFinal(method, superMethod); + if (info != null) { + return info; + } + } + return null; } - List checkedExceptions = new ArrayList<>(); - for (int i = 0; i < exceptions.length; i++) { - PsiClassType exception = exceptions[i]; - if (exception == null) { - LOG.error("throws: " + method.getThrowsList().getText() + "; method: " + method); - } - if (!ExceptionUtil.isUncheckedException(exception)) { - checkedExceptions.add(exception); - if (includeRealPositionInfo && i < referenceElements.length) { - PsiJavaCodeReferenceElement exceptionRef = referenceElements[i]; - exceptionContexts.add(exceptionRef); - } - } + + private static HighlightInfo checkSuperMethodIsFinal(PsiMethod method, PsiMethod superMethod) { + // strange things happen when super method is from Object and method from interface + if (superMethod.hasModifierProperty(PsiModifier.FINAL)) { + String description = JavaErrorBundle.message( + "final.method.override", + JavaHighlightUtil.formatMethod(method), + JavaHighlightUtil.formatMethod(superMethod), + HighlightUtil.formatClass(superMethod.getContainingClass()) + ); + TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); + HighlightInfo errorResult = + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createModifierListFix( + superMethod, + PsiModifier.FINAL, + false, + true + ) + ); + return errorResult; + } + return null; } - for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) { - PsiMethod superMethod = superMethodSignature.getMethod(); - int index = getExtraExceptionNum(methodSignature, superMethodSignature, checkedExceptions, superSubstitutor); - if (index != -1) { - if (aClass.isInterface()) { - final PsiClass superContainingClass = superMethod.getContainingClass(); - if (superContainingClass != null && !superContainingClass.isInterface()) { - continue; - } - if (superContainingClass != null && !aClass.isInheritor(superContainingClass, true)) { - continue; - } - } - PsiClassType exception = checkedExceptions.get(index); - String description = JavaErrorBundle.message("overridden.method.does.not.throw", - createClashMethodMessage(method, superMethod, true), - JavaHighlightUtil.formatType(exception)); - TextRange textRange; + + public static HighlightInfo checkMethodIncompatibleThrows( + MethodSignatureBackedByPsiMethod methodSignature, + List superMethodSignatures, + boolean includeRealPositionInfo, + PsiClass analyzedClass + ) { + PsiMethod method = methodSignature.getMethod(); + PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return null; + } + PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(aClass, analyzedClass, PsiSubstitutor.EMPTY); + PsiClassType[] exceptions = method.getThrowsList().getReferencedTypes(); + PsiJavaCodeReferenceElement[] referenceElements; + List exceptionContexts; if (includeRealPositionInfo) { - PsiElement exceptionContext = exceptionContexts.get(index); - textRange = exceptionContext.getTextRange(); + exceptionContexts = new ArrayList<>(); + referenceElements = method.getThrowsList().getReferenceElements(); } else { - textRange = TextRange.EMPTY_RANGE; + exceptionContexts = null; + referenceElements = null; } - HighlightInfo errorResult = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(errorResult, new LocalQuickFixOnPsiElementAsIntentionAdapter(QuickFixFactory.getInstance() - .createMethodThrowsFix( - method, - exception, - false, - false))); - QuickFixAction.registerQuickFixAction(errorResult, new LocalQuickFixOnPsiElementAsIntentionAdapter(QuickFixFactory.getInstance() - .createMethodThrowsFix( - superMethod, - exception, - true, - true))); - return errorResult; - } - } - return null; - } - - // return number of exception which was not declared in super method or -1 - private static int getExtraExceptionNum(final MethodSignature methodSignature, - final MethodSignatureBackedByPsiMethod superSignature, - List checkedExceptions, - PsiSubstitutor substitutorForDerivedClass) { - PsiMethod superMethod = superSignature.getMethod(); - PsiSubstitutor substitutorForMethod = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, superSignature); - for (int i = 0; i < checkedExceptions.size(); i++) { - final PsiClassType checkedEx = checkedExceptions.get(i); - final PsiType substituted = - substitutorForMethod != null ? substitutorForMethod.substitute(checkedEx) : TypeConversionUtil.erasure(checkedEx); - PsiType exception = substitutorForDerivedClass.substitute(substituted); - if (!isMethodThrows(superMethod, substitutorForMethod, exception, substitutorForDerivedClass)) { - return i; - } - } - return -1; - } - - private static boolean isMethodThrows(PsiMethod method, - @Nullable PsiSubstitutor substitutorForMethod, - PsiType exception, - PsiSubstitutor substitutorForDerivedClass) { - PsiClassType[] thrownExceptions = method.getThrowsList().getReferencedTypes(); - for (PsiClassType thrownException1 : thrownExceptions) { - PsiType thrownException = - substitutorForMethod != null ? substitutorForMethod.substitute(thrownException1) : TypeConversionUtil.erasure(thrownException1); - thrownException = substitutorForDerivedClass.substitute(thrownException); - if (TypeConversionUtil.isAssignable(thrownException, exception)) { - return true; - } - } - return false; - } - - @Nullable - public static HighlightInfo checkMethodCall(@Nonnull PsiMethodCallExpression methodCall, - @Nonnull PsiResolveHelper resolveHelper, - @Nonnull LanguageLevel languageLevel, - @Nonnull JavaSdkVersion javaSdkVersion, - @Nonnull PsiFile file) { - PsiExpressionList list = methodCall.getArgumentList(); - PsiReferenceExpression referenceToMethod = methodCall.getMethodExpression(); - JavaResolveResult[] results = referenceToMethod.multiResolve(true); - JavaResolveResult resolveResult = results.length == 1 ? results[0] : JavaResolveResult.EMPTY; - PsiElement resolved = resolveResult.getElement(); - - boolean isDummy = isDummyConstructorCall(methodCall, resolveHelper, list, referenceToMethod); - if (isDummy) { - return null; - } - HighlightInfo highlightInfo; - - final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); - if (resolved instanceof PsiMethod && resolveResult.isValidResult()) { - TextRange fixRange = getFixRange(methodCall); - highlightInfo = HighlightUtil.checkUnhandledExceptions(methodCall, fixRange); - - if (highlightInfo == null && ((PsiMethod)resolved).hasModifierProperty(PsiModifier.STATIC)) { - PsiClass containingClass = ((PsiMethod)resolved).getContainingClass(); - if (containingClass != null && containingClass.isInterface()) { - PsiReferenceExpression methodRef = methodCall.getMethodExpression(); - PsiElement element = ObjectUtil.notNull(methodRef.getReferenceNameElement(), methodRef); - highlightInfo = HighlightUtil.checkFeature(element, JavaFeature.STATIC_INTERFACE_CALLS, languageLevel, file); - if (highlightInfo == null) { - String message = - checkStaticInterfaceMethodCallQualifier(methodRef, resolveResult.getCurrentFileResolveScope(), containingClass); - if (message != null) { - highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(message).range(fixRange).create(); - } - } - } - } - - if (highlightInfo == null) { - highlightInfo = GenericsHighlightUtil.checkInferredIntersections(substitutor, fixRange); - } - - if (highlightInfo == null) { - highlightInfo = checkVarargParameterErasureToBeAccessible((MethodCandidateInfo)resolveResult, methodCall); - } - - if (highlightInfo == null) { - String errorMessage = ((MethodCandidateInfo)resolveResult).getInferenceErrorMessage(); - if (errorMessage != null) { - highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(errorMessage).range(fixRange).create(); - if (highlightInfo != null) { - registerMethodCallIntentions(highlightInfo, methodCall, list, resolveHelper); - registerMethodReturnFixAction(highlightInfo, (MethodCandidateInfo)resolveResult, methodCall); - registerTargetTypeFixesBasedOnApplicabilityInference(methodCall, - (MethodCandidateInfo)resolveResult, - (PsiMethod)resolved, - highlightInfo); - } - } - } - } - else { - PsiMethod resolvedMethod = null; - MethodCandidateInfo candidateInfo = null; - if (resolveResult instanceof MethodCandidateInfo) { - candidateInfo = (MethodCandidateInfo)resolveResult; - resolvedMethod = candidateInfo.getElement(); - } - - if (!resolveResult.isAccessible() || !resolveResult.isStaticsScopeCorrect()) { - highlightInfo = null; - } - else if (candidateInfo != null && !candidateInfo.isApplicable()) { - if (candidateInfo.isTypeArgumentsApplicable()) { - String methodName = HighlightMessageUtil.getSymbolName(resolved, substitutor); - PsiElement parent = resolved.getParent(); - String containerName = parent == null ? "" : HighlightMessageUtil.getSymbolName(parent, substitutor); - String argTypes = buildArgTypesList(list); - String description = JavaErrorBundle.message("wrong.method.arguments", methodName, containerName, argTypes); - final Ref elementToHighlight = new Ref<>(list); - String toolTip; - if (parent instanceof PsiClass) { - toolTip = buildOneLineMismatchDescription(list, candidateInfo, elementToHighlight); - if (toolTip == null) { - toolTip = createMismatchedArgumentsHtmlTooltip(candidateInfo, list); - } - } - else { - toolTip = description; - } - PsiElement element = elementToHighlight.get(); - int navigationShift = - element instanceof PsiExpressionList ? +1 : 0; // argument list starts with paren which there is no need to highlight - highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(element) - .description(description) - .escapedToolTip(toolTip) - .navigationShift(navigationShift) - .create(); - if (highlightInfo != null) { - registerMethodCallIntentions(highlightInfo, methodCall, list, resolveHelper); - registerMethodReturnFixAction(highlightInfo, candidateInfo, methodCall); - registerTargetTypeFixesBasedOnApplicabilityInference(methodCall, candidateInfo, resolvedMethod, highlightInfo); - } + List checkedExceptions = new ArrayList<>(); + for (int i = 0; i < exceptions.length; i++) { + PsiClassType exception = exceptions[i]; + if (exception == null) { + LOG.error("throws: " + method.getThrowsList().getText() + "; method: " + method); + } + if (!ExceptionUtil.isUncheckedException(exception)) { + checkedExceptions.add(exception); + if (includeRealPositionInfo && i < referenceElements.length) { + PsiJavaCodeReferenceElement exceptionRef = referenceElements[i]; + exceptionContexts.add(exceptionRef); + } + } } - else { - PsiReferenceExpression methodExpression = methodCall.getMethodExpression(); - PsiReferenceParameterList typeArgumentList = methodCall.getTypeArgumentList(); - PsiSubstitutor applicabilitySubstitutor = candidateInfo.getSubstitutor(false); - if (typeArgumentList.getTypeArguments().length == 0 && resolvedMethod.hasTypeParameters()) { - highlightInfo = GenericsHighlightUtil.checkInferredTypeArguments(resolvedMethod, methodCall, applicabilitySubstitutor); - } - else { - highlightInfo = GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, - methodExpression, - applicabilitySubstitutor, - javaSdkVersion); - } - } - } - else { - String description = JavaErrorBundle.message("method.call.expected"); - highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(methodCall).descriptionAndTooltip(description).create(); - if (resolved instanceof PsiClass) { - QuickFixAction.registerQuickFixAction(highlightInfo, - QuickFixFactory.getInstance().createInsertNewFix(methodCall, (PsiClass)resolved)); + for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) { + PsiMethod superMethod = superMethodSignature.getMethod(); + int index = getExtraExceptionNum(methodSignature, superMethodSignature, checkedExceptions, superSubstitutor); + if (index != -1) { + if (aClass.isInterface()) { + final PsiClass superContainingClass = superMethod.getContainingClass(); + if (superContainingClass != null && !superContainingClass.isInterface()) { + continue; + } + if (superContainingClass != null && !aClass.isInheritor(superContainingClass, true)) { + continue; + } + } + PsiClassType exception = checkedExceptions.get(index); + String description = JavaErrorBundle.message( + "overridden.method.does.not.throw", + createClashMethodMessage(method, superMethod, true), + JavaHighlightUtil.formatType(exception) + ); + TextRange textRange; + if (includeRealPositionInfo) { + PsiElement exceptionContext = exceptionContexts.get(index); + textRange = exceptionContext.getTextRange(); + } + else { + textRange = TextRange.EMPTY_RANGE; + } + HighlightInfo errorResult = + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + QuickFixAction.registerQuickFixAction( + errorResult, + new LocalQuickFixOnPsiElementAsIntentionAdapter( + QuickFixFactory.getInstance().createMethodThrowsFix( + method, + exception, + false, + false + ) + ) + ); + QuickFixAction.registerQuickFixAction( + errorResult, + new LocalQuickFixOnPsiElementAsIntentionAdapter( + QuickFixFactory.getInstance().createMethodThrowsFix( + superMethod, + exception, + true, + true + ) + ) + ); + return errorResult; + } } - else { - TextRange range = getFixRange(methodCall); - QuickFixAction.registerQuickFixAction(highlightInfo, range, QuickFixFactory.getInstance() - .createCreateMethodFromUsageFix(methodCall)); - QuickFixAction.registerQuickFixAction(highlightInfo, range, QuickFixFactory.getInstance() - .createCreateAbstractMethodFromUsageFix(methodCall)); - QuickFixAction.registerQuickFixAction(highlightInfo, range, QuickFixFactory.getInstance() - .createCreatePropertyFromUsageFix(methodCall)); - QuickFixAction.registerQuickFixAction(highlightInfo, - range, - QuickFixFactory.getInstance().createStaticImportMethodFix(methodCall)); - if (resolved instanceof PsiVariable && languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { - PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(((PsiVariable)resolved).getType()); - if (method != null) { - QuickFixAction.registerQuickFixAction(highlightInfo, range, QuickFixFactory.getInstance() - .createInsertMethodCallFix(methodCall, method)); - } - } - } - } - } - if (highlightInfo == null) { - highlightInfo = - GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, referenceToMethod, substitutor, javaSdkVersion); - } - return highlightInfo; - } - - private static void registerTargetTypeFixesBasedOnApplicabilityInference(@Nonnull PsiMethodCallExpression methodCall, - MethodCandidateInfo resolveResult, - PsiMethod resolved, - HighlightInfo highlightInfo) { - PsiElement parent = PsiUtil.skipParenthesizedExprUp(methodCall.getParent()); - PsiVariable variable = null; - if (parent instanceof PsiVariable) { - variable = (PsiVariable)parent; - } - else if (parent instanceof PsiAssignmentExpression) { - PsiExpression lExpression = ((PsiAssignmentExpression)parent).getLExpression(); - if (lExpression instanceof PsiReferenceExpression) { - PsiElement resolve = ((PsiReferenceExpression)lExpression).resolve(); - if (resolve instanceof PsiVariable) { - variable = (PsiVariable)resolve; - } - } + return null; } - if (variable != null) { - PsiType rType = methodCall.getType(); - if (rType != null && !variable.getType().isAssignableFrom(rType)) { - PsiType expectedTypeByApplicabilityConstraints = resolveResult.getSubstitutor(false).substitute(resolved.getReturnType()); - if (expectedTypeByApplicabilityConstraints != null && !expectedTypeByApplicabilityConstraints.equals(rType)) { - HighlightUtil.registerChangeVariableTypeFixes(variable, expectedTypeByApplicabilityConstraints, methodCall, highlightInfo); + // return number of exception which was not declared in super method or -1 + private static int getExtraExceptionNum( + final MethodSignature methodSignature, + final MethodSignatureBackedByPsiMethod superSignature, + List checkedExceptions, + PsiSubstitutor substitutorForDerivedClass + ) { + PsiMethod superMethod = superSignature.getMethod(); + PsiSubstitutor substitutorForMethod = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, superSignature); + for (int i = 0; i < checkedExceptions.size(); i++) { + final PsiClassType checkedEx = checkedExceptions.get(i); + final PsiType substituted = + substitutorForMethod != null ? substitutorForMethod.substitute(checkedEx) : TypeConversionUtil.erasure(checkedEx); + PsiType exception = substitutorForDerivedClass.substitute(substituted); + if (!isMethodThrows(superMethod, substitutorForMethod, exception, substitutorForDerivedClass)) { + return i; + } } - } - } - } - - /* see also PsiReferenceExpressionImpl.hasValidQualifier() */ - @Nullable - private static String checkStaticInterfaceMethodCallQualifier(PsiReferenceExpression ref, PsiElement scope, PsiClass containingClass) { - PsiExpression qualifierExpression = ref.getQualifierExpression(); - if (qualifierExpression == null && (scope instanceof PsiImportStaticStatement || PsiTreeUtil.isAncestor(containingClass, ref, true))) { - return null; + return -1; + } + + private static boolean isMethodThrows( + PsiMethod method, + @Nullable PsiSubstitutor substitutorForMethod, + PsiType exception, + PsiSubstitutor substitutorForDerivedClass + ) { + PsiClassType[] thrownExceptions = method.getThrowsList().getReferencedTypes(); + for (PsiClassType thrownException1 : thrownExceptions) { + PsiType thrownException = substitutorForMethod != null + ? substitutorForMethod.substitute(thrownException1) + : TypeConversionUtil.erasure(thrownException1); + thrownException = substitutorForDerivedClass.substitute(thrownException); + if (TypeConversionUtil.isAssignable(thrownException, exception)) { + return true; + } + } + return false; } - if (qualifierExpression instanceof PsiReferenceExpression) { - PsiElement resolve = ((PsiReferenceExpression)qualifierExpression).resolve(); - if (resolve == containingClass) { - return null; - } + @Nullable + public static HighlightInfo checkMethodCall( + @Nonnull PsiMethodCallExpression methodCall, + @Nonnull PsiResolveHelper resolveHelper, + @Nonnull LanguageLevel languageLevel, + @Nonnull JavaSdkVersion javaSdkVersion, + @Nonnull PsiFile file + ) { + PsiExpressionList list = methodCall.getArgumentList(); + PsiReferenceExpression referenceToMethod = methodCall.getMethodExpression(); + JavaResolveResult[] results = referenceToMethod.multiResolve(true); + JavaResolveResult resolveResult = results.length == 1 ? results[0] : JavaResolveResult.EMPTY; + PsiElement resolved = resolveResult.getElement(); + + boolean isDummy = isDummyConstructorCall(methodCall, resolveHelper, list, referenceToMethod); + if (isDummy) { + return null; + } + HighlightInfo highlightInfo; + + final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); + if (resolved instanceof PsiMethod && resolveResult.isValidResult()) { + TextRange fixRange = getFixRange(methodCall); + highlightInfo = HighlightUtil.checkUnhandledExceptions(methodCall, fixRange); + + if (highlightInfo == null && ((PsiMethod)resolved).hasModifierProperty(PsiModifier.STATIC)) { + PsiClass containingClass = ((PsiMethod)resolved).getContainingClass(); + if (containingClass != null && containingClass.isInterface()) { + PsiReferenceExpression methodRef = methodCall.getMethodExpression(); + PsiElement element = ObjectUtil.notNull(methodRef.getReferenceNameElement(), methodRef); + highlightInfo = HighlightUtil.checkFeature(element, JavaFeature.STATIC_INTERFACE_CALLS, languageLevel, file); + if (highlightInfo == null) { + String message = + checkStaticInterfaceMethodCallQualifier(methodRef, resolveResult.getCurrentFileResolveScope(), containingClass); + if (message != null) { + highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .descriptionAndTooltip(message) + .range(fixRange) + .create(); + } + } + } + } + + if (highlightInfo == null) { + highlightInfo = GenericsHighlightUtil.checkInferredIntersections(substitutor, fixRange); + } - if (resolve instanceof PsiTypeParameter) { - Set classes = new HashSet<>(); - for (PsiClassType type : ((PsiTypeParameter)resolve).getExtendsListTypes()) { - PsiClass aClass = type.resolve(); - if (aClass != null) { - classes.add(aClass); - } + if (highlightInfo == null) { + highlightInfo = checkVarargParameterErasureToBeAccessible((MethodCandidateInfo)resolveResult, methodCall); + } + + if (highlightInfo == null) { + String errorMessage = ((MethodCandidateInfo)resolveResult).getInferenceErrorMessage(); + if (errorMessage != null) { + highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .descriptionAndTooltip(errorMessage) + .range(fixRange) + .create(); + if (highlightInfo != null) { + registerMethodCallIntentions(highlightInfo, methodCall, list, resolveHelper); + registerMethodReturnFixAction(highlightInfo, (MethodCandidateInfo)resolveResult, methodCall); + registerTargetTypeFixesBasedOnApplicabilityInference( + methodCall, + (MethodCandidateInfo)resolveResult, + (PsiMethod)resolved, + highlightInfo + ); + } + } + } } + else { + PsiMethod resolvedMethod = null; + MethodCandidateInfo candidateInfo = null; + if (resolveResult instanceof MethodCandidateInfo) { + candidateInfo = (MethodCandidateInfo)resolveResult; + resolvedMethod = candidateInfo.getElement(); + } - if (classes.size() == 1 && classes.contains(containingClass)) { - return null; + if (!resolveResult.isAccessible() || !resolveResult.isStaticsScopeCorrect()) { + highlightInfo = null; + } + else if (candidateInfo != null && !candidateInfo.isApplicable()) { + if (candidateInfo.isTypeArgumentsApplicable()) { + String methodName = HighlightMessageUtil.getSymbolName(resolved, substitutor); + PsiElement parent = resolved.getParent(); + String containerName = parent == null ? "" : HighlightMessageUtil.getSymbolName(parent, substitutor); + String argTypes = buildArgTypesList(list); + String description = JavaErrorBundle.message("wrong.method.arguments", methodName, containerName, argTypes); + final Ref elementToHighlight = new Ref<>(list); + String toolTip; + if (parent instanceof PsiClass) { + toolTip = buildOneLineMismatchDescription(list, candidateInfo, elementToHighlight); + if (toolTip == null) { + toolTip = createMismatchedArgumentsHtmlTooltip(candidateInfo, list); + } + } + else { + toolTip = description; + } + PsiElement element = elementToHighlight.get(); + int navigationShift = + element instanceof PsiExpressionList ? +1 : 0; // argument list starts with paren which there is no need to highlight + highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(element) + .description(description) + .escapedToolTip(toolTip) + .navigationShift(navigationShift) + .create(); + if (highlightInfo != null) { + registerMethodCallIntentions(highlightInfo, methodCall, list, resolveHelper); + registerMethodReturnFixAction(highlightInfo, candidateInfo, methodCall); + registerTargetTypeFixesBasedOnApplicabilityInference(methodCall, candidateInfo, resolvedMethod, highlightInfo); + } + } + else { + PsiReferenceExpression methodExpression = methodCall.getMethodExpression(); + PsiReferenceParameterList typeArgumentList = methodCall.getTypeArgumentList(); + PsiSubstitutor applicabilitySubstitutor = candidateInfo.getSubstitutor(false); + if (typeArgumentList.getTypeArguments().length == 0 && resolvedMethod.hasTypeParameters()) { + highlightInfo = + GenericsHighlightUtil.checkInferredTypeArguments(resolvedMethod, methodCall, applicabilitySubstitutor); + } + else { + highlightInfo = GenericsHighlightUtil.checkParameterizedReferenceTypeArguments( + resolved, + methodExpression, + applicabilitySubstitutor, + javaSdkVersion + ); + } + } + } + else { + String description = JavaErrorBundle.message("method.call.expected"); + highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(methodCall) + .descriptionAndTooltip(description) + .create(); + if (resolved instanceof PsiClass) { + QuickFixAction.registerQuickFixAction( + highlightInfo, + QuickFixFactory.getInstance().createInsertNewFix(methodCall, (PsiClass)resolved) + ); + } + else { + TextRange range = getFixRange(methodCall); + QuickFixAction.registerQuickFixAction(highlightInfo, range, QuickFixFactory.getInstance() + .createCreateMethodFromUsageFix(methodCall)); + QuickFixAction.registerQuickFixAction(highlightInfo, range, QuickFixFactory.getInstance() + .createCreateAbstractMethodFromUsageFix(methodCall)); + QuickFixAction.registerQuickFixAction(highlightInfo, range, QuickFixFactory.getInstance() + .createCreatePropertyFromUsageFix(methodCall)); + QuickFixAction.registerQuickFixAction( + highlightInfo, + range, + QuickFixFactory.getInstance().createStaticImportMethodFix(methodCall) + ); + if (resolved instanceof PsiVariable && languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { + PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(((PsiVariable)resolved).getType()); + if (method != null) { + QuickFixAction.registerQuickFixAction(highlightInfo, range, QuickFixFactory.getInstance() + .createInsertMethodCallFix(methodCall, method)); + } + } + } + } + } + if (highlightInfo == null) { + highlightInfo = + GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, referenceToMethod, substitutor, javaSdkVersion); } - } + return highlightInfo; } - return JavaErrorBundle.message("static.interface.method.call.qualifier"); - } - - private static void registerMethodReturnFixAction(HighlightInfo highlightInfo, MethodCandidateInfo candidate, PsiCall methodCall) { - if (methodCall.getParent() instanceof PsiReturnStatement) { - final PsiMethod containerMethod = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class, true, PsiLambdaExpression.class); - if (containerMethod != null) { - final PsiMethod method = candidate.getElement(); - final PsiExpression methodCallCopy = - JavaPsiFacade.getElementFactory(method.getProject()).createExpressionFromText(methodCall.getText(), methodCall); - PsiType methodCallTypeByArgs = methodCallCopy.getType(); - //ensure type params are not included - methodCallTypeByArgs = - JavaPsiFacade.getElementFactory(method.getProject()).createRawSubstitutor(method).substitute(methodCallTypeByArgs); - if (methodCallTypeByArgs != null) { - QuickFixAction.registerQuickFixAction(highlightInfo, getFixRange(methodCall), QuickFixFactory.getInstance() - .createMethodReturnFix( - containerMethod, - methodCallTypeByArgs, - true)); - } - } - } - } - - private static String buildOneLineMismatchDescription(@Nonnull PsiExpressionList list, - @Nonnull MethodCandidateInfo candidateInfo, - @Nonnull Ref elementToHighlight) { - final PsiExpression[] expressions = list.getExpressions(); - final PsiMethod resolvedMethod = candidateInfo.getElement(); - final PsiSubstitutor substitutor = candidateInfo.getSubstitutor(); - final PsiParameter[] parameters = resolvedMethod.getParameterList().getParameters(); - if (expressions.length == parameters.length && parameters.length > 1) { - int idx = -1; - for (int i = 0; i < expressions.length; i++) { - PsiExpression expression = expressions[i]; - if (expression instanceof PsiMethodCallExpression) { - final JavaResolveResult result = ((PsiCallExpression)expression).resolveMethodGenerics(); - if (result instanceof MethodCandidateInfo && PsiUtil.isLanguageLevel8OrHigher(list) && ((MethodCandidateInfo)result).isToInferApplicability() && ((MethodCandidateInfo)result) - .getInferenceErrorMessage() == null) { - continue; - } - } - if (!TypeConversionUtil.areTypesAssignmentCompatible(substitutor.substitute(parameters[i].getType()), expression)) { - if (idx != -1) { - idx = -1; - break; - } - else { - idx = i; - } - } - } - - if (idx > -1) { - final PsiExpression wrongArg = expressions[idx]; - final PsiType argType = wrongArg.getType(); - if (argType != null) { - elementToHighlight.set(wrongArg); - final String message = JavaErrorBundle.message("incompatible.call.types", - idx + 1, - substitutor.substitute(parameters[idx].getType()).getCanonicalText(), - argType - .getCanonicalText()); - - return XmlStringUtil.wrapInHtml("" + XmlStringUtil.escapeString(message) + " " + DaemonBundle.message( - "inspection.extended.description") + ""); - } - } - } - return null; - } - - public static boolean isDummyConstructorCall(PsiMethodCallExpression methodCall, - PsiResolveHelper resolveHelper, - PsiExpressionList list, - PsiReferenceExpression referenceToMethod) { - boolean isDummy = false; - boolean isThisOrSuper = referenceToMethod.getReferenceNameElement() instanceof PsiKeyword; - if (isThisOrSuper) { - // super(..) or this(..) - if (list.getExpressions().length == 0) { // implicit ctr call - CandidateInfo[] candidates = resolveHelper.getReferencedMethodCandidates(methodCall, true); - if (candidates.length == 1 && !candidates[0].getElement().isPhysical()) { - isDummy = true;// dummy constructor + private static void registerTargetTypeFixesBasedOnApplicabilityInference( + @Nonnull PsiMethodCallExpression methodCall, + MethodCandidateInfo resolveResult, + PsiMethod resolved, + HighlightInfo highlightInfo + ) { + PsiElement parent = PsiUtil.skipParenthesizedExprUp(methodCall.getParent()); + PsiVariable variable = null; + if (parent instanceof PsiVariable) { + variable = (PsiVariable)parent; } - } - } - return isDummy; - } - - @Nullable - public static HighlightInfo checkAmbiguousMethodCallIdentifier(@Nonnull PsiReferenceExpression referenceToMethod, - @Nonnull JavaResolveResult[] resolveResults, - @Nonnull PsiExpressionList list, - final PsiElement element, - @Nonnull JavaResolveResult resolveResult, - @Nonnull PsiMethodCallExpression methodCall, - @Nonnull PsiResolveHelper resolveHelper, - @Nonnull LanguageLevel languageLevel, - @Nonnull PsiFile file) { - MethodCandidateInfo methodCandidate1 = null; - MethodCandidateInfo methodCandidate2 = null; - for (JavaResolveResult result : resolveResults) { - if (!(result instanceof MethodCandidateInfo)) { - continue; - } - MethodCandidateInfo candidate = (MethodCandidateInfo)result; - if (candidate.isApplicable() && !candidate.getElement().isConstructor()) { - if (methodCandidate1 == null) { - methodCandidate1 = candidate; + else if (parent instanceof PsiAssignmentExpression) { + PsiExpression lExpression = ((PsiAssignmentExpression)parent).getLExpression(); + if (lExpression instanceof PsiReferenceExpression) { + PsiElement resolve = ((PsiReferenceExpression)lExpression).resolve(); + if (resolve instanceof PsiVariable) { + variable = (PsiVariable)resolve; + } + } } - else { - methodCandidate2 = candidate; - break; + + if (variable != null) { + PsiType rType = methodCall.getType(); + if (rType != null && !variable.getType().isAssignableFrom(rType)) { + PsiType expectedTypeByApplicabilityConstraints = resolveResult.getSubstitutor(false).substitute(resolved.getReturnType()); + if (expectedTypeByApplicabilityConstraints != null && !expectedTypeByApplicabilityConstraints.equals(rType)) { + HighlightUtil.registerChangeVariableTypeFixes( + variable, + expectedTypeByApplicabilityConstraints, + methodCall, + highlightInfo + ); + } + } } - } } - MethodCandidateInfo[] candidates = toMethodCandidates(resolveResults); - HighlightInfoType highlightInfoType = HighlightInfoType.ERROR; - if (methodCandidate2 != null) { - return null; - } - String description; - PsiElement elementToHighlight = ObjectUtil.notNull(referenceToMethod.getReferenceNameElement(), referenceToMethod); - if (element != null && !resolveResult.isAccessible()) { - description = HighlightUtil.buildProblemWithAccessDescription(referenceToMethod, resolveResult); - } - else if (element != null && !resolveResult.isStaticsScopeCorrect()) { - if (element instanceof PsiMethod && ((PsiMethod)element).hasModifierProperty(PsiModifier.STATIC)) { - PsiClass containingClass = ((PsiMethod)element).getContainingClass(); - if (containingClass != null && containingClass.isInterface()) { - HighlightInfo info = - HighlightUtil.checkFeature(elementToHighlight, JavaFeature.STATIC_INTERFACE_CALLS, languageLevel, file); - if (info != null) { - return info; - } - description = - checkStaticInterfaceMethodCallQualifier(referenceToMethod, resolveResult.getCurrentFileResolveScope(), containingClass); - if (description != null) { - HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(highlightInfoType) - .range(elementToHighlight) - .description(description) - .escapedToolTip(XmlStringUtil.escapeString - (description)) - .create(); - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance() - .createAccessStaticViaInstanceFix(referenceToMethod, - resolveResult)); - return highlightInfo; - } + /* see also PsiReferenceExpressionImpl.hasValidQualifier() */ + @Nullable + private static String checkStaticInterfaceMethodCallQualifier(PsiReferenceExpression ref, PsiElement scope, PsiClass containingClass) { + PsiExpression qualifierExpression = ref.getQualifierExpression(); + if (qualifierExpression == null && (scope instanceof PsiImportStaticStatement + || PsiTreeUtil.isAncestor(containingClass, ref, true))) { + return null; + } + + if (qualifierExpression instanceof PsiReferenceExpression) { + PsiElement resolve = ((PsiReferenceExpression)qualifierExpression).resolve(); + if (resolve == containingClass) { + return null; + } + + if (resolve instanceof PsiTypeParameter) { + Set classes = new HashSet<>(); + for (PsiClassType type : ((PsiTypeParameter)resolve).getExtendsListTypes()) { + PsiClass aClass = type.resolve(); + if (aClass != null) { + classes.add(aClass); + } + } + + if (classes.size() == 1 && classes.contains(containingClass)) { + return null; + } + } } - } - description = HighlightUtil.buildProblemWithStaticDescription(element); + return JavaErrorBundle.message("static.interface.method.call.qualifier"); + } + + private static void registerMethodReturnFixAction(HighlightInfo highlightInfo, MethodCandidateInfo candidate, PsiCall methodCall) { + if (methodCall.getParent() instanceof PsiReturnStatement) { + final PsiMethod containerMethod = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class, true, PsiLambdaExpression.class); + if (containerMethod != null) { + final PsiMethod method = candidate.getElement(); + final PsiExpression methodCallCopy = + JavaPsiFacade.getElementFactory(method.getProject()).createExpressionFromText(methodCall.getText(), methodCall); + PsiType methodCallTypeByArgs = methodCallCopy.getType(); + //ensure type params are not included + methodCallTypeByArgs = JavaPsiFacade.getElementFactory(method.getProject()) + .createRawSubstitutor(method) + .substitute(methodCallTypeByArgs); + if (methodCallTypeByArgs != null) { + QuickFixAction.registerQuickFixAction( + highlightInfo, + getFixRange(methodCall), + QuickFixFactory.getInstance().createMethodReturnFix( + containerMethod, + methodCallTypeByArgs, + true + ) + ); + } + } + } } - else { - String methodName = referenceToMethod.getReferenceName() + buildArgTypesList(list); - description = JavaErrorBundle.message("cannot.resolve.method", methodName); - if (candidates.length == 0) { - highlightInfoType = HighlightInfoType.WRONG_REF; - } - else { + + private static String buildOneLineMismatchDescription( + @Nonnull PsiExpressionList list, + @Nonnull MethodCandidateInfo candidateInfo, + @Nonnull Ref elementToHighlight + ) { + final PsiExpression[] expressions = list.getExpressions(); + final PsiMethod resolvedMethod = candidateInfo.getElement(); + final PsiSubstitutor substitutor = candidateInfo.getSubstitutor(); + final PsiParameter[] parameters = resolvedMethod.getParameterList().getParameters(); + if (expressions.length == parameters.length && parameters.length > 1) { + int idx = -1; + for (int i = 0; i < expressions.length; i++) { + PsiExpression expression = expressions[i]; + if (expression instanceof PsiMethodCallExpression) { + final JavaResolveResult result = ((PsiCallExpression)expression).resolveMethodGenerics(); + if (result instanceof MethodCandidateInfo + && PsiUtil.isLanguageLevel8OrHigher(list) + && ((MethodCandidateInfo)result).isToInferApplicability() + && ((MethodCandidateInfo)result).getInferenceErrorMessage() == null) { + continue; + } + } + if (!TypeConversionUtil.areTypesAssignmentCompatible(substitutor.substitute(parameters[i].getType()), expression)) { + if (idx != -1) { + idx = -1; + break; + } + else { + idx = i; + } + } + } + + if (idx > -1) { + final PsiExpression wrongArg = expressions[idx]; + final PsiType argType = wrongArg.getType(); + if (argType != null) { + elementToHighlight.set(wrongArg); + final String message = JavaErrorBundle.message( + "incompatible.call.types", + idx + 1, + substitutor.substitute(parameters[idx].getType()).getCanonicalText(), + argType.getCanonicalText() + ); + + return XmlStringUtil.wrapInHtml("" + XmlStringUtil.escapeString(message) + " " + DaemonBundle.message( + "inspection.extended.description") + ""); + } + } + } return null; - } } - String toolTip = XmlStringUtil.escapeString(description); - HighlightInfo info = - HighlightInfo.newHighlightInfo(highlightInfoType).range(elementToHighlight).description(description).escapedToolTip(toolTip).create(); - registerMethodCallIntentions(info, methodCall, list, resolveHelper); - if (element != null && !resolveResult.isStaticsScopeCorrect()) { - HighlightUtil.registerStaticProblemQuickFixAction(element, info, referenceToMethod); - } + public static boolean isDummyConstructorCall( + PsiMethodCallExpression methodCall, + PsiResolveHelper resolveHelper, + PsiExpressionList list, + PsiReferenceExpression referenceToMethod + ) { + boolean isDummy = false; + boolean isThisOrSuper = referenceToMethod.getReferenceNameElement() instanceof PsiKeyword; + if (isThisOrSuper) { + // super(..) or this(..) + if (list.getExpressions().length == 0) { // implicit ctr call + CandidateInfo[] candidates = resolveHelper.getReferencedMethodCandidates(methodCall, true); + if (candidates.length == 1 && !candidates[0].getElement().isPhysical()) { + isDummy = true;// dummy constructor + } + } + } + return isDummy; + } + + @Nullable + public static HighlightInfo checkAmbiguousMethodCallIdentifier( + @Nonnull PsiReferenceExpression referenceToMethod, + @Nonnull JavaResolveResult[] resolveResults, + @Nonnull PsiExpressionList list, + final PsiElement element, + @Nonnull JavaResolveResult resolveResult, + @Nonnull PsiMethodCallExpression methodCall, + @Nonnull PsiResolveHelper resolveHelper, + @Nonnull LanguageLevel languageLevel, + @Nonnull PsiFile file + ) { + MethodCandidateInfo methodCandidate1 = null; + MethodCandidateInfo methodCandidate2 = null; + for (JavaResolveResult result : resolveResults) { + if (!(result instanceof MethodCandidateInfo)) { + continue; + } + MethodCandidateInfo candidate = (MethodCandidateInfo)result; + if (candidate.isApplicable() && !candidate.getElement().isConstructor()) { + if (methodCandidate1 == null) { + methodCandidate1 = candidate; + } + else { + methodCandidate2 = candidate; + break; + } + } + } + MethodCandidateInfo[] candidates = toMethodCandidates(resolveResults); - TextRange fixRange = getFixRange(elementToHighlight); - CastMethodArgumentFix.REGISTRAR.registerCastActions(candidates, methodCall, info, fixRange); - WrapArrayToArraysAsListFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); - WrapLongWithMathToIntExactFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); - WrapObjectWithOptionalOfNullableFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); - WrapLongWithMathToIntExactFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); - PermuteArgumentsFix.registerFix(info, methodCall, candidates, fixRange); - WrapExpressionFix.registerWrapAction(candidates, list.getExpressions(), info); - registerChangeParameterClassFix(methodCall, list, info); - if (candidates.length == 0 && info != null) { - UnresolvedReferenceQuickFixProvider.registerReferenceFixes(methodCall.getMethodExpression(), QuickFixActionRegistrar.create(info)); - } - return info; - } - - @Nullable - public static HighlightInfo checkAmbiguousMethodCallArguments(@Nonnull PsiReferenceExpression referenceToMethod, - @Nonnull JavaResolveResult[] resolveResults, - @Nonnull PsiExpressionList list, - final PsiElement element, - @Nonnull JavaResolveResult resolveResult, - @Nonnull PsiMethodCallExpression methodCall, - @Nonnull PsiResolveHelper resolveHelper, - @Nonnull PsiElement elementToHighlight) { - MethodCandidateInfo methodCandidate1 = null; - MethodCandidateInfo methodCandidate2 = null; - for (JavaResolveResult result : resolveResults) { - if (!(result instanceof MethodCandidateInfo)) { - continue; - } - MethodCandidateInfo candidate = (MethodCandidateInfo)result; - if (candidate.isApplicable() && !candidate.getElement().isConstructor()) { - if (methodCandidate1 == null) { - methodCandidate1 = candidate; + HighlightInfoType highlightInfoType = HighlightInfoType.ERROR; + if (methodCandidate2 != null) { + return null; + } + String description; + PsiElement elementToHighlight = ObjectUtil.notNull(referenceToMethod.getReferenceNameElement(), referenceToMethod); + if (element != null && !resolveResult.isAccessible()) { + description = HighlightUtil.buildProblemWithAccessDescription(referenceToMethod, resolveResult); + } + else if (element != null && !resolveResult.isStaticsScopeCorrect()) { + if (element instanceof PsiMethod && ((PsiMethod)element).hasModifierProperty(PsiModifier.STATIC)) { + PsiClass containingClass = ((PsiMethod)element).getContainingClass(); + if (containingClass != null && containingClass.isInterface()) { + HighlightInfo info = + HighlightUtil.checkFeature(elementToHighlight, JavaFeature.STATIC_INTERFACE_CALLS, languageLevel, file); + if (info != null) { + return info; + } + description = checkStaticInterfaceMethodCallQualifier( + referenceToMethod, + resolveResult.getCurrentFileResolveScope(), + containingClass + ); + if (description != null) { + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(highlightInfoType) + .range(elementToHighlight) + .description(description) + .escapedToolTip(XmlStringUtil.escapeString(description)) + .create(); + QuickFixAction.registerQuickFixAction( + highlightInfo, + QuickFixFactory.getInstance().createAccessStaticViaInstanceFix( + referenceToMethod, + resolveResult + ) + ); + return highlightInfo; + } + } + } + + description = HighlightUtil.buildProblemWithStaticDescription(element); } else { - methodCandidate2 = candidate; - break; + String methodName = referenceToMethod.getReferenceName() + buildArgTypesList(list); + description = JavaErrorBundle.message("cannot.resolve.method", methodName); + if (candidates.length == 0) { + highlightInfoType = HighlightInfoType.WRONG_REF; + } + else { + return null; + } } - } - } - MethodCandidateInfo[] candidates = toMethodCandidates(resolveResults); - - String description; - String toolTip; - HighlightInfoType highlightInfoType = HighlightInfoType.ERROR; - if (methodCandidate2 != null) { - PsiMethod element1 = methodCandidate1.getElement(); - String m1 = PsiFormatUtil.formatMethod(element1, - methodCandidate1.getSubstitutor(false), - PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase - .SHOW_PARAMETERS, - PsiFormatUtilBase.SHOW_TYPE); - PsiMethod element2 = methodCandidate2.getElement(); - String m2 = PsiFormatUtil.formatMethod(element2, - methodCandidate2.getSubstitutor(false), - PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase - .SHOW_PARAMETERS, - PsiFormatUtilBase.SHOW_TYPE); - VirtualFile virtualFile1 = PsiUtilCore.getVirtualFile(element1); - VirtualFile virtualFile2 = PsiUtilCore.getVirtualFile(element2); - if (!Comparing.equal(virtualFile1, virtualFile2)) { - if (virtualFile1 != null) { - m1 += " (In " + virtualFile1.getPresentableUrl() + ")"; - } - if (virtualFile2 != null) { - m2 += " (In " + virtualFile2.getPresentableUrl() + ")"; - } - } - description = JavaErrorBundle.message("ambiguous.method.call", m1, m2); - toolTip = createAmbiguousMethodHtmlTooltip(new MethodCandidateInfo[]{ - methodCandidate1, - methodCandidate2 - }); - } - else { - if (element != null && !resolveResult.isAccessible()) { - return null; - } - if (element != null && !resolveResult.isStaticsScopeCorrect()) { - return null; - } - String methodName = referenceToMethod.getReferenceName() + buildArgTypesList(list); - description = JavaErrorBundle.message("cannot.resolve.method", methodName); - if (candidates.length == 0) { - return null; - } - toolTip = XmlStringUtil.escapeString(description); - } - HighlightInfo info = - HighlightInfo.newHighlightInfo(highlightInfoType).range(elementToHighlight).description(description).escapedToolTip(toolTip).create(); - if (methodCandidate2 == null) { - registerMethodCallIntentions(info, methodCall, list, resolveHelper); - } - if (!resolveResult.isAccessible() && resolveResult.isStaticsScopeCorrect() && methodCandidate2 != null) { - HighlightUtil.registerAccessQuickFixAction((PsiMember)element, referenceToMethod, info, resolveResult.getCurrentFileResolveScope()); - } - if (element != null && !resolveResult.isStaticsScopeCorrect()) { - HighlightUtil.registerStaticProblemQuickFixAction(element, info, referenceToMethod); - } - TextRange fixRange = getFixRange(elementToHighlight); - CastMethodArgumentFix.REGISTRAR.registerCastActions(candidates, methodCall, info, fixRange); - WrapArrayToArraysAsListFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); - WrapLongWithMathToIntExactFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); - WrapObjectWithOptionalOfNullableFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); - WrapStringWithFileFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); - PermuteArgumentsFix.registerFix(info, methodCall, candidates, fixRange); - WrapExpressionFix.registerWrapAction(candidates, list.getExpressions(), info); - registerChangeParameterClassFix(methodCall, list, info); - return info; - } - - @Nonnull - private static MethodCandidateInfo[] toMethodCandidates(@Nonnull JavaResolveResult[] resolveResults) { - List candidateList = new ArrayList<>(resolveResults.length); - - for (JavaResolveResult result : resolveResults) { - if (!(result instanceof MethodCandidateInfo)) { - continue; - } - MethodCandidateInfo candidate = (MethodCandidateInfo)result; - if (candidate.isAccessible()) { - candidateList.add(candidate); - } - } - return candidateList.toArray(new MethodCandidateInfo[candidateList.size()]); - } - - private static void registerMethodCallIntentions(@Nullable HighlightInfo highlightInfo, - PsiMethodCallExpression methodCall, - PsiExpressionList list, - PsiResolveHelper resolveHelper) { - TextRange fixRange = getFixRange(methodCall); - final PsiExpression qualifierExpression = methodCall.getMethodExpression().getQualifierExpression(); - if (qualifierExpression instanceof PsiReferenceExpression) { - final PsiElement resolve = ((PsiReferenceExpression)qualifierExpression).resolve(); - if (resolve instanceof PsiClass && ((PsiClass)resolve).getContainingClass() != null && !((PsiClass)resolve).hasModifierProperty( - PsiModifier.STATIC)) { - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance() - .createModifierListFix((PsiClass)resolve, - PsiModifier.STATIC, - true, - false)); - } - } + String toolTip = XmlStringUtil.escapeString(description); + HighlightInfo info = HighlightInfo.newHighlightInfo(highlightInfoType) + .range(elementToHighlight) + .description(description) + .escapedToolTip(toolTip) + .create(); + registerMethodCallIntentions(info, methodCall, list, resolveHelper); + if (element != null && !resolveResult.isStaticsScopeCorrect()) { + HighlightUtil.registerStaticProblemQuickFixAction(element, info, referenceToMethod); + } - QuickFixAction.registerQuickFixAction(highlightInfo, - fixRange, - QuickFixFactory.getInstance().createCreateMethodFromUsageFix(methodCall)); - QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QuickFixFactory.getInstance() - .createCreateAbstractMethodFromUsageFix(methodCall)); - QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QuickFixFactory.getInstance() - .createCreateConstructorFromSuperFix(methodCall)); - QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QuickFixFactory.getInstance() - .createCreateConstructorFromThisFix(methodCall)); - QuickFixAction.registerQuickFixAction(highlightInfo, - fixRange, - QuickFixFactory.getInstance().createCreatePropertyFromUsageFix(methodCall)); - QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QuickFixFactory.getInstance() - .createCreateGetterSetterPropertyFromUsageFix(methodCall)); - CandidateInfo[] methodCandidates = resolveHelper.getReferencedMethodCandidates(methodCall, false); - CastMethodArgumentFix.REGISTRAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange); - PermuteArgumentsFix.registerFix(highlightInfo, methodCall, methodCandidates, fixRange); - AddTypeArgumentsFix.REGISTRAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange); - WrapArrayToArraysAsListFix.REGISTAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange); - WrapLongWithMathToIntExactFix.REGISTAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange); - WrapObjectWithOptionalOfNullableFix.REGISTAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange); - WrapStringWithFileFix.REGISTAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange); - registerMethodAccessLevelIntentions(methodCandidates, methodCall, list, highlightInfo); - registerChangeMethodSignatureFromUsageIntentions(methodCandidates, list, highlightInfo, fixRange); - RemoveRedundantArgumentsFix.registerIntentions(methodCandidates, list, highlightInfo, fixRange); - ConvertDoubleToFloatFix.registerIntentions(methodCandidates, list, highlightInfo, fixRange); - WrapExpressionFix.registerWrapAction(methodCandidates, list.getExpressions(), highlightInfo); - registerChangeParameterClassFix(methodCall, list, highlightInfo); - if (methodCandidates.length == 0) { - QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QuickFixFactory.getInstance().createStaticImportMethodFix(methodCall)); - QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QuickFixFactory.getInstance().addMethodQualifierFix(methodCall)); - } - for (IntentionAction action : QuickFixFactory.getInstance().getVariableTypeFromCallFixes(methodCall, list)) { - QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, action); - } - QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QuickFixFactory.getInstance() - .createReplaceAddAllArrayToCollectionFix(methodCall)); - QuickFixAction.registerQuickFixAction(highlightInfo, - fixRange, - QuickFixFactory.getInstance().createSurroundWithArrayFix(methodCall, null)); - QualifyThisArgumentFix.registerQuickFixAction(methodCandidates, methodCall, highlightInfo, fixRange); - - CandidateInfo[] candidates = resolveHelper.getReferencedMethodCandidates(methodCall, true); - ChangeStringLiteralToCharInMethodCallFix.registerFixes(candidates, methodCall, highlightInfo); - } - - private static void registerMethodAccessLevelIntentions(CandidateInfo[] methodCandidates, - PsiMethodCallExpression methodCall, - PsiExpressionList exprList, - HighlightInfo highlightInfo) { - for (CandidateInfo methodCandidate : methodCandidates) { - PsiMethod method = (PsiMethod)methodCandidate.getElement(); - if (!methodCandidate.isAccessible() && PsiUtil.isApplicable(method, methodCandidate.getSubstitutor(), exprList)) { - HighlightUtil.registerAccessQuickFixAction(method, - methodCall.getMethodExpression(), - highlightInfo, - methodCandidate.getCurrentFileResolveScope()); - } - } - } - - @Nonnull - private static String createAmbiguousMethodHtmlTooltip(MethodCandidateInfo[] methodCandidates) { - return JavaErrorBundle.message("ambiguous.method.html.tooltip", - methodCandidates[0].getElement().getParameterList().getParametersCount() + 2, - createAmbiguousMethodHtmlTooltipMethodRow - (methodCandidates[0]), - getContainingClassName(methodCandidates[0]), - createAmbiguousMethodHtmlTooltipMethodRow(methodCandidates[1]), - getContainingClassName(methodCandidates[1])); - } - - private static String getContainingClassName(final MethodCandidateInfo methodCandidate) { - PsiMethod method = methodCandidate.getElement(); - PsiClass containingClass = method.getContainingClass(); - return containingClass == null ? method.getContainingFile().getName() : HighlightUtil.formatClass(containingClass, false); - } - - @Language("HTML") - private static String createAmbiguousMethodHtmlTooltipMethodRow(final MethodCandidateInfo methodCandidate) { - PsiMethod method = methodCandidate.getElement(); - PsiParameter[] parameters = method.getParameterList().getParameters(); - PsiSubstitutor substitutor = methodCandidate.getSubstitutor(); - @NonNls @Language("HTML") String ms = "" + method.getName() + ""; - - for (int j = 0; j < parameters.length; j++) { - PsiParameter parameter = parameters[j]; - PsiType type = substitutor.substitute(parameter.getType()); - ms += - "" + (j == 0 ? "(" : "") + XmlStringUtil.escapeString(type.getPresentableText()) + (j == parameters.length - 1 ? ")" : ",") + ""; - } - if (parameters.length == 0) { - ms += "()"; + TextRange fixRange = getFixRange(elementToHighlight); + CastMethodArgumentFix.REGISTRAR.registerCastActions(candidates, methodCall, info, fixRange); + WrapArrayToArraysAsListFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); + WrapLongWithMathToIntExactFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); + WrapObjectWithOptionalOfNullableFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); + WrapLongWithMathToIntExactFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); + PermuteArgumentsFix.registerFix(info, methodCall, candidates, fixRange); + WrapExpressionFix.registerWrapAction(candidates, list.getExpressions(), info); + registerChangeParameterClassFix(methodCall, list, info); + if (candidates.length == 0 && info != null) { + UnresolvedReferenceQuickFixProvider.registerReferenceFixes( + methodCall.getMethodExpression(), + QuickFixActionRegistrar.create(info) + ); + } + return info; } - return ms; - } - - private static String createMismatchedArgumentsHtmlTooltip(MethodCandidateInfo info, PsiExpressionList list) { - PsiMethod method = info.getElement(); - PsiSubstitutor substitutor = info.getSubstitutor(); - PsiClass aClass = method.getContainingClass(); - PsiParameter[] parameters = method.getParameterList().getParameters(); - String methodName = method.getName(); - return createMismatchedArgumentsHtmlTooltip(list, info, parameters, methodName, substitutor, aClass); - } - - private static String createShortMismatchedArgumentsHtmlTooltip(PsiExpressionList list, - @Nullable MethodCandidateInfo info, - PsiParameter[] parameters, - String methodName, - PsiSubstitutor substitutor, - PsiClass aClass) { - PsiExpression[] expressions = list.getExpressions(); - int cols = Math.max(parameters.length, expressions.length); - - @Language("HTML") @NonNls String parensizedName = methodName + (parameters.length == 0 ? "( ) " : ""); - String errorMessage = info != null ? info.getParentInferenceErrorMessage(list) : null; - return JavaErrorBundle.message("argument.mismatch.html.tooltip", - cols - parameters.length + 1, - parensizedName, - HighlightUtil.formatClass(aClass, false), - createMismatchedArgsHtmlTooltipParamsRow(parameters, substitutor, expressions), - createMismatchedArgsHtmlTooltipArgumentsRow(expressions, parameters, substitutor, cols), - errorMessage - != null ? "
reason: " + XmlStringUtil.escapeString(errorMessage).replaceAll("\n", "
") : ""); - } - - private static String esctrim(@Nonnull String s) { - return XmlStringUtil.escapeString(trimNicely(s)); - } - - private static String trimNicely(String s) { - if (s.length() <= 40) { - return s; + + @Nullable + public static HighlightInfo checkAmbiguousMethodCallArguments( + @Nonnull PsiReferenceExpression referenceToMethod, + @Nonnull JavaResolveResult[] resolveResults, + @Nonnull PsiExpressionList list, + final PsiElement element, + @Nonnull JavaResolveResult resolveResult, + @Nonnull PsiMethodCallExpression methodCall, + @Nonnull PsiResolveHelper resolveHelper, + @Nonnull PsiElement elementToHighlight + ) { + MethodCandidateInfo methodCandidate1 = null; + MethodCandidateInfo methodCandidate2 = null; + for (JavaResolveResult result : resolveResults) { + if (!(result instanceof MethodCandidateInfo)) { + continue; + } + MethodCandidateInfo candidate = (MethodCandidateInfo)result; + if (candidate.isApplicable() && !candidate.getElement().isConstructor()) { + if (methodCandidate1 == null) { + methodCandidate1 = candidate; + } + else { + methodCandidate2 = candidate; + break; + } + } + } + MethodCandidateInfo[] candidates = toMethodCandidates(resolveResults); + + String description; + String toolTip; + HighlightInfoType highlightInfoType = HighlightInfoType.ERROR; + if (methodCandidate2 != null) { + PsiMethod element1 = methodCandidate1.getElement(); + String m1 = PsiFormatUtil.formatMethod( + element1, + methodCandidate1.getSubstitutor(false), + PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, + PsiFormatUtilBase.SHOW_TYPE + ); + PsiMethod element2 = methodCandidate2.getElement(); + String m2 = PsiFormatUtil.formatMethod( + element2, + methodCandidate2.getSubstitutor(false), + PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, + PsiFormatUtilBase.SHOW_TYPE + ); + VirtualFile virtualFile1 = PsiUtilCore.getVirtualFile(element1); + VirtualFile virtualFile2 = PsiUtilCore.getVirtualFile(element2); + if (!Comparing.equal(virtualFile1, virtualFile2)) { + if (virtualFile1 != null) { + m1 += " (In " + virtualFile1.getPresentableUrl() + ")"; + } + if (virtualFile2 != null) { + m2 += " (In " + virtualFile2.getPresentableUrl() + ")"; + } + } + description = JavaErrorBundle.message("ambiguous.method.call", m1, m2); + toolTip = createAmbiguousMethodHtmlTooltip(new MethodCandidateInfo[]{ + methodCandidate1, + methodCandidate2 + }); + } + else { + if (element != null && !resolveResult.isAccessible()) { + return null; + } + if (element != null && !resolveResult.isStaticsScopeCorrect()) { + return null; + } + String methodName = referenceToMethod.getReferenceName() + buildArgTypesList(list); + description = JavaErrorBundle.message("cannot.resolve.method", methodName); + if (candidates.length == 0) { + return null; + } + toolTip = XmlStringUtil.escapeString(description); + } + HighlightInfo info = HighlightInfo.newHighlightInfo(highlightInfoType) + .range(elementToHighlight) + .description(description) + .escapedToolTip(toolTip) + .create(); + if (methodCandidate2 == null) { + registerMethodCallIntentions(info, methodCall, list, resolveHelper); + } + if (!resolveResult.isAccessible() && resolveResult.isStaticsScopeCorrect() && methodCandidate2 != null) { + HighlightUtil.registerAccessQuickFixAction( + (PsiMember)element, + referenceToMethod, + info, + resolveResult.getCurrentFileResolveScope() + ); + } + if (element != null && !resolveResult.isStaticsScopeCorrect()) { + HighlightUtil.registerStaticProblemQuickFixAction(element, info, referenceToMethod); + } + + TextRange fixRange = getFixRange(elementToHighlight); + CastMethodArgumentFix.REGISTRAR.registerCastActions(candidates, methodCall, info, fixRange); + WrapArrayToArraysAsListFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); + WrapLongWithMathToIntExactFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); + WrapObjectWithOptionalOfNullableFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); + WrapStringWithFileFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange); + PermuteArgumentsFix.registerFix(info, methodCall, candidates, fixRange); + WrapExpressionFix.registerWrapAction(candidates, list.getExpressions(), info); + registerChangeParameterClassFix(methodCall, list, info); + return info; } - List wordIndices = TextRangeUtil.getWordIndicesIn(s); - if (wordIndices.size() > 2) { - int firstWordEnd = wordIndices.get(0).getEndOffset(); + @Nonnull + private static MethodCandidateInfo[] toMethodCandidates(@Nonnull JavaResolveResult[] resolveResults) { + List candidateList = new ArrayList<>(resolveResults.length); - // try firstWord...remainder - for (int i = 1; i < wordIndices.size(); i++) { - int stringLength = firstWordEnd + s.length() - wordIndices.get(i).getStartOffset(); - if (stringLength <= 40) { - return s.substring(0, firstWordEnd) + "..." + s.substring(wordIndices.get(i).getStartOffset()); + for (JavaResolveResult result : resolveResults) { + if (!(result instanceof MethodCandidateInfo)) { + continue; + } + MethodCandidateInfo candidate = (MethodCandidateInfo)result; + if (candidate.isAccessible()) { + candidateList.add(candidate); + } + } + return candidateList.toArray(new MethodCandidateInfo[candidateList.size()]); + } + + private static void registerMethodCallIntentions( + @Nullable HighlightInfo highlightInfo, + PsiMethodCallExpression methodCall, + PsiExpressionList list, + PsiResolveHelper resolveHelper + ) { + TextRange fixRange = getFixRange(methodCall); + final PsiExpression qualifierExpression = methodCall.getMethodExpression().getQualifierExpression(); + if (qualifierExpression instanceof PsiReferenceExpression) { + final PsiElement resolve = ((PsiReferenceExpression)qualifierExpression).resolve(); + if (resolve instanceof PsiClass + && ((PsiClass)resolve).getContainingClass() != null + && !((PsiClass)resolve).hasModifierProperty(PsiModifier.STATIC)) { + QuickFixAction.registerQuickFixAction( + highlightInfo, + QuickFixFactory.getInstance().createModifierListFix( + (PsiClass)resolve, + PsiModifier.STATIC, + true, + false + ) + ); + } + } + + QuickFixAction.registerQuickFixAction( + highlightInfo, + fixRange, + QuickFixFactory.getInstance().createCreateMethodFromUsageFix(methodCall) + ); + QuickFixAction.registerQuickFixAction( + highlightInfo, + fixRange, + QuickFixFactory.getInstance().createCreateAbstractMethodFromUsageFix(methodCall) + ); + QuickFixAction.registerQuickFixAction( + highlightInfo, + fixRange, + QuickFixFactory.getInstance().createCreateConstructorFromSuperFix(methodCall) + ); + QuickFixAction.registerQuickFixAction( + highlightInfo, + fixRange, + QuickFixFactory.getInstance().createCreateConstructorFromThisFix(methodCall) + ); + QuickFixAction.registerQuickFixAction( + highlightInfo, + fixRange, + QuickFixFactory.getInstance().createCreatePropertyFromUsageFix(methodCall) + ); + QuickFixAction.registerQuickFixAction( + highlightInfo, + fixRange, + QuickFixFactory.getInstance().createCreateGetterSetterPropertyFromUsageFix(methodCall) + ); + CandidateInfo[] methodCandidates = resolveHelper.getReferencedMethodCandidates(methodCall, false); + CastMethodArgumentFix.REGISTRAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange); + PermuteArgumentsFix.registerFix(highlightInfo, methodCall, methodCandidates, fixRange); + AddTypeArgumentsFix.REGISTRAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange); + WrapArrayToArraysAsListFix.REGISTAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange); + WrapLongWithMathToIntExactFix.REGISTAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange); + WrapObjectWithOptionalOfNullableFix.REGISTAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange); + WrapStringWithFileFix.REGISTAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange); + registerMethodAccessLevelIntentions(methodCandidates, methodCall, list, highlightInfo); + registerChangeMethodSignatureFromUsageIntentions(methodCandidates, list, highlightInfo, fixRange); + RemoveRedundantArgumentsFix.registerIntentions(methodCandidates, list, highlightInfo, fixRange); + ConvertDoubleToFloatFix.registerIntentions(methodCandidates, list, highlightInfo, fixRange); + WrapExpressionFix.registerWrapAction(methodCandidates, list.getExpressions(), highlightInfo); + registerChangeParameterClassFix(methodCall, list, highlightInfo); + if (methodCandidates.length == 0) { + QuickFixAction.registerQuickFixAction( + highlightInfo, + fixRange, + QuickFixFactory.getInstance().createStaticImportMethodFix(methodCall) + ); + QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QuickFixFactory.getInstance().addMethodQualifierFix(methodCall)); + } + for (IntentionAction action : QuickFixFactory.getInstance().getVariableTypeFromCallFixes(methodCall, list)) { + QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, action); + } + QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QuickFixFactory.getInstance() + .createReplaceAddAllArrayToCollectionFix(methodCall)); + QuickFixAction.registerQuickFixAction( + highlightInfo, + fixRange, + QuickFixFactory.getInstance().createSurroundWithArrayFix(methodCall, null) + ); + QualifyThisArgumentFix.registerQuickFixAction(methodCandidates, methodCall, highlightInfo, fixRange); + + CandidateInfo[] candidates = resolveHelper.getReferencedMethodCandidates(methodCall, true); + ChangeStringLiteralToCharInMethodCallFix.registerFixes(candidates, methodCall, highlightInfo); + } + + private static void registerMethodAccessLevelIntentions( + CandidateInfo[] methodCandidates, + PsiMethodCallExpression methodCall, + PsiExpressionList exprList, + HighlightInfo highlightInfo + ) { + for (CandidateInfo methodCandidate : methodCandidates) { + PsiMethod method = (PsiMethod)methodCandidate.getElement(); + if (!methodCandidate.isAccessible() && PsiUtil.isApplicable(method, methodCandidate.getSubstitutor(), exprList)) { + HighlightUtil.registerAccessQuickFixAction( + method, + methodCall.getMethodExpression(), + highlightInfo, + methodCandidate.getCurrentFileResolveScope() + ); + } } - } - } - // maybe one last word will fit? - if (!wordIndices.isEmpty() && s.length() - wordIndices.get(wordIndices.size() - 1).getStartOffset() <= 40) { - return "..." + s.substring(wordIndices.get(wordIndices.size() - 1).getStartOffset()); } - return StringUtil.last(s, 40, true).toString(); - } - - private static String createMismatchedArgumentsHtmlTooltip(PsiExpressionList list, - MethodCandidateInfo info, - PsiParameter[] parameters, - String methodName, - PsiSubstitutor substitutor, - PsiClass aClass) { - return Math.max(parameters.length, list.getExpressions().length) <= 2 ? createShortMismatchedArgumentsHtmlTooltip(list, - info, - parameters, - methodName, - substitutor, - aClass) : - createLongMismatchedArgumentsHtmlTooltip(list, info, parameters, methodName, substitutor, aClass); - } - - @SuppressWarnings("StringContatenationInLoop") - @Language("HTML") - private static String createLongMismatchedArgumentsHtmlTooltip(PsiExpressionList list, - @Nullable MethodCandidateInfo info, - PsiParameter[] parameters, - String methodName, - PsiSubstitutor substitutor, - PsiClass aClass) { - PsiExpression[] expressions = list.getExpressions(); - - @SuppressWarnings("NonConstantStringShouldBeStringBuffer") @NonNls String s = - "" + "" + "" + ""; - - for (int i = 0; i < Math.max(parameters.length, expressions.length); i++) { - PsiParameter parameter = i < parameters.length ? parameters[i] : null; - PsiExpression expression = i < expressions.length ? expressions[i] : null; - boolean showShort = showShortType(i, parameters, expressions, substitutor); - @NonNls String mismatchColor = showShort ? null : UIUtil.isUnderDarcula() ? "FF6B68" : "red"; - - s += - ""; - s += ""; - - s += ""; - - s += ""; - - s += ""; + @Nonnull + private static String createAmbiguousMethodHtmlTooltip(MethodCandidateInfo[] methodCandidates) { + return JavaErrorBundle.message( + "ambiguous.method.html.tooltip", + methodCandidates[0].getElement().getParameterList().getParametersCount() + 2, + createAmbiguousMethodHtmlTooltipMethodRow + (methodCandidates[0]), + getContainingClassName(methodCandidates[0]), + createAmbiguousMethodHtmlTooltipMethodRow(methodCandidates[1]), + getContainingClassName(methodCandidates[1]) + ); } - s += "
" + "" + methodName + "() in " + - HighlightUtil.formatClass(aClass, - false) + " cannot be applied to:" + "
Expected
Parameters:
Actual
Arguments:

"; - if (parameter != null) { - String name = parameter.getName(); - if (name != null) { - s += esctrim(name) + ":"; - } - } - s += ""; - if (parameter != null) { - PsiType type = substitutor.substitute(parameter.getType()); - s += - "" + esctrim(showShort ? type.getPresentableText() : JavaHighlightUtil.formatType( - type)) + ""; - } - s += ""; - if (expression != null) { - PsiType type = expression.getType(); - s += - "" + esctrim(expression.getText()) + "  " + (mismatchColor == null || type == null || type - == PsiType.NULL ? "" : "(" + esctrim(JavaHighlightUtil.formatType(type)) + ")") + ""; - - } - s += "
"; - final String errorMessage = info != null ? info.getParentInferenceErrorMessage(list) : null; - if (errorMessage != null) { - s += "reason: "; - s += XmlStringUtil.escapeString(errorMessage).replaceAll("\n", "
"); + private static String getContainingClassName(final MethodCandidateInfo methodCandidate) { + PsiMethod method = methodCandidate.getElement(); + PsiClass containingClass = method.getContainingClass(); + return containingClass == null ? method.getContainingFile().getName() : HighlightUtil.formatClass(containingClass, false); } - s += ""; - return s; - } - - @SuppressWarnings("StringContatenationInLoop") - @Language("HTML") - private static String createMismatchedArgsHtmlTooltipArgumentsRow(final PsiExpression[] expressions, - final PsiParameter[] parameters, - final PsiSubstitutor substitutor, - final int cols) { + @Language("HTML") + private static String createAmbiguousMethodHtmlTooltipMethodRow(final MethodCandidateInfo methodCandidate) { + PsiMethod method = methodCandidate.getElement(); + PsiParameter[] parameters = method.getParameterList().getParameters(); + PsiSubstitutor substitutor = methodCandidate.getSubstitutor(); + @NonNls @Language("HTML") String ms = "" + method.getName() + ""; + + for (int j = 0; j < parameters.length; j++) { + PsiParameter parameter = parameters[j]; + PsiType type = substitutor.substitute(parameter.getType()); + ms += + "" + (j == 0 ? "(" : "") + XmlStringUtil.escapeString(type.getPresentableText()) + (j == parameters.length - 1 ? ")" : ",") + ""; + } + if (parameters.length == 0) { + ms += "()"; + } + return ms; + } + + private static String createMismatchedArgumentsHtmlTooltip(MethodCandidateInfo info, PsiExpressionList list) { + PsiMethod method = info.getElement(); + PsiSubstitutor substitutor = info.getSubstitutor(); + PsiClass aClass = method.getContainingClass(); + PsiParameter[] parameters = method.getParameterList().getParameters(); + String methodName = method.getName(); + return createMismatchedArgumentsHtmlTooltip(list, info, parameters, methodName, substitutor, aClass); + } + + private static String createShortMismatchedArgumentsHtmlTooltip( + PsiExpressionList list, + @Nullable MethodCandidateInfo info, + PsiParameter[] parameters, + String methodName, + PsiSubstitutor substitutor, + PsiClass aClass + ) { + PsiExpression[] expressions = list.getExpressions(); + int cols = Math.max(parameters.length, expressions.length); + + @Language("HTML") @NonNls String parensizedName = methodName + (parameters.length == 0 ? "( ) " : ""); + String errorMessage = info != null ? info.getParentInferenceErrorMessage(list) : null; + return JavaErrorBundle.message( + "argument.mismatch.html.tooltip", + cols - parameters.length + 1, + parensizedName, + HighlightUtil.formatClass(aClass, false), + createMismatchedArgsHtmlTooltipParamsRow(parameters, substitutor, expressions), + createMismatchedArgsHtmlTooltipArgumentsRow(expressions, parameters, substitutor, cols), + errorMessage != null + ? "
reason: " + XmlStringUtil.escapeString(errorMessage).replaceAll("\n", "
") + : "" + ); + } + + private static String esctrim(@Nonnull String s) { + return XmlStringUtil.escapeString(trimNicely(s)); + } + + private static String trimNicely(String s) { + if (s.length() <= 40) { + return s; + } - String ms = ""; - for (int i = 0; i < expressions.length; i++) { - PsiExpression expression = expressions[i]; - PsiType type = expression.getType(); - - boolean showShort = showShortType(i, parameters, expressions, substitutor); - String mismatchColor = showShort ? null : ColorUtil.toHex(JBColor.RED); - ms += - " " + "" + (i == 0 ? "(" : "") + "" + XmlStringUtil.escapeString( - showShort ? type.getPresentableText() : - JavaHighlightUtil.formatType(type)) + "" + (i == expressions.length - 1 ? ")" : ",") + ""; - } - for (int i = expressions.length; i < cols + 1; i++) { - ms += "" + (i == 0 ? "()" : "") + " "; - } - return ms; - } - - @SuppressWarnings("StringContatenationInLoop") - @Language("HTML") - private static String createMismatchedArgsHtmlTooltipParamsRow(final PsiParameter[] parameters, - final PsiSubstitutor substitutor, - final PsiExpression[] expressions) { - @NonNls String ms = ""; - for (int i = 0; i < parameters.length; i++) { - PsiParameter parameter = parameters[i]; - PsiType type = substitutor.substitute(parameter.getType()); - ms += "" + (i == 0 ? "(" : "") + XmlStringUtil.escapeString(showShortType(i, - parameters, - expressions, - substitutor) ? type.getPresentableText() : JavaHighlightUtil.formatType - (type)) + (i == parameters.length - 1 ? ")" : ",") + ""; - } - return ms; - } + List wordIndices = TextRangeUtil.getWordIndicesIn(s); + if (wordIndices.size() > 2) { + int firstWordEnd = wordIndices.get(0).getEndOffset(); - private static boolean showShortType(int i, PsiParameter[] parameters, PsiExpression[] expressions, PsiSubstitutor substitutor) { - PsiExpression expression = i < expressions.length ? expressions[i] : null; - if (expression == null) { - return true; - } - PsiType paramType = i < parameters.length && parameters[i] != null ? substitutor.substitute(parameters[i].getType()) : null; - PsiType expressionType = expression.getType(); - return paramType != null && expressionType != null && TypeConversionUtil.isAssignable(paramType, expressionType); - } - - - public static HighlightInfo checkMethodMustHaveBody(PsiMethod method, PsiClass aClass) { - HighlightInfo errorResult = null; - if (method.getBody() == null && !method.hasModifierProperty(PsiModifier.ABSTRACT) && !method.hasModifierProperty(PsiModifier.NATIVE) && aClass != null && !aClass.isInterface() && !PsiUtilCore - .hasErrorElementChild(method)) { - int start = method.getModifierList().getTextRange().getStartOffset(); - int end = method.getTextRange().getEndOffset(); - - String description = JavaErrorBundle.message("missing.method.body"); - errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(start, end).descriptionAndTooltip(description).create(); - if (HighlightUtil.getIncompatibleModifier(PsiModifier.ABSTRACT, method.getModifierList()) == null) { - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance() - .createModifierListFix(method, - PsiModifier.ABSTRACT, - true, - false)); - } - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createAddMethodBodyFix(method)); + // try firstWord...remainder + for (int i = 1; i < wordIndices.size(); i++) { + int stringLength = firstWordEnd + s.length() - wordIndices.get(i).getStartOffset(); + if (stringLength <= 40) { + return s.substring(0, firstWordEnd) + "..." + s.substring(wordIndices.get(i).getStartOffset()); + } + } + } + // maybe one last word will fit? + if (!wordIndices.isEmpty() && s.length() - wordIndices.get(wordIndices.size() - 1).getStartOffset() <= 40) { + return "..." + s.substring(wordIndices.get(wordIndices.size() - 1).getStartOffset()); + } + + return StringUtil.last(s, 40, true).toString(); } - return errorResult; - } - - - public static HighlightInfo checkAbstractMethodInConcreteClass(PsiMethod method, PsiElement elementToHighlight) { - HighlightInfo errorResult = null; - PsiClass aClass = method.getContainingClass(); - if (method.hasModifierProperty(PsiModifier.ABSTRACT) && aClass != null && !aClass.hasModifierProperty(PsiModifier.ABSTRACT) && !aClass.isEnum() && !PsiUtilCore.hasErrorElementChild( - method)) { - String description = JavaErrorBundle.message("abstract.method.in.non.abstract.class"); - errorResult = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(elementToHighlight).descriptionAndTooltip(description).create(); - if (method.getBody() != null) { - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance() - .createModifierListFix(method, - PsiModifier.ABSTRACT, - false, - false)); - } - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createAddMethodBodyFix(method)); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance() - .createModifierListFix(aClass, PsiModifier.ABSTRACT, true, false)); + + private static String createMismatchedArgumentsHtmlTooltip( + PsiExpressionList list, + MethodCandidateInfo info, + PsiParameter[] parameters, + String methodName, + PsiSubstitutor substitutor, + PsiClass aClass + ) { + return Math.max(parameters.length, list.getExpressions().length) <= 2 + ? createShortMismatchedArgumentsHtmlTooltip(list, info, parameters, methodName, substitutor, aClass) + : createLongMismatchedArgumentsHtmlTooltip(list, info, parameters, methodName, substitutor, aClass); } - return errorResult; - } + @SuppressWarnings("StringContatenationInLoop") + @Language("HTML") + private static String createLongMismatchedArgumentsHtmlTooltip( + PsiExpressionList list, + @Nullable MethodCandidateInfo info, + PsiParameter[] parameters, + String methodName, + PsiSubstitutor substitutor, + PsiClass aClass + ) { + PsiExpression[] expressions = list.getExpressions(); + + @SuppressWarnings("NonConstantStringShouldBeStringBuffer") @NonNls String s = + "" + "" + "" + ""; + + for (int i = 0; i < Math.max(parameters.length, expressions.length); i++) { + PsiParameter parameter = i < parameters.length ? parameters[i] : null; + PsiExpression expression = i < expressions.length ? expressions[i] : null; + boolean showShort = showShortType(i, parameters, expressions, substitutor); + @NonNls String mismatchColor = showShort ? null : UIUtil.isUnderDarcula() ? "FF6B68" : "red"; + + s += ""; + s += ""; - public static HighlightInfo checkConstructorName(PsiMethod method) { - String methodName = method.getName(); - PsiClass aClass = method.getContainingClass(); - HighlightInfo errorResult = null; + s += ""; + + s += ""; + + s += ""; } - } - } - return errorResult; - } - - @Nullable - public static HighlightInfo checkDuplicateMethod(PsiClass aClass, - @Nonnull PsiMethod method, - @Nonnull MostlySingularMultiMap duplicateMethods) { - if (aClass == null || method instanceof ExternallyDefinedPsiElement) { - return null; - } - MethodSignature methodSignature = method.getSignature(PsiSubstitutor.EMPTY); - int methodCount = 1; - List methods = (List)duplicateMethods.get(methodSignature); - if (methods.size() > 1) { - methodCount++; - } - if (methodCount == 1 && aClass.isEnum() && GenericsHighlightUtil.isEnumSyntheticMethod(methodSignature, aClass.getProject())) { - methodCount++; - } - if (methodCount > 1) { - String description = - JavaErrorBundle.message("duplicate.method", JavaHighlightUtil.formatMethod(method), HighlightUtil.formatClass(aClass)); - TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR). - range(method, textRange.getStartOffset(), textRange.getEndOffset()). - descriptionAndTooltip(description).create(); - } - return null; - } - - @Nullable - public static HighlightInfo checkMethodCanHaveBody(@Nonnull PsiMethod method, @Nonnull LanguageLevel languageLevel) { - PsiClass aClass = method.getContainingClass(); - boolean hasNoBody = method.getBody() == null; - boolean isInterface = aClass != null && aClass.isInterface(); - boolean isExtension = method.hasModifierProperty(PsiModifier.DEFAULT); - boolean isStatic = method.hasModifierProperty(PsiModifier.STATIC); - boolean isPrivate = method.hasModifierProperty(PsiModifier.PRIVATE); - - final List additionalFixes = new ArrayList<>(); - String description = null; - if (hasNoBody) { - if (isExtension) { - description = JavaErrorBundle.message("extension.method.should.have.a.body"); - additionalFixes.add(QuickFixFactory.getInstance().createAddMethodBodyFix(method)); - } - else if (isInterface) { - if (isStatic && languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { - description = "Static methods in interfaces should have a body"; - } - else if (isPrivate && languageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { - description = "Private methods in interfaces should have a body"; - } - } - } - else if (isInterface) { - if (!isExtension && !isStatic && !isPrivate) { - description = JavaErrorBundle.message("interface.methods.cannot.have.body"); - if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { - additionalFixes.add(QuickFixFactory.getInstance().createModifierListFix(method, PsiModifier.DEFAULT, true, false)); - additionalFixes.add(QuickFixFactory.getInstance().createModifierListFix(method, PsiModifier.STATIC, true, false)); - } - } - } - else if (isExtension) { - description = JavaErrorBundle.message("extension.method.in.class"); - } - else if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { - description = JavaErrorBundle.message("abstract.methods.cannot.have.a.body"); - } - else if (method.hasModifierProperty(PsiModifier.NATIVE)) { - description = JavaErrorBundle.message("native.methods.cannot.have.a.body"); - } - if (description == null) { - return null; + s += "
" + "" + methodName + "() in " + + HighlightUtil.formatClass( + aClass, + false + ) + " cannot be applied to:" + "
Expected
Parameters:
Actual
Arguments:

"; + if (parameter != null) { + String name = parameter.getName(); + if (name != null) { + s += esctrim(name) + ":"; + } + } + s += ""; + if (parameter != null) { + PsiType type = substitutor.substitute(parameter.getType()); + s += "" + + esctrim(showShort ? type.getPresentableText() : JavaHighlightUtil.formatType(type)) + ""; + } + s += ""; + if (expression != null) { + PsiType type = expression.getType(); + s += "" + esctrim(expression.getText()) + + "  " + ( + mismatchColor == null || type == null || type == PsiType.NULL + ? "" + : "(" + esctrim(JavaHighlightUtil.formatType(type)) + ")" + ) + ""; - if (aClass != null) { - String className = aClass instanceof PsiAnonymousClass ? null : aClass.getName(); - if (className == null || !Comparing.strEqual(methodName, className)) { - PsiElement element = method.getNameIdentifier(); - String description = JavaErrorBundle.message("missing.return.type"); - errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); - if (className != null) { - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createRenameElementFix(method, className)); + } + s += "
"; + final String errorMessage = info != null ? info.getParentInferenceErrorMessage(list) : null; + if (errorMessage != null) { + s += "reason: "; + s += XmlStringUtil.escapeString(errorMessage).replaceAll("\n", "
"); + } + s += ""; + return s; } - TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - if (!hasNoBody) { - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createDeleteMethodBodyFix(method)); - } - if (method.hasModifierProperty(PsiModifier.ABSTRACT) && !isInterface) { - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance() - .createModifierListFix(method, PsiModifier.ABSTRACT, false, false)); - } - for (IntentionAction intentionAction : additionalFixes) { - QuickFixAction.registerQuickFixAction(info, intentionAction); + @SuppressWarnings("StringContatenationInLoop") + @Language("HTML") + private static String createMismatchedArgsHtmlTooltipArgumentsRow( + final PsiExpression[] expressions, + final PsiParameter[] parameters, + final PsiSubstitutor substitutor, + final int cols + ) { + @Language("HTML") + + String ms = ""; + for (int i = 0; i < expressions.length; i++) { + PsiExpression expression = expressions[i]; + PsiType type = expression.getType(); + + boolean showShort = showShortType(i, parameters, expressions, substitutor); + String mismatchColor = showShort ? null : ColorUtil.toHex(JBColor.RED); + ms += " " + "" + (i == 0 ? "(" : "") + "" + + XmlStringUtil.escapeString( + showShort + ? type.getPresentableText() + : JavaHighlightUtil.formatType(type) + ) + "" + (i == expressions.length - 1 ? ")" : ",") + ""; + } + for (int i = expressions.length; i < cols + 1; i++) { + ms += "" + (i == 0 ? "()" : "") + " "; + } + return ms; } - return info; - } - @Nullable - public static HighlightInfo checkConstructorCallMustBeFirstStatement(@Nonnull PsiMethodCallExpression methodCall) { - if (!RefactoringChangeUtil.isSuperOrThisMethodCall(methodCall)) { - return null; + @SuppressWarnings("StringContatenationInLoop") + @Language("HTML") + private static String createMismatchedArgsHtmlTooltipParamsRow( + final PsiParameter[] parameters, + final PsiSubstitutor substitutor, + final PsiExpression[] expressions + ) { + @NonNls String ms = ""; + for (int i = 0; i < parameters.length; i++) { + PsiParameter parameter = parameters[i]; + PsiType type = substitutor.substitute(parameter.getType()); + ms += "" + (i == 0 ? "(" : "") + XmlStringUtil.escapeString( + showShortType(i, parameters, expressions, substitutor) + ? type.getPresentableText() + : JavaHighlightUtil.formatType(type) + ) + (i == parameters.length - 1 ? ")" : ",") + ""; + } + return ms; } - PsiElement codeBlock = methodCall.getParent().getParent(); - if (codeBlock instanceof PsiCodeBlock && codeBlock.getParent() instanceof PsiMethod && ((PsiMethod)codeBlock.getParent()).isConstructor()) { - PsiElement prevSibling = methodCall.getParent().getPrevSibling(); - while (true) { - if (prevSibling == null) { - return null; - } - if (prevSibling instanceof PsiStatement) { - break; - } - prevSibling = prevSibling.getPrevSibling(); - } + + private static boolean showShortType(int i, PsiParameter[] parameters, PsiExpression[] expressions, PsiSubstitutor substitutor) { + PsiExpression expression = i < expressions.length ? expressions[i] : null; + if (expression == null) { + return true; + } + PsiType paramType = i < parameters.length && parameters[i] != null ? substitutor.substitute(parameters[i].getType()) : null; + PsiType expressionType = expression.getType(); + return paramType != null && expressionType != null && TypeConversionUtil.isAssignable(paramType, expressionType); + } + + + public static HighlightInfo checkMethodMustHaveBody(PsiMethod method, PsiClass aClass) { + HighlightInfo errorResult = null; + if (method.getBody() == null && !method.hasModifierProperty(PsiModifier.ABSTRACT) + && !method.hasModifierProperty(PsiModifier.NATIVE) && aClass != null && !aClass.isInterface() + && !PsiUtilCore.hasErrorElementChild(method)) { + int start = method.getModifierList().getTextRange().getStartOffset(); + int end = method.getTextRange().getEndOffset(); + + String description = JavaErrorBundle.message("missing.method.body"); + errorResult = + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(start, end).descriptionAndTooltip(description).create(); + if (HighlightUtil.getIncompatibleModifier(PsiModifier.ABSTRACT, method.getModifierList()) == null) { + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createModifierListFix( + method, + PsiModifier.ABSTRACT, + true, + false + ) + ); + } + QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createAddMethodBodyFix(method)); + } + return errorResult; } - PsiReferenceExpression expression = methodCall.getMethodExpression(); - String message = JavaErrorBundle.message("constructor.call.must.be.first.statement", expression.getText() + "()"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(methodCall).descriptionAndTooltip(message).create(); - } - public static HighlightInfo checkSuperAbstractMethodDirectCall(@Nonnull PsiMethodCallExpression methodCallExpression) { - PsiReferenceExpression expression = methodCallExpression.getMethodExpression(); - if (!(expression.getQualifierExpression() instanceof PsiSuperExpression)) { - return null; + public static HighlightInfo checkAbstractMethodInConcreteClass(PsiMethod method, PsiElement elementToHighlight) { + HighlightInfo errorResult = null; + PsiClass aClass = method.getContainingClass(); + if (method.hasModifierProperty(PsiModifier.ABSTRACT) && aClass != null + && !aClass.hasModifierProperty(PsiModifier.ABSTRACT) && !aClass.isEnum() && !PsiUtilCore.hasErrorElementChild(method)) { + String description = JavaErrorBundle.message("abstract.method.in.non.abstract.class"); + errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(elementToHighlight) + .descriptionAndTooltip(description) + .create(); + if (method.getBody() != null) { + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createModifierListFix( + method, + PsiModifier.ABSTRACT, + false, + false + ) + ); + } + QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createAddMethodBodyFix(method)); + QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance() + .createModifierListFix(aClass, PsiModifier.ABSTRACT, true, false)); + } + return errorResult; } - PsiMethod method = methodCallExpression.resolveMethod(); - if (method != null && method.hasModifierProperty(PsiModifier.ABSTRACT)) { - String message = JavaErrorBundle.message("direct.abstract.method.access", JavaHighlightUtil.formatMethod(method)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(methodCallExpression).descriptionAndTooltip(message).create(); + + public static HighlightInfo checkConstructorName(PsiMethod method) { + String methodName = method.getName(); + PsiClass aClass = method.getContainingClass(); + HighlightInfo errorResult = null; + + if (aClass != null) { + String className = aClass instanceof PsiAnonymousClass ? null : aClass.getName(); + if (className == null || !Comparing.strEqual(methodName, className)) { + PsiElement element = method.getNameIdentifier(); + String description = JavaErrorBundle.message("missing.return.type"); + errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(element) + .descriptionAndTooltip(description) + .create(); + if (className != null) { + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createRenameElementFix(method, className) + ); + } + } + } + return errorResult; } - return null; - } + @Nullable + public static HighlightInfo checkDuplicateMethod( + PsiClass aClass, + @Nonnull PsiMethod method, + @Nonnull MostlySingularMultiMap duplicateMethods + ) { + if (aClass == null || method instanceof ExternallyDefinedPsiElement) { + return null; + } + MethodSignature methodSignature = method.getSignature(PsiSubstitutor.EMPTY); + int methodCount = 1; + List methods = (List)duplicateMethods.get(methodSignature); + if (methods.size() > 1) { + methodCount++; + } - public static HighlightInfo checkConstructorCallsBaseClassConstructor(PsiMethod constructor, - RefCountHolder refCountHolder, - PsiResolveHelper resolveHelper) { - if (!constructor.isConstructor()) { - return null; - } - PsiClass aClass = constructor.getContainingClass(); - if (aClass == null) { - return null; - } - if (aClass.isEnum()) { - return null; - } - PsiCodeBlock body = constructor.getBody(); - if (body == null) { - return null; + if (methodCount == 1 && aClass.isEnum() && GenericsHighlightUtil.isEnumSyntheticMethod(methodSignature, aClass.getProject())) { + methodCount++; + } + if (methodCount > 1) { + String description = + JavaErrorBundle.message("duplicate.method", JavaHighlightUtil.formatMethod(method), HighlightUtil.formatClass(aClass)); + TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(method, textRange.getStartOffset(), textRange.getEndOffset()) + .descriptionAndTooltip(description) + .create(); + } + return null; } - // check whether constructor call super(...) or this(...) - PsiElement element = new PsiMatcherImpl(body).firstChild(PsiMatchers.hasClass(PsiExpressionStatement.class)) - .firstChild(PsiMatchers.hasClass(PsiMethodCallExpression.class)) - .firstChild - (PsiMatchers.hasClass(PsiReferenceExpression.class)) - .firstChild(PsiMatchers.hasClass(PsiKeyword.class)) - .getElement(); - if (element != null) { - return null; - } - TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(constructor); - PsiClassType[] handledExceptions = constructor.getThrowsList().getReferencedTypes(); - HighlightInfo info = - HighlightClassUtil.checkBaseClassDefaultConstructorProblem(aClass, refCountHolder, resolveHelper, textRange, handledExceptions); - if (info != null) { - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createInsertSuperFix(constructor)); - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createAddDefaultConstructorFix(aClass.getSuperClass())); - } - return info; - } - - - /** - * @return error if static method overrides instance method or - * instance method overrides static. see JLS 8.4.6.1, 8.4.6.2 - */ - public static HighlightInfo checkStaticMethodOverride(@Nonnull PsiMethod method, @Nonnull PsiFile containingFile) { - // constructors are not members and therefor don't override class methods - if (method.isConstructor()) { - return null; - } + @Nullable + public static HighlightInfo checkMethodCanHaveBody(@Nonnull PsiMethod method, @Nonnull LanguageLevel languageLevel) { + PsiClass aClass = method.getContainingClass(); + boolean hasNoBody = method.getBody() == null; + boolean isInterface = aClass != null && aClass.isInterface(); + boolean isExtension = method.hasModifierProperty(PsiModifier.DEFAULT); + boolean isStatic = method.hasModifierProperty(PsiModifier.STATIC); + boolean isPrivate = method.hasModifierProperty(PsiModifier.PRIVATE); + + final List additionalFixes = new ArrayList<>(); + String description = null; + if (hasNoBody) { + if (isExtension) { + description = JavaErrorBundle.message("extension.method.should.have.a.body"); + additionalFixes.add(QuickFixFactory.getInstance().createAddMethodBodyFix(method)); + } + else if (isInterface) { + if (isStatic && languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { + description = "Static methods in interfaces should have a body"; + } + else if (isPrivate && languageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { + description = "Private methods in interfaces should have a body"; + } + } + } + else if (isInterface) { + if (!isExtension && !isStatic && !isPrivate) { + description = JavaErrorBundle.message("interface.methods.cannot.have.body"); + if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { + additionalFixes.add(QuickFixFactory.getInstance().createModifierListFix(method, PsiModifier.DEFAULT, true, false)); + additionalFixes.add(QuickFixFactory.getInstance().createModifierListFix(method, PsiModifier.STATIC, true, false)); + } + } + } + else if (isExtension) { + description = JavaErrorBundle.message("extension.method.in.class"); + } + else if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { + description = JavaErrorBundle.message("abstract.methods.cannot.have.a.body"); + } + else if (method.hasModifierProperty(PsiModifier.NATIVE)) { + description = JavaErrorBundle.message("native.methods.cannot.have.a.body"); + } + if (description == null) { + return null; + } - PsiClass aClass = method.getContainingClass(); - if (aClass == null) { - return null; - } - final HierarchicalMethodSignature methodSignature = PsiSuperMethodImplUtil.getHierarchicalMethodSignature(method); - final List superSignatures = methodSignature.getSuperSignatures(); - if (superSignatures.isEmpty()) { - return null; + TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); + HighlightInfo info = + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + if (!hasNoBody) { + QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createDeleteMethodBodyFix(method)); + } + if (method.hasModifierProperty(PsiModifier.ABSTRACT) && !isInterface) { + QuickFixAction.registerQuickFixAction( + info, + QuickFixFactory.getInstance().createModifierListFix(method, PsiModifier.ABSTRACT, false, false) + ); + } + for (IntentionAction intentionAction : additionalFixes) { + QuickFixAction.registerQuickFixAction(info, intentionAction); + } + return info; } - boolean isStatic = method.hasModifierProperty(PsiModifier.STATIC); - for (HierarchicalMethodSignature signature : superSignatures) { - final PsiMethod superMethod = signature.getMethod(); - final PsiClass superClass = superMethod.getContainingClass(); - if (superClass == null) { - continue; - } - final HighlightInfo highlightInfo = checkStaticMethodOverride(aClass, method, isStatic, superClass, superMethod, containingFile); - if (highlightInfo != null) { - return highlightInfo; - } - } - return null; - } - - private static HighlightInfo checkStaticMethodOverride(PsiClass aClass, - PsiMethod method, - boolean isMethodStatic, - PsiClass superClass, - PsiMethod superMethod, - @Nonnull PsiFile containingFile) { - if (superMethod == null) { - return null; - } - PsiManager manager = containingFile.getManager(); - PsiModifierList superModifierList = superMethod.getModifierList(); - PsiModifierList modifierList = method.getModifierList(); - if (superModifierList.hasModifierProperty(PsiModifier.PRIVATE)) { - return null; - } - if (superModifierList.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) && !JavaPsiFacade.getInstance(manager.getProject()) - .arePackagesTheSame(aClass, superClass)) { - return null; - } - boolean isSuperMethodStatic = superModifierList.hasModifierProperty(PsiModifier.STATIC); - if (isMethodStatic != isSuperMethodStatic) { - TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); - @NonNls final String messageKey = - isMethodStatic ? "static.method.cannot.override.instance.method" : "instance.method.cannot.override.static.method"; - - String description = JavaErrorBundle.message(messageKey, - JavaHighlightUtil.formatMethod(method), - HighlightUtil.formatClass(aClass), - JavaHighlightUtil.formatMethod(superMethod), - HighlightUtil.formatClass(superClass)); - - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - if (!isSuperMethodStatic || HighlightUtil.getIncompatibleModifier(PsiModifier.STATIC, modifierList) == null) { - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance() - .createModifierListFix(method, - PsiModifier.STATIC, - isSuperMethodStatic, - false)); - } - if (manager.isInProject(superMethod) && (!isMethodStatic || HighlightUtil.getIncompatibleModifier(PsiModifier.STATIC, - superModifierList) == null)) { - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance() - .createModifierListFix(superMethod, - PsiModifier.STATIC, - isMethodStatic, - true)); - } - return info; + @Nullable + public static HighlightInfo checkConstructorCallMustBeFirstStatement(@Nonnull PsiMethodCallExpression methodCall) { + if (!RefactoringChangeUtil.isSuperOrThisMethodCall(methodCall)) { + return null; + } + PsiElement codeBlock = methodCall.getParent().getParent(); + if (codeBlock instanceof PsiCodeBlock && codeBlock.getParent() instanceof PsiMethod && ((PsiMethod)codeBlock.getParent()).isConstructor()) { + PsiElement prevSibling = methodCall.getParent().getPrevSibling(); + while (true) { + if (prevSibling == null) { + return null; + } + if (prevSibling instanceof PsiStatement) { + break; + } + prevSibling = prevSibling.getPrevSibling(); + } + } + PsiReferenceExpression expression = methodCall.getMethodExpression(); + String message = JavaErrorBundle.message("constructor.call.must.be.first.statement", expression.getText() + "()"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(methodCall) + .descriptionAndTooltip(message) + .create(); } - if (isMethodStatic) { - if (superClass.isInterface()) { + + public static HighlightInfo checkSuperAbstractMethodDirectCall(@Nonnull PsiMethodCallExpression methodCallExpression) { + PsiReferenceExpression expression = methodCallExpression.getMethodExpression(); + if (!(expression.getQualifierExpression() instanceof PsiSuperExpression)) { + return null; + } + PsiMethod method = methodCallExpression.resolveMethod(); + if (method != null && method.hasModifierProperty(PsiModifier.ABSTRACT)) { + String message = JavaErrorBundle.message("direct.abstract.method.access", JavaHighlightUtil.formatMethod(method)); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(methodCallExpression) + .descriptionAndTooltip(message) + .create(); + } return null; - } - int accessLevel = PsiUtil.getAccessLevel(modifierList); - String accessModifier = PsiUtil.getAccessModifier(accessLevel); - HighlightInfo info = isWeaker(method, modifierList, accessModifier, accessLevel, superMethod, true); - if (info != null) { - return info; - } - info = checkSuperMethodIsFinal(method, superMethod); - if (info != null) { - return info; - } } - return null; - } - private static HighlightInfo checkInterfaceInheritedMethodsReturnTypes(@Nonnull List superMethodSignatures, - @Nonnull LanguageLevel languageLevel) { - if (superMethodSignatures.size() < 2) { - return null; - } - final MethodSignatureBackedByPsiMethod[] returnTypeSubstitutable = {superMethodSignatures.get(0)}; - for (int i = 1; i < superMethodSignatures.size(); i++) { - PsiMethod currentMethod = returnTypeSubstitutable[0].getMethod(); - PsiType currentType = returnTypeSubstitutable[0].getSubstitutor().substitute(currentMethod.getReturnType()); - - MethodSignatureBackedByPsiMethod otherSuperSignature = superMethodSignatures.get(i); - PsiMethod otherSuperMethod = otherSuperSignature.getMethod(); - PsiSubstitutor otherSubstitutor = otherSuperSignature.getSubstitutor(); - PsiType otherSuperReturnType = otherSubstitutor.substitute(otherSuperMethod.getReturnType()); - PsiSubstitutor unifyingSubstitutor = - MethodSignatureUtil.getSuperMethodSignatureSubstitutor(returnTypeSubstitutable[0], otherSuperSignature); - if (unifyingSubstitutor != null) { - otherSuperReturnType = unifyingSubstitutor.substitute(otherSuperReturnType); - currentType = unifyingSubstitutor.substitute(currentType); - } - - if (otherSuperReturnType == null || currentType == null || otherSuperReturnType.equals(currentType)) { - continue; - } - PsiType otherReturnType = otherSuperReturnType; - PsiType curType = currentType; - final HighlightInfo info = - LambdaUtil.performWithSubstitutedParameterBounds(otherSuperMethod.getTypeParameters(), otherSubstitutor, () -> - { - if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5)) { - //http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8 Example 8.1.5-3 - if (!(otherReturnType instanceof PsiPrimitiveType || curType instanceof PsiPrimitiveType)) { - if (otherReturnType.isAssignableFrom(curType)) { - return null; - } - if (curType.isAssignableFrom(otherReturnType)) { - returnTypeSubstitutable[0] = otherSuperSignature; - return null; - } - } - if (otherSuperMethod.getTypeParameters().length > 0 && JavaGenericsUtil.isRawToGeneric(otherReturnType, curType)) { - return null; - } - } - return createIncompatibleReturnTypeMessage(otherSuperMethod, - currentMethod, - curType, - otherReturnType, - JavaErrorBundle.message("unrelated.overriding.methods.return.types"), - TextRange.EMPTY_RANGE); - }); - if (info != null) { + public static HighlightInfo checkConstructorCallsBaseClassConstructor( + PsiMethod constructor, + RefCountHolder refCountHolder, + PsiResolveHelper resolveHelper + ) { + if (!constructor.isConstructor()) { + return null; + } + PsiClass aClass = constructor.getContainingClass(); + if (aClass == null) { + return null; + } + if (aClass.isEnum()) { + return null; + } + PsiCodeBlock body = constructor.getBody(); + if (body == null) { + return null; + } + + // check whether constructor call super(...) or this(...) + PsiElement element = new PsiMatcherImpl(body).firstChild(PsiMatchers.hasClass(PsiExpressionStatement.class)) + .firstChild(PsiMatchers.hasClass(PsiMethodCallExpression.class)) + .firstChild + (PsiMatchers.hasClass(PsiReferenceExpression.class)) + .firstChild(PsiMatchers.hasClass(PsiKeyword.class)) + .getElement(); + if (element != null) { + return null; + } + TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(constructor); + PsiClassType[] handledExceptions = constructor.getThrowsList().getReferencedTypes(); + HighlightInfo info = + HighlightClassUtil.checkBaseClassDefaultConstructorProblem(aClass, refCountHolder, resolveHelper, textRange, handledExceptions); + if (info != null) { + QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createInsertSuperFix(constructor)); + QuickFixAction.registerQuickFixAction( + info, + QuickFixFactory.getInstance().createAddDefaultConstructorFix(aClass.getSuperClass()) + ); + } return info; - } - } - return null; - } - - public static HighlightInfo checkOverrideEquivalentInheritedMethods(PsiClass aClass, - PsiFile containingFile, - @Nonnull LanguageLevel languageLevel) { - String description = null; - boolean appendImplementMethodFix = true; - final Collection visibleSignatures = aClass.getVisibleSignatures(); - PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(aClass.getProject()).getResolveHelper(); - Ultimate: - for (HierarchicalMethodSignature signature : visibleSignatures) { - PsiMethod method = signature.getMethod(); - if (!resolveHelper.isAccessible(method, aClass, null)) { - continue; - } - List superSignatures = signature.getSuperSignatures(); - - boolean allAbstracts = method.hasModifierProperty(PsiModifier.ABSTRACT); - final PsiClass containingClass = method.getContainingClass(); - if (aClass.equals(containingClass)) { - continue; //to be checked at method level - } - - if (aClass.isInterface() && !containingClass.isInterface()) { - continue; - } - HighlightInfo highlightInfo; - if (allAbstracts) { - superSignatures = new ArrayList<>(superSignatures); - superSignatures.add(0, signature); - highlightInfo = checkInterfaceInheritedMethodsReturnTypes(superSignatures, languageLevel); - } - else { - highlightInfo = checkMethodIncompatibleReturnType(signature, superSignatures, false); - } - if (highlightInfo != null) { - description = highlightInfo.getDescription(); - } - - if (method.hasModifierProperty(PsiModifier.STATIC)) { - for (HierarchicalMethodSignature superSignature : superSignatures) { - PsiMethod superMethod = superSignature.getMethod(); - if (!superMethod.hasModifierProperty(PsiModifier.STATIC)) { - description = JavaErrorBundle.message("static.method.cannot.override.instance.method", - JavaHighlightUtil.formatMethod(method), - HighlightUtil.formatClass(containingClass), - JavaHighlightUtil.formatMethod(superMethod), - HighlightUtil.formatClass(superMethod.getContainingClass())); - appendImplementMethodFix = false; - break Ultimate; - } - } - continue; - } - - if (description == null) { - highlightInfo = checkMethodIncompatibleThrows(signature, superSignatures, false, aClass); - if (highlightInfo != null) { - description = highlightInfo.getDescription(); - } - } - - if (description == null) { - highlightInfo = checkMethodWeakerPrivileges(signature, superSignatures, false, containingFile); - if (highlightInfo != null) { - description = highlightInfo.getDescription(); - } - } - - if (description != null) { - break; - } } - if (description != null) { - // show error info at the class level - TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - final HighlightInfo highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - if (appendImplementMethodFix) { - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance().createImplementMethodsFix(aClass)); - } - return highlightInfo; - } - return null; - } + /** + * @return error if static method overrides instance method or + * instance method overrides static. see JLS 8.4.6.1, 8.4.6.2 + */ + public static HighlightInfo checkStaticMethodOverride(@Nonnull PsiMethod method, @Nonnull PsiFile containingFile) { + // constructors are not members and therefor don't override class methods + if (method.isConstructor()) { + return null; + } + PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return null; + } + final HierarchicalMethodSignature methodSignature = PsiSuperMethodImplUtil.getHierarchicalMethodSignature(method); + final List superSignatures = methodSignature.getSuperSignatures(); + if (superSignatures.isEmpty()) { + return null; + } - public static HighlightInfo checkConstructorHandleSuperClassExceptions(PsiMethod method) { - if (!method.isConstructor()) { - return null; - } - PsiCodeBlock body = method.getBody(); - PsiStatement[] statements = body == null ? null : body.getStatements(); - if (statements == null) { - return null; + boolean isStatic = method.hasModifierProperty(PsiModifier.STATIC); + for (HierarchicalMethodSignature signature : superSignatures) { + final PsiMethod superMethod = signature.getMethod(); + final PsiClass superClass = superMethod.getContainingClass(); + if (superClass == null) { + continue; + } + final HighlightInfo highlightInfo = + checkStaticMethodOverride(aClass, method, isStatic, superClass, superMethod, containingFile); + if (highlightInfo != null) { + return highlightInfo; + } + } + return null; } - // if we have unhandled exception inside method body, we could not have been called here, - // so the only problem it can catch here is with super ctr only - Collection unhandled = ExceptionUtil.collectUnhandledExceptions(method, method.getContainingClass()); - if (unhandled.isEmpty()) { - return null; - } - String description = HighlightUtil.getUnhandledExceptionsDescriptor(unhandled); - TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); - HighlightInfo highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - for (PsiClassType exception : unhandled) { - QuickFixAction.registerQuickFixAction(highlightInfo, new LocalQuickFixOnPsiElementAsIntentionAdapter(QuickFixFactory.getInstance() - .createMethodThrowsFix( - method, - exception, - true, - false))); + private static HighlightInfo checkStaticMethodOverride( + PsiClass aClass, + PsiMethod method, + boolean isMethodStatic, + PsiClass superClass, + PsiMethod superMethod, + @Nonnull PsiFile containingFile + ) { + if (superMethod == null) { + return null; + } + PsiManager manager = containingFile.getManager(); + PsiModifierList superModifierList = superMethod.getModifierList(); + PsiModifierList modifierList = method.getModifierList(); + if (superModifierList.hasModifierProperty(PsiModifier.PRIVATE)) { + return null; + } + if (superModifierList.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) && !JavaPsiFacade.getInstance(manager.getProject()) + .arePackagesTheSame(aClass, superClass)) { + return null; + } + boolean isSuperMethodStatic = superModifierList.hasModifierProperty(PsiModifier.STATIC); + if (isMethodStatic != isSuperMethodStatic) { + TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); + @NonNls final String messageKey = isMethodStatic + ? "static.method.cannot.override.instance.method" + : "instance.method.cannot.override.static.method"; + + String description = JavaErrorBundle.message( + messageKey, + JavaHighlightUtil.formatMethod(method), + HighlightUtil.formatClass(aClass), + JavaHighlightUtil.formatMethod(superMethod), + HighlightUtil.formatClass(superClass) + ); + + HighlightInfo info = + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + if (!isSuperMethodStatic || HighlightUtil.getIncompatibleModifier(PsiModifier.STATIC, modifierList) == null) { + QuickFixAction.registerQuickFixAction( + info, + QuickFixFactory.getInstance().createModifierListFix( + method, + PsiModifier.STATIC, + isSuperMethodStatic, + false + ) + ); + } + if (manager.isInProject(superMethod) + && (!isMethodStatic || HighlightUtil.getIncompatibleModifier(PsiModifier.STATIC, superModifierList) == null)) { + QuickFixAction.registerQuickFixAction( + info, + QuickFixFactory.getInstance().createModifierListFix( + superMethod, + PsiModifier.STATIC, + isMethodStatic, + true + ) + ); + } + return info; + } + + if (isMethodStatic) { + if (superClass.isInterface()) { + return null; + } + int accessLevel = PsiUtil.getAccessLevel(modifierList); + String accessModifier = PsiUtil.getAccessModifier(accessLevel); + HighlightInfo info = isWeaker(method, modifierList, accessModifier, accessLevel, superMethod, true); + if (info != null) { + return info; + } + info = checkSuperMethodIsFinal(method, superMethod); + if (info != null) { + return info; + } + } + return null; } - return highlightInfo; - } + private static HighlightInfo checkInterfaceInheritedMethodsReturnTypes( + @Nonnull List superMethodSignatures, + @Nonnull LanguageLevel languageLevel + ) { + if (superMethodSignatures.size() < 2) { + return null; + } + final MethodSignatureBackedByPsiMethod[] returnTypeSubstitutable = {superMethodSignatures.get(0)}; + for (int i = 1; i < superMethodSignatures.size(); i++) { + PsiMethod currentMethod = returnTypeSubstitutable[0].getMethod(); + PsiType currentType = returnTypeSubstitutable[0].getSubstitutor().substitute(currentMethod.getReturnType()); + + MethodSignatureBackedByPsiMethod otherSuperSignature = superMethodSignatures.get(i); + PsiMethod otherSuperMethod = otherSuperSignature.getMethod(); + PsiSubstitutor otherSubstitutor = otherSuperSignature.getSubstitutor(); + PsiType otherSuperReturnType = otherSubstitutor.substitute(otherSuperMethod.getReturnType()); + PsiSubstitutor unifyingSubstitutor = + MethodSignatureUtil.getSuperMethodSignatureSubstitutor(returnTypeSubstitutable[0], otherSuperSignature); + if (unifyingSubstitutor != null) { + otherSuperReturnType = unifyingSubstitutor.substitute(otherSuperReturnType); + currentType = unifyingSubstitutor.substitute(currentType); + } - public static HighlightInfo checkRecursiveConstructorInvocation(@Nonnull PsiMethod method) { - if (HighlightControlFlowUtil.isRecursivelyCalledConstructor(method)) { - TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); - String description = JavaErrorBundle.message("recursive.constructor.invocation"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - } - return null; - } - - @Nonnull - public static TextRange getFixRange(@Nonnull PsiElement element) { - TextRange range = element.getTextRange(); - int start = range.getStartOffset(); - int end = range.getEndOffset(); - - PsiElement nextSibling = element.getNextSibling(); - if (nextSibling instanceof PsiJavaToken && ((PsiJavaToken)nextSibling).getTokenType() == JavaTokenType.SEMICOLON) { - return new TextRange(start, end + 1); + if (otherSuperReturnType == null || currentType == null || otherSuperReturnType.equals(currentType)) { + continue; + } + PsiType otherReturnType = otherSuperReturnType; + PsiType curType = currentType; + final HighlightInfo info = + LambdaUtil.performWithSubstitutedParameterBounds(otherSuperMethod.getTypeParameters(), otherSubstitutor, () -> + { + if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5)) { + //http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8 Example 8.1.5-3 + if (!(otherReturnType instanceof PsiPrimitiveType || curType instanceof PsiPrimitiveType)) { + if (otherReturnType.isAssignableFrom(curType)) { + return null; + } + if (curType.isAssignableFrom(otherReturnType)) { + returnTypeSubstitutable[0] = otherSuperSignature; + return null; + } + } + if (otherSuperMethod.getTypeParameters().length > 0 && JavaGenericsUtil.isRawToGeneric(otherReturnType, curType)) { + return null; + } + } + return createIncompatibleReturnTypeMessage( + otherSuperMethod, + currentMethod, + curType, + otherReturnType, + JavaErrorBundle.message("unrelated.overriding.methods.return.types"), + TextRange.EMPTY_RANGE + ); + }); + if (info != null) { + return info; + } + } + return null; } - return range; - } + public static HighlightInfo checkOverrideEquivalentInheritedMethods( + PsiClass aClass, + PsiFile containingFile, + @Nonnull LanguageLevel languageLevel + ) { + String description = null; + boolean appendImplementMethodFix = true; + final Collection visibleSignatures = aClass.getVisibleSignatures(); + PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(aClass.getProject()).getResolveHelper(); + Ultimate: + for (HierarchicalMethodSignature signature : visibleSignatures) { + PsiMethod method = signature.getMethod(); + if (!resolveHelper.isAccessible(method, aClass, null)) { + continue; + } + List superSignatures = signature.getSuperSignatures(); - public static void checkNewExpression(@Nonnull PsiNewExpression expression, - PsiType type, - @Nonnull HighlightInfoHolder holder, - @Nonnull JavaSdkVersion javaSdkVersion) { - if (!(type instanceof PsiClassType)) { - return; - } - PsiClassType.ClassResolveResult typeResult = ((PsiClassType)type).resolveGenerics(); - PsiClass aClass = typeResult.getElement(); - if (aClass == null) { - return; - } - if (aClass instanceof PsiAnonymousClass) { - type = ((PsiAnonymousClass)aClass).getBaseClassType(); - typeResult = ((PsiClassType)type).resolveGenerics(); - aClass = typeResult.getElement(); - if (aClass == null) { - return; - } - } + boolean allAbstracts = method.hasModifierProperty(PsiModifier.ABSTRACT); + final PsiClass containingClass = method.getContainingClass(); + if (aClass.equals(containingClass)) { + continue; //to be checked at method level + } - PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference(); - checkConstructorCall(typeResult, expression, type, classReference, holder, javaSdkVersion); - } + if (aClass.isInterface() && !containingClass.isInterface()) { + continue; + } + HighlightInfo highlightInfo; + if (allAbstracts) { + superSignatures = new ArrayList<>(superSignatures); + superSignatures.add(0, signature); + highlightInfo = checkInterfaceInheritedMethodsReturnTypes(superSignatures, languageLevel); + } + else { + highlightInfo = checkMethodIncompatibleReturnType(signature, superSignatures, false); + } + if (highlightInfo != null) { + description = highlightInfo.getDescription(); + } + if (method.hasModifierProperty(PsiModifier.STATIC)) { + for (HierarchicalMethodSignature superSignature : superSignatures) { + PsiMethod superMethod = superSignature.getMethod(); + if (!superMethod.hasModifierProperty(PsiModifier.STATIC)) { + description = JavaErrorBundle.message( + "static.method.cannot.override.instance.method", + JavaHighlightUtil.formatMethod(method), + HighlightUtil.formatClass(containingClass), + JavaHighlightUtil.formatMethod(superMethod), + HighlightUtil.formatClass(superMethod.getContainingClass()) + ); + appendImplementMethodFix = false; + break Ultimate; + } + } + continue; + } - public static void checkConstructorCall(@Nonnull PsiClassType.ClassResolveResult typeResolveResult, - @Nonnull PsiConstructorCall constructorCall, - @Nonnull PsiType type, - PsiJavaCodeReferenceElement classReference, - @Nonnull HighlightInfoHolder holder, - @Nonnull JavaSdkVersion javaSdkVersion) { - PsiExpressionList list = constructorCall.getArgumentList(); - if (list == null) { - return; - } - PsiClass aClass = typeResolveResult.getElement(); - if (aClass == null) { - return; + if (description == null) { + highlightInfo = checkMethodIncompatibleThrows(signature, superSignatures, false, aClass); + if (highlightInfo != null) { + description = highlightInfo.getDescription(); + } + } + + if (description == null) { + highlightInfo = checkMethodWeakerPrivileges(signature, superSignatures, false, containingFile); + if (highlightInfo != null) { + description = highlightInfo.getDescription(); + } + } + + if (description != null) { + break; + } + } + + if (description != null) { + // show error info at the class level + TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); + final HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(textRange) + .descriptionAndTooltip(description) + .create(); + if (appendImplementMethodFix) { + QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance().createImplementMethodsFix(aClass)); + } + return highlightInfo; + } + return null; } - final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(holder.getProject()).getResolveHelper(); - PsiClass accessObjectClass = null; - if (constructorCall instanceof PsiNewExpression) { - PsiExpression qualifier = ((PsiNewExpression)constructorCall).getQualifier(); - if (qualifier != null) { - accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass(qualifier).getElement(); - } + + public static HighlightInfo checkConstructorHandleSuperClassExceptions(PsiMethod method) { + if (!method.isConstructor()) { + return null; + } + PsiCodeBlock body = method.getBody(); + PsiStatement[] statements = body == null ? null : body.getStatements(); + if (statements == null) { + return null; + } + + // if we have unhandled exception inside method body, we could not have been called here, + // so the only problem it can catch here is with super ctr only + Collection unhandled = ExceptionUtil.collectUnhandledExceptions(method, method.getContainingClass()); + if (unhandled.isEmpty()) { + return null; + } + String description = HighlightUtil.getUnhandledExceptionsDescriptor(unhandled); + TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); + HighlightInfo highlightInfo = + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + for (PsiClassType exception : unhandled) { + QuickFixAction.registerQuickFixAction( + highlightInfo, + new LocalQuickFixOnPsiElementAsIntentionAdapter( + QuickFixFactory.getInstance().createMethodThrowsFix( + method, + exception, + true, + false + ) + ) + ); + } + return highlightInfo; } - if (classReference != null && !resolveHelper.isAccessible(aClass, constructorCall, accessObjectClass)) { - String description = HighlightUtil.buildProblemWithAccessDescription(classReference, typeResolveResult); - PsiElement element = classReference.getReferenceNameElement(); - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); - HighlightUtil.registerAccessQuickFixAction(aClass, classReference, info, null); - holder.add(info); - return; + + + public static HighlightInfo checkRecursiveConstructorInvocation(@Nonnull PsiMethod method) { + if (HighlightControlFlowUtil.isRecursivelyCalledConstructor(method)) { + TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); + String description = JavaErrorBundle.message("recursive.constructor.invocation"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + } + return null; } - PsiMethod[] constructors = aClass.getConstructors(); - - if (constructors.length == 0) { - if (list.getExpressions().length != 0) { - String constructorName = aClass.getName(); - String argTypes = buildArgTypesList(list); - String description = JavaErrorBundle.message("wrong.constructor.arguments", constructorName + "()", argTypes); - String tooltip = - createMismatchedArgumentsHtmlTooltip(list, null, PsiParameter.EMPTY_ARRAY, constructorName, PsiSubstitutor.EMPTY, aClass); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(list) - .description(description) - .escapedToolTip(tooltip) - .navigationShift(+1) - .create(); - QuickFixAction.registerQuickFixAction(info, constructorCall.getTextRange(), QuickFixFactory.getInstance() - .createCreateConstructorFromCallFix( - constructorCall)); - if (classReference != null) { - ConstructorParametersFixer.registerFixActions(classReference, constructorCall, info, getFixRange(list)); - } - holder.add(info); - return; - } - if (classReference != null && aClass.hasModifierProperty(PsiModifier.PROTECTED) && callingProtectedConstructorFromDerivedClass( - constructorCall, - aClass)) { - holder.add(buildAccessProblem(classReference, typeResolveResult, aClass)); - } - else if (aClass.isInterface() && constructorCall instanceof PsiNewExpression) { - final PsiReferenceParameterList typeArgumentList = ((PsiNewExpression)constructorCall).getTypeArgumentList(); - if (typeArgumentList.getTypeArguments().length > 0) { - holder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(typeArgumentList) - .descriptionAndTooltip("Anonymous class implements interface; cannot have type " + - "arguments") - .create()); - } - } + + @Nonnull + public static TextRange getFixRange(@Nonnull PsiElement element) { + TextRange range = element.getTextRange(); + int start = range.getStartOffset(); + int end = range.getEndOffset(); + + PsiElement nextSibling = element.getNextSibling(); + if (nextSibling instanceof PsiJavaToken && ((PsiJavaToken)nextSibling).getTokenType() == JavaTokenType.SEMICOLON) { + return new TextRange(start, end + 1); + } + return range; } - else { - PsiElement place = list; - if (constructorCall instanceof PsiNewExpression) { - final PsiAnonymousClass anonymousClass = ((PsiNewExpression)constructorCall).getAnonymousClass(); - if (anonymousClass != null) { - place = anonymousClass; - } - } - - JavaResolveResult[] results = resolveHelper.multiResolveConstructor((PsiClassType)type, list, place); - MethodCandidateInfo result = null; - if (results.length == 1) { - result = (MethodCandidateInfo)results[0]; - } - - PsiMethod constructor = result == null ? null : result.getElement(); - - boolean applicable = true; - try { - final PsiDiamondType diamondType = - constructorCall instanceof PsiNewExpression ? PsiDiamondType.getDiamondType((PsiNewExpression)constructorCall) : null; - final JavaResolveResult staticFactory = diamondType != null ? diamondType.getStaticFactory() : null; - applicable = - staticFactory instanceof MethodCandidateInfo ? ((MethodCandidateInfo)staticFactory).isApplicable() : result != null && result.isApplicable(); - } - catch (IndexNotReadyException e) { - // ignore - } - - PsiElement infoElement = list.getTextLength() > 0 ? list : constructorCall; - if (constructor == null) { - String name = aClass.getName(); - name += buildArgTypesList(list); - String description = JavaErrorBundle.message("cannot.resolve.constructor", name); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(list) - .descriptionAndTooltip(description) - .navigationShift(+1) - .create(); - if (info != null) { - WrapExpressionFix.registerWrapAction(results, list.getExpressions(), info); - registerFixesOnInvalidConstructorCall(constructorCall, classReference, list, aClass, constructors, results, infoElement, info); - holder.add(info); - } - } - else { - if (classReference != null && (!result.isAccessible() || constructor.hasModifierProperty(PsiModifier.PROTECTED) && callingProtectedConstructorFromDerivedClass( - constructorCall, - aClass))) { - holder.add(buildAccessProblem(classReference, result, constructor)); - } - else if (!applicable) { - String constructorName = HighlightMessageUtil.getSymbolName(constructor, result.getSubstitutor()); - String containerName = HighlightMessageUtil.getSymbolName(constructor.getContainingClass(), result.getSubstitutor()); - String argTypes = buildArgTypesList(list); - String description = JavaErrorBundle.message("wrong.method.arguments", constructorName, containerName, argTypes); - String toolTip = createMismatchedArgumentsHtmlTooltip(result, list); - - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(infoElement) - .description(description) - .escapedToolTip(toolTip) - .navigationShift(+1) - .create(); - if (info != null) { - JavaResolveResult[] methodCandidates = results; - if (constructorCall instanceof PsiNewExpression) { - methodCandidates = resolveHelper.getReferencedMethodCandidates((PsiCallExpression)constructorCall, true); - } - registerFixesOnInvalidConstructorCall(constructorCall, - classReference, - list, - aClass, - constructors, - methodCandidates, - infoElement, - info); - registerMethodReturnFixAction(info, result, constructorCall); + + public static void checkNewExpression( + @Nonnull PsiNewExpression expression, + PsiType type, + @Nonnull HighlightInfoHolder holder, + @Nonnull JavaSdkVersion javaSdkVersion + ) { + if (!(type instanceof PsiClassType)) { + return; + } + PsiClassType.ClassResolveResult typeResult = ((PsiClassType)type).resolveGenerics(); + PsiClass aClass = typeResult.getElement(); + if (aClass == null) { + return; + } + if (aClass instanceof PsiAnonymousClass) { + type = ((PsiAnonymousClass)aClass).getBaseClassType(); + typeResult = ((PsiClassType)type).resolveGenerics(); + aClass = typeResult.getElement(); + if (aClass == null) { + return; + } + } + + PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference(); + checkConstructorCall(typeResult, expression, type, classReference, holder, javaSdkVersion); + } + + public static void checkConstructorCall( + @Nonnull PsiClassType.ClassResolveResult typeResolveResult, + @Nonnull PsiConstructorCall constructorCall, + @Nonnull PsiType type, + PsiJavaCodeReferenceElement classReference, + @Nonnull HighlightInfoHolder holder, + @Nonnull JavaSdkVersion javaSdkVersion + ) { + PsiExpressionList list = constructorCall.getArgumentList(); + if (list == null) { + return; + } + PsiClass aClass = typeResolveResult.getElement(); + if (aClass == null) { + return; + } + final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(holder.getProject()).getResolveHelper(); + PsiClass accessObjectClass = null; + if (constructorCall instanceof PsiNewExpression) { + PsiExpression qualifier = ((PsiNewExpression)constructorCall).getQualifier(); + if (qualifier != null) { + accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass(qualifier).getElement(); + } + } + if (classReference != null && !resolveHelper.isAccessible(aClass, constructorCall, accessObjectClass)) { + String description = HighlightUtil.buildProblemWithAccessDescription(classReference, typeResolveResult); + PsiElement element = classReference.getReferenceNameElement(); + HighlightInfo info = + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); + HighlightUtil.registerAccessQuickFixAction(aClass, classReference, info, null); holder.add(info); - } + return; } - else { - if (constructorCall instanceof PsiNewExpression) { - PsiReferenceParameterList typeArgumentList = ((PsiNewExpression)constructorCall).getTypeArgumentList(); - HighlightInfo info = GenericsHighlightUtil.checkReferenceTypeArgumentList(constructor, - typeArgumentList, - result.getSubstitutor(), - false, - javaSdkVersion); - if (info != null) { - holder.add(info); + PsiMethod[] constructors = aClass.getConstructors(); + + if (constructors.length == 0) { + if (list.getExpressions().length != 0) { + String constructorName = aClass.getName(); + String argTypes = buildArgTypesList(list); + String description = JavaErrorBundle.message("wrong.constructor.arguments", constructorName + "()", argTypes); + String tooltip = createMismatchedArgumentsHtmlTooltip( + list, + null, + PsiParameter.EMPTY_ARRAY, + constructorName, + PsiSubstitutor.EMPTY, + aClass + ); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(list) + .description(description) + .escapedToolTip(tooltip) + .navigationShift(+1) + .create(); + QuickFixAction.registerQuickFixAction( + info, + constructorCall.getTextRange(), + QuickFixFactory.getInstance().createCreateConstructorFromCallFix(constructorCall) + ); + if (classReference != null) { + ConstructorParametersFixer.registerFixActions(classReference, constructorCall, info, getFixRange(list)); + } + holder.add(info); + return; + } + if (classReference != null && aClass.hasModifierProperty(PsiModifier.PROTECTED) + && callingProtectedConstructorFromDerivedClass(constructorCall, aClass)) { + holder.add(buildAccessProblem(classReference, typeResolveResult, aClass)); + } + else if (aClass.isInterface() && constructorCall instanceof PsiNewExpression) { + final PsiReferenceParameterList typeArgumentList = ((PsiNewExpression)constructorCall).getTypeArgumentList(); + if (typeArgumentList.getTypeArguments().length > 0) { + holder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeArgumentList) + .descriptionAndTooltip("Anonymous class implements interface; cannot have type arguments") + .create()); + } } - } } - } + else { + PsiElement place = list; + if (constructorCall instanceof PsiNewExpression) { + final PsiAnonymousClass anonymousClass = ((PsiNewExpression)constructorCall).getAnonymousClass(); + if (anonymousClass != null) { + place = anonymousClass; + } + } - if (result != null && !holder.hasErrorResults()) { - holder.add(checkVarargParameterErasureToBeAccessible(result, constructorCall)); - } - } - } - - /** - * If the compile-time declaration is applicable by variable arity invocation, - * then where the last formal parameter type of the invocation type of the method is Fn[], - * it is a compile-time error if the type which is the erasure of Fn is not accessible at the point of invocation. - */ - private static HighlightInfo checkVarargParameterErasureToBeAccessible(MethodCandidateInfo info, PsiCall place) { - final PsiMethod method = info.getElement(); - if (info.isVarargs() || method.isVarArgs() && !PsiUtil.isLanguageLevel8OrHigher(place)) { - final PsiParameter[] parameters = method.getParameterList().getParameters(); - final PsiType componentType = ((PsiEllipsisType)parameters[parameters.length - 1].getType()).getComponentType(); - final PsiType substitutedTypeErasure = TypeConversionUtil.erasure(info.getSubstitutor().substitute(componentType)); - final PsiClass targetClass = PsiUtil.resolveClassInClassTypeOnly(substitutedTypeErasure); - if (targetClass != null && !PsiUtil.isAccessible(targetClass, place, null)) { - final PsiExpressionList argumentList = place.getArgumentList(); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .descriptionAndTooltip("Formal varargs element type " + PsiFormatUtil.formatClass(targetClass, PsiFormatUtilBase - .SHOW_FQ_NAME) + " is inaccessible here") - .range(argumentList != null ? argumentList : place) - .create(); - } - } - return null; - } - - private static void registerFixesOnInvalidConstructorCall(PsiConstructorCall constructorCall, - PsiJavaCodeReferenceElement classReference, - PsiExpressionList list, - PsiClass aClass, - PsiMethod[] constructors, - JavaResolveResult[] results, - PsiElement infoElement, - @Nonnull final HighlightInfo info) { - QuickFixAction.registerQuickFixAction(info, constructorCall.getTextRange(), QuickFixFactory.getInstance() - .createCreateConstructorFromCallFix( - constructorCall)); - if (classReference != null) { - ConstructorParametersFixer.registerFixActions(classReference, constructorCall, info, getFixRange(infoElement)); - ChangeTypeArgumentsFix.registerIntentions(results, list, info, aClass); - ConvertDoubleToFloatFix.registerIntentions(results, list, info, null); - } - registerChangeMethodSignatureFromUsageIntentions(results, list, info, null); - PermuteArgumentsFix.registerFix(info, constructorCall, toMethodCandidates(results), getFixRange(list)); - registerChangeParameterClassFix(constructorCall, list, info); - QuickFixAction.registerQuickFixAction(info, getFixRange(list), QuickFixFactory.getInstance() - .createSurroundWithArrayFix(constructorCall, null)); - ChangeStringLiteralToCharInMethodCallFix.registerFixes(constructors, constructorCall, info); - } - - private static HighlightInfo buildAccessProblem(@Nonnull PsiJavaCodeReferenceElement classReference, - JavaResolveResult result, - PsiMember elementToFix) { - String description = HighlightUtil.buildProblemWithAccessDescription(classReference, result); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(classReference) - .descriptionAndTooltip(description) - .navigationShift(+1) - .create(); - if (result.isStaticsScopeCorrect()) { - HighlightUtil.registerAccessQuickFixAction(elementToFix, classReference, info, result.getCurrentFileResolveScope()); - } - return info; - } + JavaResolveResult[] results = resolveHelper.multiResolveConstructor((PsiClassType)type, list, place); + MethodCandidateInfo result = null; + if (results.length == 1) { + result = (MethodCandidateInfo)results[0]; + } - private static boolean callingProtectedConstructorFromDerivedClass(PsiConstructorCall place, PsiClass constructorClass) { - if (constructorClass == null) { - return false; - } - // indirect instantiation via anonymous class is ok - if (place instanceof PsiNewExpression && ((PsiNewExpression)place).getAnonymousClass() != null) { - return false; - } - PsiElement curElement = place; - PsiClass containingClass = constructorClass.getContainingClass(); - while (true) { - PsiClass aClass = PsiTreeUtil.getParentOfType(curElement, PsiClass.class); - if (aClass == null) { - return false; - } - curElement = aClass; - if ((aClass.isInheritor(constructorClass, true) || containingClass != null && aClass.isInheritor(containingClass, - true)) && !JavaPsiFacade.getInstance( - aClass.getProject()) - .arePackagesTheSame( - aClass, - constructorClass)) { - return true; - } - } - } - - private static String buildArgTypesList(PsiExpressionList list) { - StringBuilder builder = new StringBuilder(); - builder.append("("); - PsiExpression[] args = list.getExpressions(); - for (int i = 0; i < args.length; i++) { - if (i > 0) { - builder.append(", "); - } - PsiType argType = args[i].getType(); - builder.append(argType != null ? JavaHighlightUtil.formatType(argType) : "?"); - } - builder.append(")"); - return builder.toString(); - } - - private static void registerChangeParameterClassFix(@Nonnull PsiCall methodCall, - @Nonnull PsiExpressionList list, - HighlightInfo highlightInfo) { - final JavaResolveResult result = methodCall.resolveMethodGenerics(); - PsiMethod method = (PsiMethod)result.getElement(); - final PsiSubstitutor substitutor = result.getSubstitutor(); - PsiExpression[] expressions = list.getExpressions(); - if (method == null) { - return; + PsiMethod constructor = result == null ? null : result.getElement(); + + boolean applicable = true; + try { + final PsiDiamondType diamondType = + constructorCall instanceof PsiNewExpression ? PsiDiamondType.getDiamondType((PsiNewExpression)constructorCall) : null; + final JavaResolveResult staticFactory = diamondType != null ? diamondType.getStaticFactory() : null; + applicable = staticFactory instanceof MethodCandidateInfo + ? ((MethodCandidateInfo)staticFactory).isApplicable() + : result != null && result.isApplicable(); + } + catch (IndexNotReadyException e) { + // ignore + } + + PsiElement infoElement = list.getTextLength() > 0 ? list : constructorCall; + if (constructor == null) { + String name = aClass.getName(); + name += buildArgTypesList(list); + String description = JavaErrorBundle.message("cannot.resolve.constructor", name); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(list) + .descriptionAndTooltip(description) + .navigationShift(+1) + .create(); + if (info != null) { + WrapExpressionFix.registerWrapAction(results, list.getExpressions(), info); + registerFixesOnInvalidConstructorCall( + constructorCall, + classReference, + list, + aClass, + constructors, + results, + infoElement, + info + ); + holder.add(info); + } + } + else if (classReference != null && (!result.isAccessible() + || constructor.hasModifierProperty(PsiModifier.PROTECTED) + && callingProtectedConstructorFromDerivedClass(constructorCall, aClass))) { + holder.add(buildAccessProblem(classReference, result, constructor)); + } + else if (!applicable) { + String constructorName = HighlightMessageUtil.getSymbolName(constructor, result.getSubstitutor()); + String containerName = HighlightMessageUtil.getSymbolName(constructor.getContainingClass(), result.getSubstitutor()); + String argTypes = buildArgTypesList(list); + String description = JavaErrorBundle.message("wrong.method.arguments", constructorName, containerName, argTypes); + String toolTip = createMismatchedArgumentsHtmlTooltip(result, list); + + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(infoElement) + .description(description) + .escapedToolTip(toolTip) + .navigationShift(+1) + .create(); + if (info != null) { + JavaResolveResult[] methodCandidates = results; + if (constructorCall instanceof PsiNewExpression) { + methodCandidates = resolveHelper.getReferencedMethodCandidates((PsiCallExpression)constructorCall, true); + } + registerFixesOnInvalidConstructorCall( + constructorCall, + classReference, + list, + aClass, + constructors, + methodCandidates, + infoElement, + info + ); + registerMethodReturnFixAction(info, result, constructorCall); + holder.add(info); + } + } + else if (constructorCall instanceof PsiNewExpression) { + PsiReferenceParameterList typeArgumentList = ((PsiNewExpression)constructorCall).getTypeArgumentList(); + HighlightInfo info = GenericsHighlightUtil.checkReferenceTypeArgumentList( + constructor, + typeArgumentList, + result.getSubstitutor(), + false, + javaSdkVersion + ); + if (info != null) { + holder.add(info); + } + } + + if (result != null && !holder.hasErrorResults()) { + holder.add(checkVarargParameterErasureToBeAccessible(result, constructorCall)); + } + } } - final PsiParameter[] parameters = method.getParameterList().getParameters(); - if (parameters.length != expressions.length) { - return; + + /** + * If the compile-time declaration is applicable by variable arity invocation, + * then where the last formal parameter type of the invocation type of the method is Fn[], + * it is a compile-time error if the type which is the erasure of Fn is not accessible at the point of invocation. + */ + private static HighlightInfo checkVarargParameterErasureToBeAccessible(MethodCandidateInfo info, PsiCall place) { + final PsiMethod method = info.getElement(); + if (info.isVarargs() || method.isVarArgs() && !PsiUtil.isLanguageLevel8OrHigher(place)) { + final PsiParameter[] parameters = method.getParameterList().getParameters(); + final PsiType componentType = ((PsiEllipsisType)parameters[parameters.length - 1].getType()).getComponentType(); + final PsiType substitutedTypeErasure = TypeConversionUtil.erasure(info.getSubstitutor().substitute(componentType)); + final PsiClass targetClass = PsiUtil.resolveClassInClassTypeOnly(substitutedTypeErasure); + if (targetClass != null && !PsiUtil.isAccessible(targetClass, place, null)) { + final PsiExpressionList argumentList = place.getArgumentList(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .descriptionAndTooltip( + "Formal varargs element type " + PsiFormatUtil.formatClass(targetClass, PsiFormatUtilBase.SHOW_FQ_NAME) + + " is inaccessible here" + ) + .range(argumentList != null ? argumentList : place) + .create(); + } + } + return null; } - for (int i = 0; i < expressions.length; i++) { - final PsiExpression expression = expressions[i]; - final PsiParameter parameter = parameters[i]; - final PsiType expressionType = expression.getType(); - final PsiType parameterType = substitutor.substitute(parameter.getType()); - if (expressionType == null || expressionType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(expressionType) || expressionType instanceof PsiArrayType) { - continue; - } - if (parameterType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(parameterType) || parameterType instanceof PsiArrayType) { - continue; - } - if (parameterType.isAssignableFrom(expressionType)) { - continue; - } - PsiClass parameterClass = PsiUtil.resolveClassInType(parameterType); - PsiClass expressionClass = PsiUtil.resolveClassInType(expressionType); - if (parameterClass == null || expressionClass == null) { - continue; - } - if (expressionClass instanceof PsiAnonymousClass) { - continue; - } - if (parameterClass.isInheritor(expressionClass, true)) { - continue; - } - QuickFixAction.registerQuickFixAction(highlightInfo, - QuickFixFactory.getInstance() - .createChangeParameterClassFix(expressionClass, (PsiClassType)parameterType)); + + private static void registerFixesOnInvalidConstructorCall( + PsiConstructorCall constructorCall, + PsiJavaCodeReferenceElement classReference, + PsiExpressionList list, + PsiClass aClass, + PsiMethod[] constructors, + JavaResolveResult[] results, + PsiElement infoElement, + @Nonnull final HighlightInfo info + ) { + QuickFixAction.registerQuickFixAction(info, constructorCall.getTextRange(), QuickFixFactory.getInstance() + .createCreateConstructorFromCallFix(constructorCall)); + if (classReference != null) { + ConstructorParametersFixer.registerFixActions(classReference, constructorCall, info, getFixRange(infoElement)); + ChangeTypeArgumentsFix.registerIntentions(results, list, info, aClass); + ConvertDoubleToFloatFix.registerIntentions(results, list, info, null); + } + registerChangeMethodSignatureFromUsageIntentions(results, list, info, null); + PermuteArgumentsFix.registerFix(info, constructorCall, toMethodCandidates(results), getFixRange(list)); + registerChangeParameterClassFix(constructorCall, list, info); + QuickFixAction.registerQuickFixAction(info, getFixRange(list), QuickFixFactory.getInstance() + .createSurroundWithArrayFix(constructorCall, null)); + ChangeStringLiteralToCharInMethodCallFix.registerFixes(constructors, constructorCall, info); + } + + private static HighlightInfo buildAccessProblem( + @Nonnull PsiJavaCodeReferenceElement classReference, + JavaResolveResult result, + PsiMember elementToFix + ) { + String description = HighlightUtil.buildProblemWithAccessDescription(classReference, result); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(classReference) + .descriptionAndTooltip(description) + .navigationShift(+1) + .create(); + if (result.isStaticsScopeCorrect()) { + HighlightUtil.registerAccessQuickFixAction(elementToFix, classReference, info, result.getCurrentFileResolveScope()); + } + return info; } - } - - private static void registerChangeMethodSignatureFromUsageIntentions(@Nonnull JavaResolveResult[] candidates, - @Nonnull PsiExpressionList list, - @Nullable HighlightInfo highlightInfo, - TextRange fixRange) { - if (candidates.length == 0) { - return; + + private static boolean callingProtectedConstructorFromDerivedClass(PsiConstructorCall place, PsiClass constructorClass) { + if (constructorClass == null) { + return false; + } + // indirect instantiation via anonymous class is ok + if (place instanceof PsiNewExpression && ((PsiNewExpression)place).getAnonymousClass() != null) { + return false; + } + PsiElement curElement = place; + PsiClass containingClass = constructorClass.getContainingClass(); + while (true) { + PsiClass aClass = PsiTreeUtil.getParentOfType(curElement, PsiClass.class); + if (aClass == null) { + return false; + } + curElement = aClass; + if ((aClass.isInheritor(constructorClass, true) || containingClass != null + && aClass.isInheritor(containingClass, true)) + && !JavaPsiFacade.getInstance(aClass.getProject()).arePackagesTheSame(aClass, constructorClass)) { + return true; + } + } } - PsiExpression[] expressions = list.getExpressions(); - for (JavaResolveResult candidate : candidates) { - registerChangeMethodSignatureFromUsageIntention(expressions, highlightInfo, fixRange, candidate, list); + + private static String buildArgTypesList(PsiExpressionList list) { + StringBuilder builder = new StringBuilder(); + builder.append("("); + PsiExpression[] args = list.getExpressions(); + for (int i = 0; i < args.length; i++) { + if (i > 0) { + builder.append(", "); + } + PsiType argType = args[i].getType(); + builder.append(argType != null ? JavaHighlightUtil.formatType(argType) : "?"); + } + builder.append(")"); + return builder.toString(); + } + + private static void registerChangeParameterClassFix( + @Nonnull PsiCall methodCall, + @Nonnull PsiExpressionList list, + HighlightInfo highlightInfo + ) { + final JavaResolveResult result = methodCall.resolveMethodGenerics(); + PsiMethod method = (PsiMethod)result.getElement(); + final PsiSubstitutor substitutor = result.getSubstitutor(); + PsiExpression[] expressions = list.getExpressions(); + if (method == null) { + return; + } + final PsiParameter[] parameters = method.getParameterList().getParameters(); + if (parameters.length != expressions.length) { + return; + } + for (int i = 0; i < expressions.length; i++) { + final PsiExpression expression = expressions[i]; + final PsiParameter parameter = parameters[i]; + final PsiType expressionType = expression.getType(); + final PsiType parameterType = substitutor.substitute(parameter.getType()); + if (expressionType == null + || expressionType instanceof PsiPrimitiveType + || TypeConversionUtil.isNullType(expressionType) + || expressionType instanceof PsiArrayType) { + continue; + } + if (parameterType instanceof PsiPrimitiveType + || TypeConversionUtil.isNullType(parameterType) + || parameterType instanceof PsiArrayType) { + continue; + } + if (parameterType.isAssignableFrom(expressionType)) { + continue; + } + PsiClass parameterClass = PsiUtil.resolveClassInType(parameterType); + PsiClass expressionClass = PsiUtil.resolveClassInType(expressionType); + if (parameterClass == null || expressionClass == null) { + continue; + } + if (expressionClass instanceof PsiAnonymousClass) { + continue; + } + if (parameterClass.isInheritor(expressionClass, true)) { + continue; + } + QuickFixAction.registerQuickFixAction( + highlightInfo, + QuickFixFactory.getInstance() + .createChangeParameterClassFix(expressionClass, (PsiClassType)parameterType) + ); + } } - } - - private static void registerChangeMethodSignatureFromUsageIntention(@Nonnull PsiExpression[] expressions, - @Nullable HighlightInfo highlightInfo, - TextRange fixRange, - @Nonnull JavaResolveResult candidate, - @Nonnull PsiElement context) { - if (!candidate.isStaticsScopeCorrect()) { - return; + + private static void registerChangeMethodSignatureFromUsageIntentions( + @Nonnull JavaResolveResult[] candidates, + @Nonnull PsiExpressionList list, + @Nullable HighlightInfo highlightInfo, + TextRange fixRange + ) { + if (candidates.length == 0) { + return; + } + PsiExpression[] expressions = list.getExpressions(); + for (JavaResolveResult candidate : candidates) { + registerChangeMethodSignatureFromUsageIntention(expressions, highlightInfo, fixRange, candidate, list); + } } - PsiMethod method = (PsiMethod)candidate.getElement(); - PsiSubstitutor substitutor = candidate.getSubstitutor(); - if (method != null && context.getManager().isInProject(method)) { - IntentionAction fix = QuickFixFactory.getInstance() - .createChangeMethodSignatureFromUsageFix(method, expressions, substitutor, context, false, 2); - QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, fix); - IntentionAction f2 = QuickFixFactory.getInstance() - .createChangeMethodSignatureFromUsageReverseOrderFix(method, - expressions, - substitutor, - context, - false, - 2); - QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, f2); + + private static void registerChangeMethodSignatureFromUsageIntention( + @Nonnull PsiExpression[] expressions, + @Nullable HighlightInfo highlightInfo, + TextRange fixRange, + @Nonnull JavaResolveResult candidate, + @Nonnull PsiElement context + ) { + if (!candidate.isStaticsScopeCorrect()) { + return; + } + PsiMethod method = (PsiMethod)candidate.getElement(); + PsiSubstitutor substitutor = candidate.getSubstitutor(); + if (method != null && context.getManager().isInProject(method)) { + IntentionAction fix = QuickFixFactory.getInstance() + .createChangeMethodSignatureFromUsageFix(method, expressions, substitutor, context, false, 2); + QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, fix); + IntentionAction f2 = QuickFixFactory.getInstance().createChangeMethodSignatureFromUsageReverseOrderFix( + method, + expressions, + substitutor, + context, + false, + 2 + ); + QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, f2); + } } - } } diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index ab803437cf..407ce1e73b 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -66,1926 +66,2146 @@ import static consulo.util.lang.ObjectUtil.notNull; public class HighlightVisitorImpl extends JavaElementVisitor implements HighlightVisitor { - private final PsiResolveHelper myResolveHelper; + private final PsiResolveHelper myResolveHelper; + + private HighlightInfoHolder myHolder; + private RefCountHolder myRefCountHolder; + private LanguageLevel myLanguageLevel; + private JavaSdkVersion myJavaSdkVersion; + + @SuppressWarnings("StatefulEp") + private PsiFile myFile; + @SuppressWarnings("StatefulEp") + private PsiJavaModule myJavaModule; + + // map codeBlock->List of PsiReferenceExpression of uninitialized final variables + private final Map> myUninitializedVarProblems = new HashMap<>(); + // map codeBlock->List of PsiReferenceExpression of extra initialization of final variable + private final Map> myFinalVarProblems = new HashMap<>(); + + // value==1: no info if the parameter was reassigned (but the parameter is present in current file), value==2: parameter was reassigned + private final ObjectIntMap myReassignedParameters = ObjectMaps.newObjectIntHashMap(); + + private final Map> mySingleImportedClasses = new HashMap<>(); + private final Map> mySingleImportedFields = new HashMap<>(); + + private final PsiElementVisitor REGISTER_REFERENCES_VISITOR = new PsiRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + super.visitElement(element); + for (PsiReference reference : element.getReferences()) { + PsiElement resolved = reference.resolve(); + if (resolved instanceof PsiNamedElement) { + myRefCountHolder.registerLocallyReferenced((PsiNamedElement)resolved); + if (resolved instanceof PsiMember) { + myRefCountHolder.registerReference(reference, new CandidateInfo(resolved, PsiSubstitutor.EMPTY)); + } + } + } + } + }; + private final Map> myDuplicateMethods = new HashMap<>(); + private final Set myOverrideEquivalentMethodsVisitedClasses = new HashSet<>(); + + @Inject + public HighlightVisitorImpl(@Nonnull PsiResolveHelper resolveHelper) { + myResolveHelper = resolveHelper; + } + + @Nonnull + private MostlySingularMultiMap getDuplicateMethods(@Nonnull PsiClass aClass) { + MostlySingularMultiMap signatures = myDuplicateMethods.get(aClass); + if (signatures == null) { + signatures = new MostlySingularMultiMap<>(); + for (PsiMethod method : aClass.getMethods()) { + if (method instanceof ExternallyDefinedPsiElement) { + continue; // ignore aspectj-weaved methods; they are checked elsewhere + } + MethodSignature signature = method.getSignature(PsiSubstitutor.EMPTY); + signatures.add(signature, method); + } + + myDuplicateMethods.put(aClass, signatures); + } + return signatures; + } + + @Override + public void visit(@Nonnull PsiElement element) { + element.accept(this); + } - private HighlightInfoHolder myHolder; - private RefCountHolder myRefCountHolder; - private LanguageLevel myLanguageLevel; - private JavaSdkVersion myJavaSdkVersion; + private void registerReferencesFromInjectedFragments(@Nonnull PsiElement element) { + InjectedLanguageManager manager = InjectedLanguageManager.getInstance(myFile.getProject()); + manager.enumerateEx(element, myFile, false, (injectedPsi, places) -> injectedPsi.accept(REGISTER_REFERENCES_VISITOR)); + } - @SuppressWarnings("StatefulEp") - private PsiFile myFile; - @SuppressWarnings("StatefulEp") - private PsiJavaModule myJavaModule; + @Override + public boolean analyze( + @Nonnull PsiFile file, + boolean updateWholeFile, + @Nonnull HighlightInfoHolder holder, + @Nonnull Runnable highlight + ) { + try { + prepare(holder, file); + if (updateWholeFile) { + ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); + if (progress == null) { + throw new IllegalStateException("Must be run under progress"); + } + Project project = file.getProject(); + Document document = PsiDocumentManager.getInstance(project).getDocument(file); + TextRange dirtyScope = document == null ? null : DaemonCodeAnalyzer.getInstance(project) + .getFileStatusMap() + .getFileDirtyScope(document, Pass.UPDATE_ALL); + if (dirtyScope == null) { + dirtyScope = file.getTextRange(); + } + RefCountHolder refCountHolder = RefCountHolder.get(file, dirtyScope); + if (refCountHolder == null) { + // RefCountHolder was GCed and queried again for some inner code block + // "highlight.run()" can't fill it again because it runs for only a subset of elements, + // so we have to restart the daemon for the whole file + return false; + } + myRefCountHolder = refCountHolder; + + highlight.run(); + ProgressManager.checkCanceled(); + refCountHolder.storeReadyHolder(file); + if (document != null) { + new PostHighlightingVisitor(file, document, refCountHolder).collectHighlights(holder, progress); + } + } + else { + myRefCountHolder = null; + highlight.run(); + } + } + finally { + myUninitializedVarProblems.clear(); + myFinalVarProblems.clear(); + mySingleImportedClasses.clear(); + mySingleImportedFields.clear(); + myReassignedParameters.clear(); + + myRefCountHolder = null; + myJavaModule = null; + myFile = null; + myHolder = null; + myDuplicateMethods.clear(); + myOverrideEquivalentMethodsVisitedClasses.clear(); + } - // map codeBlock->List of PsiReferenceExpression of uninitialized final variables - private final Map> myUninitializedVarProblems = new HashMap<>(); - // map codeBlock->List of PsiReferenceExpression of extra initialization of final variable - private final Map> myFinalVarProblems = new HashMap<>(); + return true; + } - // value==1: no info if the parameter was reassigned (but the parameter is present in current file), value==2: parameter was reassigned - private final ObjectIntMap myReassignedParameters = ObjectMaps.newObjectIntHashMap(); + protected void prepareToRunAsInspection(@Nonnull HighlightInfoHolder holder) { + prepare(holder, holder.getContextFile()); + } - private final Map> mySingleImportedClasses = new HashMap<>(); - private final Map> mySingleImportedFields = new HashMap<>(); + private void prepare(HighlightInfoHolder holder, PsiFile file) { + myHolder = holder; + myFile = file; + myLanguageLevel = PsiUtil.getLanguageLevel(file); + myJavaSdkVersion = + notNull(JavaVersionService.getInstance().getJavaSdkVersion(file), JavaSdkVersion.fromLanguageLevel(myLanguageLevel)); + myJavaModule = myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9) ? ModuleHighlightUtil.getModuleDescriptor(file) : null; + } - private final PsiElementVisitor REGISTER_REFERENCES_VISITOR = new PsiRecursiveElementWalkingVisitor() { @Override public void visitElement(PsiElement element) { - super.visitElement(element); - for (PsiReference reference : element.getReferences()) { - PsiElement resolved = reference.resolve(); - if (resolved instanceof PsiNamedElement) { - myRefCountHolder.registerLocallyReferenced((PsiNamedElement) resolved); - if (resolved instanceof PsiMember) { - myRefCountHolder.registerReference(reference, new CandidateInfo(resolved, PsiSubstitutor.EMPTY)); - } - } - } - } - }; - private final Map> myDuplicateMethods = new HashMap<>(); - private final Set myOverrideEquivalentMethodsVisitedClasses = new HashSet<>(); - - @Inject - public HighlightVisitorImpl(@Nonnull PsiResolveHelper resolveHelper) { - myResolveHelper = resolveHelper; - } - - @Nonnull - private MostlySingularMultiMap getDuplicateMethods(@Nonnull PsiClass aClass) { - MostlySingularMultiMap signatures = myDuplicateMethods.get(aClass); - if (signatures == null) { - signatures = new MostlySingularMultiMap<>(); - for (PsiMethod method : aClass.getMethods()) { - if (method instanceof ExternallyDefinedPsiElement) { - continue; // ignore aspectj-weaved methods; they are checked elsewhere - } - MethodSignature signature = method.getSignature(PsiSubstitutor.EMPTY); - signatures.add(signature, method); - } - - myDuplicateMethods.put(aClass, signatures); - } - return signatures; - } - - @Override - public void visit(@Nonnull PsiElement element) { - element.accept(this); - } - - private void registerReferencesFromInjectedFragments(@Nonnull PsiElement element) { - InjectedLanguageManager manager = InjectedLanguageManager.getInstance(myFile.getProject()); - manager.enumerateEx(element, myFile, false, (injectedPsi, places) -> injectedPsi.accept(REGISTER_REFERENCES_VISITOR)); - } - - @Override - public boolean analyze(@Nonnull PsiFile file, boolean updateWholeFile, @Nonnull HighlightInfoHolder holder, @Nonnull Runnable highlight) { - try { - prepare(holder, file); - if (updateWholeFile) { - ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); - if (progress == null) throw new IllegalStateException("Must be run under progress"); - Project project = file.getProject(); - Document document = PsiDocumentManager.getInstance(project).getDocument(file); - TextRange dirtyScope = document == null ? null : DaemonCodeAnalyzer.getInstance(project).getFileStatusMap().getFileDirtyScope(document, Pass.UPDATE_ALL); - if (dirtyScope == null) dirtyScope = file.getTextRange(); - RefCountHolder refCountHolder = RefCountHolder.get(file, dirtyScope); - if (refCountHolder == null) { - // RefCountHolder was GCed and queried again for some inner code block - // "highlight.run()" can't fill it again because it runs for only a subset of elements, - // so we have to restart the daemon for the whole file - return false; - } - myRefCountHolder = refCountHolder; - - highlight.run(); - ProgressManager.checkCanceled(); - refCountHolder.storeReadyHolder(file); - if (document != null) { - new PostHighlightingVisitor(file, document, refCountHolder).collectHighlights(holder, progress); - } - } else { - myRefCountHolder = null; - highlight.run(); - } - } finally { - myUninitializedVarProblems.clear(); - myFinalVarProblems.clear(); - mySingleImportedClasses.clear(); - mySingleImportedFields.clear(); - myReassignedParameters.clear(); - - myRefCountHolder = null; - myJavaModule = null; - myFile = null; - myHolder = null; - myDuplicateMethods.clear(); - myOverrideEquivalentMethodsVisitedClasses.clear(); - } - - return true; - } - - protected void prepareToRunAsInspection(@Nonnull HighlightInfoHolder holder) { - prepare(holder, holder.getContextFile()); - } - - private void prepare(HighlightInfoHolder holder, PsiFile file) { - myHolder = holder; - myFile = file; - myLanguageLevel = PsiUtil.getLanguageLevel(file); - myJavaSdkVersion = notNull(JavaVersionService.getInstance().getJavaSdkVersion(file), JavaSdkVersion.fromLanguageLevel(myLanguageLevel)); - myJavaModule = myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9) ? ModuleHighlightUtil.getModuleDescriptor(file) : null; - } - - @Override - public void visitElement(PsiElement element) { - if (myRefCountHolder != null && myFile instanceof ServerPageFile) { - // in JSP, XmlAttributeValue may contain java references - try { - for (PsiReference reference : element.getReferences()) { - if (reference instanceof PsiJavaReference) { - PsiJavaReference psiJavaReference = (PsiJavaReference) reference; - myRefCountHolder.registerReference(psiJavaReference, psiJavaReference.advancedResolve(false)); - } - } - } catch (IndexNotReadyException ignored) { - } - } - - if (!(myFile instanceof ServerPageFile)) { - myHolder.add(DefaultHighlightUtil.checkBadCharacter(element)); - } - } - - @Nullable - public static JavaResolveResult resolveJavaReference(@Nonnull PsiReference reference) { - if (reference instanceof PsiJavaReference) { - PsiJavaReference psiJavaReference = (PsiJavaReference) reference; - return psiJavaReference.advancedResolve(false); - } - if (reference instanceof PsiPolyVariantReference && - reference instanceof ResolvingHint && ((ResolvingHint) reference).canResolveTo(PsiClass.class)) { - ResolveResult[] resolve = ((PsiPolyVariantReference) reference).multiResolve(false); - if (resolve.length == 1 && resolve[0] instanceof JavaResolveResult) { - return (JavaResolveResult) resolve[0]; - } - } - return null; - } - - @Override - public void visitAnnotation(PsiAnnotation annotation) { - super.visitAnnotation(annotation); - if (!myHolder.hasErrorResults()) { - myHolder.add(checkFeature(annotation, JavaFeature.ANNOTATIONS)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(AnnotationsHighlightUtil.checkApplicability(annotation, myLanguageLevel, myFile)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(AnnotationsHighlightUtil.checkAnnotationType(annotation)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(AnnotationsHighlightUtil.checkMissingAttributes(annotation)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(AnnotationsHighlightUtil.checkTargetAnnotationDuplicates(annotation)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(AnnotationsHighlightUtil.checkDuplicateAnnotations(annotation, myLanguageLevel)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(AnnotationsHighlightUtil.checkFunctionalInterface(annotation, myLanguageLevel)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(AnnotationsHighlightUtil.checkRepeatableAnnotation(annotation)); - } - if (JavaClassNames.JAVA_LANG_OVERRIDE.equals(annotation.getQualifiedName())) { - PsiAnnotationOwner owner = annotation.getOwner(); - PsiElement parent = owner instanceof PsiModifierList ? ((PsiModifierList) owner).getParent() : null; - if (parent instanceof PsiMethod) { - myHolder.add(GenericsHighlightUtil.checkOverrideAnnotation((PsiMethod) parent, annotation, myLanguageLevel)); - } - } - } - - @Override - public void visitAnnotationArrayInitializer(PsiArrayInitializerMemberValue initializer) { - PsiMethod method = null; + if (myRefCountHolder != null && myFile instanceof ServerPageFile) { + // in JSP, XmlAttributeValue may contain java references + try { + for (PsiReference reference : element.getReferences()) { + if (reference instanceof PsiJavaReference) { + PsiJavaReference psiJavaReference = (PsiJavaReference)reference; + myRefCountHolder.registerReference(psiJavaReference, psiJavaReference.advancedResolve(false)); + } + } + } + catch (IndexNotReadyException ignored) { + } + } + + if (!(myFile instanceof ServerPageFile)) { + myHolder.add(DefaultHighlightUtil.checkBadCharacter(element)); + } + } + + @Nullable + public static JavaResolveResult resolveJavaReference(@Nonnull PsiReference reference) { + if (reference instanceof PsiJavaReference) { + PsiJavaReference psiJavaReference = (PsiJavaReference)reference; + return psiJavaReference.advancedResolve(false); + } + if (reference instanceof PsiPolyVariantReference && + reference instanceof ResolvingHint && ((ResolvingHint)reference).canResolveTo(PsiClass.class)) { + ResolveResult[] resolve = ((PsiPolyVariantReference)reference).multiResolve(false); + if (resolve.length == 1 && resolve[0] instanceof JavaResolveResult) { + return (JavaResolveResult)resolve[0]; + } + } + return null; + } + + @Override + public void visitAnnotation(PsiAnnotation annotation) { + super.visitAnnotation(annotation); + if (!myHolder.hasErrorResults()) { + myHolder.add(checkFeature(annotation, JavaFeature.ANNOTATIONS)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(AnnotationsHighlightUtil.checkApplicability(annotation, myLanguageLevel, myFile)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(AnnotationsHighlightUtil.checkAnnotationType(annotation)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(AnnotationsHighlightUtil.checkMissingAttributes(annotation)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(AnnotationsHighlightUtil.checkTargetAnnotationDuplicates(annotation)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(AnnotationsHighlightUtil.checkDuplicateAnnotations(annotation, myLanguageLevel)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(AnnotationsHighlightUtil.checkFunctionalInterface(annotation, myLanguageLevel)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(AnnotationsHighlightUtil.checkRepeatableAnnotation(annotation)); + } + if (JavaClassNames.JAVA_LANG_OVERRIDE.equals(annotation.getQualifiedName())) { + PsiAnnotationOwner owner = annotation.getOwner(); + PsiElement parent = owner instanceof PsiModifierList ? ((PsiModifierList)owner).getParent() : null; + if (parent instanceof PsiMethod) { + myHolder.add(GenericsHighlightUtil.checkOverrideAnnotation((PsiMethod)parent, annotation, myLanguageLevel)); + } + } + } - PsiElement parent = initializer.getParent(); - if (parent instanceof PsiNameValuePair) { - PsiReference reference = parent.getReference(); - if (reference != null) { - method = (PsiMethod) reference.resolve(); - } - } else if (PsiUtil.isAnnotationMethod(parent)) { - method = (PsiMethod) parent; - } - - if (method != null) { - PsiType type = method.getReturnType(); - if (type instanceof PsiArrayType) { - type = ((PsiArrayType) type).getComponentType(); - PsiAnnotationMemberValue[] initializers = initializer.getInitializers(); - for (PsiAnnotationMemberValue initializer1 : initializers) { - myHolder.add(AnnotationsHighlightUtil.checkMemberValueType(initializer1, type)); - } - } - } - } - - @Override - public void visitAnnotationMethod(PsiAnnotationMethod method) { - PsiType returnType = method.getReturnType(); - PsiAnnotationMemberValue value = method.getDefaultValue(); - if (returnType != null && value != null) { - myHolder.add(AnnotationsHighlightUtil.checkMemberValueType(value, returnType)); - } - - myHolder.add(AnnotationsHighlightUtil.checkValidAnnotationType(method.getReturnType(), method.getReturnTypeElement())); - final PsiClass aClass = method.getContainingClass(); - myHolder.add(AnnotationsHighlightUtil.checkCyclicMemberType(method.getReturnTypeElement(), aClass)); - myHolder.add(AnnotationsHighlightUtil.checkClashesWithSuperMethods(method)); + @Override + public void visitAnnotationArrayInitializer(PsiArrayInitializerMemberValue initializer) { + PsiMethod method = null; + + PsiElement parent = initializer.getParent(); + if (parent instanceof PsiNameValuePair) { + PsiReference reference = parent.getReference(); + if (reference != null) { + method = (PsiMethod)reference.resolve(); + } + } + else if (PsiUtil.isAnnotationMethod(parent)) { + method = (PsiMethod)parent; + } - if (!myHolder.hasErrorResults() && aClass != null) { - myHolder.add(HighlightMethodUtil.checkDuplicateMethod(aClass, method, getDuplicateMethods(aClass))); + if (method != null) { + PsiType type = method.getReturnType(); + if (type instanceof PsiArrayType) { + type = ((PsiArrayType)type).getComponentType(); + PsiAnnotationMemberValue[] initializers = initializer.getInitializers(); + for (PsiAnnotationMemberValue initializer1 : initializers) { + myHolder.add(AnnotationsHighlightUtil.checkMemberValueType(initializer1, type)); + } + } + } } - } - - @Override - public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) { - super.visitArrayInitializerExpression(expression); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkArrayInitializerApplicable(expression)); - } - if (!(expression.getParent() instanceof PsiNewExpression)) { - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkGenericArrayCreation(expression, expression.getType())); - } - } - } - - @Override - public void visitAssignmentExpression(PsiAssignmentExpression assignment) { - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkAssignmentCompatibleTypes(assignment)); + + @Override + public void visitAnnotationMethod(PsiAnnotationMethod method) { + PsiType returnType = method.getReturnType(); + PsiAnnotationMemberValue value = method.getDefaultValue(); + if (returnType != null && value != null) { + myHolder.add(AnnotationsHighlightUtil.checkMemberValueType(value, returnType)); + } + + myHolder.add(AnnotationsHighlightUtil.checkValidAnnotationType(method.getReturnType(), method.getReturnTypeElement())); + final PsiClass aClass = method.getContainingClass(); + myHolder.add(AnnotationsHighlightUtil.checkCyclicMemberType(method.getReturnTypeElement(), aClass)); + myHolder.add(AnnotationsHighlightUtil.checkClashesWithSuperMethods(method)); + + if (!myHolder.hasErrorResults() && aClass != null) { + myHolder.add(HighlightMethodUtil.checkDuplicateMethod(aClass, method, getDuplicateMethods(aClass))); + } } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkAssignmentOperatorApplicable(assignment)); + + @Override + public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) { + super.visitArrayInitializerExpression(expression); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkArrayInitializerApplicable(expression)); + } + if (!(expression.getParent() instanceof PsiNewExpression)) { + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkGenericArrayCreation(expression, expression.getType())); + } + } } - if (!myHolder.hasErrorResults()) { - visitExpression(assignment); + + @Override + public void visitAssignmentExpression(PsiAssignmentExpression assignment) { + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkAssignmentCompatibleTypes(assignment)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkAssignmentOperatorApplicable(assignment)); + } + if (!myHolder.hasErrorResults()) { + visitExpression(assignment); + } } - } - @Override - public void visitPolyadicExpression(PsiPolyadicExpression expression) { - super.visitPolyadicExpression(expression); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkPolyadicOperatorApplicable(expression)); + @Override + public void visitPolyadicExpression(PsiPolyadicExpression expression) { + super.visitPolyadicExpression(expression); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkPolyadicOperatorApplicable(expression)); + } } - } - @Override - public void visitLambdaExpression(PsiLambdaExpression expression) { - myHolder.add(checkFeature(expression, JavaFeature.LAMBDA_EXPRESSIONS)); - final PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent()); - if (parent instanceof PsiExpressionStatement) { - return; + @Override + public void visitLambdaExpression(PsiLambdaExpression expression) { + myHolder.add(checkFeature(expression, JavaFeature.LAMBDA_EXPRESSIONS)); + final PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent()); + if (parent instanceof PsiExpressionStatement) { + return; + } + if (!myHolder.hasErrorResults() && !LambdaUtil.isValidLambdaContext(parent)) { + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip("Lambda expression not expected here") + .create()); + } + + PsiType functionalInterfaceType = null; + if (!myHolder.hasErrorResults()) { + functionalInterfaceType = expression.getFunctionalInterfaceType(); + if (functionalInterfaceType != null) { + final String notFunctionalMessage = LambdaHighlightingUtil.checkInterfaceFunctional(functionalInterfaceType); + if (notFunctionalMessage != null) { + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(notFunctionalMessage) + .create()); + } + else { + checkFunctionalInterfaceTypeAccessible(expression, functionalInterfaceType); + } + } + else if (LambdaUtil.getFunctionalInterfaceType(expression, true) != null) { + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip("Cannot infer functional interface type") + .create()); + } + } + + if (!myHolder.hasErrorResults() && functionalInterfaceType != null) { + String parentInferenceErrorMessage = null; + final PsiCallExpression callExpression = + parent instanceof PsiExpressionList && parent.getParent() instanceof PsiCallExpression ? (PsiCallExpression)parent.getParent() : null; + final JavaResolveResult containingCallResolveResult = callExpression != null ? callExpression.resolveMethodGenerics() : null; + if (containingCallResolveResult instanceof MethodCandidateInfo) { + parentInferenceErrorMessage = ((MethodCandidateInfo)containingCallResolveResult).getInferenceErrorMessage(); + } + final Map returnErrors = + LambdaUtil.checkReturnTypeCompatible(expression, LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType)); + if (parentInferenceErrorMessage != null && (returnErrors == null || !returnErrors.containsValue(parentInferenceErrorMessage))) { + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(parentInferenceErrorMessage) + .create()); + } + else if (returnErrors != null) { + for (Map.Entry entry : returnErrors.entrySet()) { + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(entry.getKey()) + .descriptionAndTooltip(entry.getValue()) + .create()); + } + } + } + + if (!myHolder.hasErrorResults() && functionalInterfaceType != null) { + final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); + if (interfaceMethod != null) { + final PsiParameter[] parameters = interfaceMethod.getParameterList().getParameters(); + myHolder.add(LambdaHighlightingUtil.checkParametersCompatible( + expression, + parameters, + LambdaUtil.getSubstitutor(interfaceMethod, resolveResult) + )); + } + } + + if (!myHolder.hasErrorResults()) { + final PsiElement body = expression.getBody(); + if (body instanceof PsiCodeBlock) { + myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement((PsiCodeBlock)body)); + } + } } - if (!myHolder.hasErrorResults() && !LambdaUtil.isValidLambdaContext(parent)) { - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip("Lambda expression not expected here").create()); + + @Override + public void visitBreakStatement(PsiBreakStatement statement) { + super.visitBreakStatement(statement); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkLabelDefined(statement.getLabelIdentifier(), statement.findExitedStatement())); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkBreakOutsideLoop(statement)); + } } - PsiType functionalInterfaceType = null; - if (!myHolder.hasErrorResults()) { - functionalInterfaceType = expression.getFunctionalInterfaceType(); - if (functionalInterfaceType != null) { - final String notFunctionalMessage = LambdaHighlightingUtil.checkInterfaceFunctional(functionalInterfaceType); - if (notFunctionalMessage != null) { - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(notFunctionalMessage).create()); - } else { - checkFunctionalInterfaceTypeAccessible(expression, functionalInterfaceType); + @Override + public void visitClass(PsiClass aClass) { + super.visitClass(aClass); + if (aClass instanceof PsiSyntheticClass) { + return; + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkInterfaceMultipleInheritance(aClass)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.areSupersAccessible(aClass)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkDuplicateTopLevelClass(aClass)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkEnumMustNotBeLocal(aClass)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkEnumWithoutConstantsCantHaveAbstractMethods(aClass)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkImplicitThisReferenceBeforeSuper(aClass, myJavaSdkVersion)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkClassAndPackageConflict(aClass)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkPublicClassInRightFile(aClass)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkTypeParameterOverrideEquivalentMethods(aClass, myLanguageLevel)); } - } else if (LambdaUtil.getFunctionalInterfaceType(expression, true) != null) { - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip("Cannot infer functional interface type").create()); - } } - if (!myHolder.hasErrorResults() && functionalInterfaceType != null) { - String parentInferenceErrorMessage = null; - final PsiCallExpression callExpression = parent instanceof PsiExpressionList && parent.getParent() instanceof PsiCallExpression ? (PsiCallExpression) parent.getParent() : null; - final JavaResolveResult containingCallResolveResult = callExpression != null ? callExpression.resolveMethodGenerics() : null; - if (containingCallResolveResult instanceof MethodCandidateInfo) { - parentInferenceErrorMessage = ((MethodCandidateInfo) containingCallResolveResult).getInferenceErrorMessage(); - } - final Map returnErrors = LambdaUtil.checkReturnTypeCompatible(expression, LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType)); - if (parentInferenceErrorMessage != null && (returnErrors == null || !returnErrors.containsValue(parentInferenceErrorMessage))) { - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(parentInferenceErrorMessage).create()); - } else if (returnErrors != null) { - for (Map.Entry entry : returnErrors.entrySet()) { - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(entry.getKey()).descriptionAndTooltip(entry.getValue()).create()); + @Override + public void visitClassInitializer(PsiClassInitializer initializer) { + super.visitClassInitializer(initializer); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightControlFlowUtil.checkInitializerCompleteNormally(initializer)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement(initializer.getBody())); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkThingNotAllowedInInterface(initializer, initializer.getContainingClass())); + } + } + + @Override + public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) { + super.visitClassObjectAccessExpression(expression); + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkClassObjectAccessExpression(expression)); + } + } + + @Override + public void visitComment(PsiComment comment) { + super.visitComment(comment); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkUnclosedComment(comment)); + } + if (myRefCountHolder != null && !myHolder.hasErrorResults()) { + registerReferencesFromInjectedFragments(comment); + } + } + + @Override + public void visitContinueStatement(PsiContinueStatement statement) { + super.visitContinueStatement(statement); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkLabelDefined(statement.getLabelIdentifier(), statement.findContinuedStatement())); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkContinueOutsideLoop(statement)); + } + } + + @Override + public void visitJavaToken(PsiJavaToken token) { + super.visitJavaToken(token); + if (!myHolder.hasErrorResults() && token.getTokenType() == JavaTokenType.RBRACE && token.getParent() instanceof PsiCodeBlock) { + + final PsiElement gParent = token.getParent().getParent(); + final PsiCodeBlock codeBlock; + final PsiType returnType; + if (gParent instanceof PsiMethod) { + PsiMethod method = (PsiMethod)gParent; + codeBlock = method.getBody(); + returnType = method.getReturnType(); + } + else if (gParent instanceof PsiLambdaExpression) { + final PsiElement body = ((PsiLambdaExpression)gParent).getBody(); + if (!(body instanceof PsiCodeBlock)) { + return; + } + codeBlock = (PsiCodeBlock)body; + returnType = LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)gParent); + } + else { + return; + } + myHolder.add(HighlightControlFlowUtil.checkMissingReturnStatement(codeBlock, returnType)); + } + } + + @Override + public void visitDocComment(PsiDocComment comment) { + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkUnclosedComment(comment)); + } + } + + @Override + public void visitDocTagValue(PsiDocTagValue value) { + PsiReference reference = value.getReference(); + if (reference != null) { + PsiElement element = reference.resolve(); + final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); + if (element instanceof PsiMethod) { + PsiElement nameElement = ((PsiDocMethodOrFieldRef)value).getNameElement(); + if (nameElement != null) { + myHolder.add(HighlightNamesUtil.highlightMethodName((PsiMethod)element, nameElement, false, colorsScheme)); + } + } + else if (element instanceof PsiParameter) { + myHolder.add(HighlightNamesUtil.highlightVariableName((PsiVariable)element, value.getNavigationElement(), colorsScheme)); + } + } + } + + @Override + public void visitEnumConstant(PsiEnumConstant enumConstant) { + super.visitEnumConstant(enumConstant); + if (!myHolder.hasErrorResults()) { + GenericsHighlightUtil.checkEnumConstantForConstructorProblems(enumConstant, myHolder, myJavaSdkVersion); + } + if (!myHolder.hasErrorResults()) { + registerConstructorCall(enumConstant); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkUnhandledExceptions(enumConstant, null)); + } + } + + @Override + public void visitEnumConstantInitializer(PsiEnumConstantInitializer enumConstantInitializer) { + super.visitEnumConstantInitializer(enumConstantInitializer); + if (!myHolder.hasErrorResults()) { + TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(enumConstantInitializer); + myHolder.add(HighlightClassUtil.checkClassMustBeAbstract(enumConstantInitializer, textRange)); + } + } + + @Override + public void visitExpression(PsiExpression expression) { + ProgressManager.checkCanceled(); // visitLiteralExpression is invoked very often in array initializers + + super.visitExpression(expression); + PsiType type = expression.getType(); + if (myHolder.add(HighlightUtil.checkMustBeBoolean(expression, type))) { + return; + } + + if (expression instanceof PsiArrayAccessExpression) { + myHolder.add(HighlightUtil.checkValidArrayAccessExpression((PsiArrayAccessExpression)expression)); + } + + PsiElement parent = expression.getParent(); + if (parent instanceof PsiNewExpression && ((PsiNewExpression)parent).getQualifier() != expression && ((PsiNewExpression)parent).getArrayInitializer() != expression) { + // like in 'new String["s"]' + myHolder.add(HighlightUtil.checkAssignability(PsiType.INT, expression.getType(), expression, expression)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightControlFlowUtil.checkCannotWriteToFinal(expression, myFile)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkVariableExpected(expression)); + } + if (!myHolder.hasErrorResults()) { + myHolder.addAll(HighlightUtil.checkArrayInitializer(expression, type)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkTernaryOperatorConditionIsBoolean(expression, type)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkAssertOperatorTypes(expression, type)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkSynchronizedExpressionType(expression, type, myFile)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkConditionalExpressionBranchTypesMatch(expression, type)); + } + if (!myHolder.hasErrorResults() && parent instanceof PsiThrowStatement && ((PsiThrowStatement)parent).getException() == expression) { + myHolder.add(HighlightUtil.checkMustBeThrowable(type, expression, true)); + } + + if (!myHolder.hasErrorResults()) { + myHolder.add(AnnotationsHighlightUtil.checkConstantExpression(expression)); + } + if (!myHolder.hasErrorResults() && parent instanceof PsiForeachStatement && ((PsiForeachStatement)parent).getIteratedValue() == expression) { + myHolder.add(GenericsHighlightUtil.checkForeachExpressionTypeIsIterable(expression)); + } + } + + @Override + public void visitExpressionList(PsiExpressionList list) { + super.visitExpressionList(list); + PsiElement parent = list.getParent(); + if (parent instanceof PsiMethodCallExpression) { + PsiMethodCallExpression expression = (PsiMethodCallExpression)parent; + if (expression.getArgumentList() == list) { + PsiReferenceExpression referenceExpression = expression.getMethodExpression(); + JavaResolveResult[] results = resolveOptimised(referenceExpression); + if (results == null) { + return; + } + JavaResolveResult result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY; + PsiElement resolved = result.getElement(); + + if ((!result.isAccessible() || !result.isStaticsScopeCorrect()) + && !HighlightMethodUtil.isDummyConstructorCall(expression, myResolveHelper, list, referenceExpression) + // this check is for fake expression from JspMethodCallImpl + && referenceExpression.getParent() == expression) { + try { + if (PsiTreeUtil.findChildrenOfType(expression.getArgumentList(), PsiLambdaExpression.class).isEmpty()) { + myHolder.add(HighlightMethodUtil.checkAmbiguousMethodCallArguments( + referenceExpression, + results, + list, + resolved, + result, + expression, + myResolveHelper, + list + )); + } + } + catch (IndexNotReadyException ignored) { + } + } + } + } + } + + @Override + public void visitField(PsiField field) { + super.visitField(field); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightControlFlowUtil.checkFinalFieldInitialized(field)); + } + } + + @Override + public void visitForStatement(PsiForStatement statement) { + myHolder.add(HighlightUtil.checkForStatement(statement)); + } + + @Override + public void visitForeachStatement(PsiForeachStatement statement) { + myHolder.add(checkFeature(statement, JavaFeature.FOR_EACH)); + } + + @Override + public void visitImportStaticStatement(PsiImportStaticStatement statement) { + myHolder.add(checkFeature(statement, JavaFeature.STATIC_IMPORTS)); + if (!myHolder.hasErrorResults()) { + myHolder.add(ImportsHighlightUtil.checkStaticOnDemandImportResolvesToClass(statement)); + } + } + + @Override + public void visitIdentifier(final PsiIdentifier identifier) { + TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); + + PsiElement parent = identifier.getParent(); + if (parent instanceof PsiVariable) { + PsiVariable variable = (PsiVariable)parent; + myHolder.add(HighlightUtil.checkVariableAlreadyDefined(variable)); + + if (variable.getInitializer() == null) { + final PsiElement child = variable.getLastChild(); + if (child instanceof PsiErrorElement && child.getPrevSibling() == identifier) { + return; + } + } + + boolean isMethodParameter = + variable instanceof PsiParameter && ((PsiParameter)variable).getDeclarationScope() instanceof PsiMethod; + if (isMethodParameter) { + myReassignedParameters.putInt((PsiParameter)variable, 1); // mark param as present in current file + } + // method params are highlighted in visitMethod since we should make sure the method body was visited before + else if (HighlightControlFlowUtil.isReassigned(variable, myFinalVarProblems)) { + myHolder.add(HighlightNamesUtil.highlightReassignedVariable(variable, identifier)); + } + else { + myHolder.add(HighlightNamesUtil.highlightVariableName(variable, identifier, colorsScheme)); + } + } + else if (parent instanceof PsiClass) { + PsiClass aClass = (PsiClass)parent; + if (aClass.isAnnotationType()) { + myHolder.add(checkFeature(identifier, JavaFeature.ANNOTATIONS)); + } + + myHolder.add(HighlightClassUtil.checkClassAlreadyImported(aClass, identifier)); + if (!(parent instanceof PsiAnonymousClass) && aClass.getNameIdentifier() == identifier) { + myHolder.add(HighlightNamesUtil.highlightClassName(aClass, identifier, colorsScheme)); + } + if (!myHolder.hasErrorResults() && myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { + myHolder.add(GenericsHighlightUtil.checkUnrelatedDefaultMethods(aClass, identifier)); + } + + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkUnrelatedConcrete(aClass, identifier)); + } + } + else if (parent instanceof PsiMethod) { + PsiMethod method = (PsiMethod)parent; + if (method.isConstructor()) { + myHolder.add(HighlightMethodUtil.checkConstructorName(method)); + } + myHolder.add(HighlightNamesUtil.highlightMethodName(method, identifier, true, colorsScheme)); + final PsiClass aClass = method.getContainingClass(); + if (aClass != null) { + myHolder.add(GenericsHighlightUtil.checkDefaultMethodOverrideEquivalentToObjectNonPrivate( + myLanguageLevel, + aClass, + method, + identifier + )); + } + } + + myHolder.add(HighlightUtil.checkUnderscore(identifier, myLanguageLevel)); + + super.visitIdentifier(identifier); + } + + @Override + public void visitImportStatement(final PsiImportStatement statement) { + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkSingleImportClassConflict(statement, mySingleImportedClasses, myFile)); + } + } + + @Override + public void visitImportStaticReferenceElement(@Nonnull PsiImportStaticReferenceElement ref) { + final String refName = ref.getReferenceName(); + final JavaResolveResult[] results = ref.multiResolve(false); + + final PsiElement referenceNameElement = ref.getReferenceNameElement(); + if (results.length == 0) { + final String description = JavaErrorBundle.message("cannot.resolve.symbol", refName); + assert referenceNameElement != null : ref; + final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF) + .range(referenceNameElement) + .descriptionAndTooltip(description) + .create(); + QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createSetupJDKFix()); + myHolder.add(info); + } + else { + final PsiManager manager = ref.getManager(); + for (JavaResolveResult result : results) { + final PsiElement element = result.getElement(); + + String description = null; + if (element instanceof PsiClass) { + final Pair imported = mySingleImportedClasses.get(refName); + final PsiClass aClass = imported == null ? null : imported.getSecond(); + if (aClass != null && !manager.areElementsEquivalent(aClass, element)) { + //noinspection ConditionalExpressionWithIdenticalBranches + description = imported.first == null + ? JavaErrorBundle.message("single.import.class.conflict", refName) + : imported.first.equals(ref) + ? JavaErrorBundle.message("class.is.ambiguous.in.single.static.import", refName) + : JavaErrorBundle.message("class.is.already.defined.in.single.static.import", refName); + } + mySingleImportedClasses.put(refName, Pair.create(ref, (PsiClass)element)); + } + else if (element instanceof PsiField) { + final Pair imported = mySingleImportedFields.get(refName); + final PsiField field = imported == null ? null : imported.getSecond(); + if (field != null && !manager.areElementsEquivalent(field, element)) { + //noinspection ConditionalExpressionWithIdenticalBranches + description = imported.first.equals(ref) + ? JavaErrorBundle.message("field.is.ambiguous.in.single.static.import", refName) + : JavaErrorBundle.message("field.is.already.defined.in.single.static.import", refName); + } + mySingleImportedFields.put(refName, Pair.create(ref, (PsiField)element)); + } + + if (description != null) { + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(ref) + .descriptionAndTooltip(description) + .create()); + } + } + } + if (!myHolder.hasErrorResults()) { + PsiElement resolved = results.length >= 1 ? results[0].getElement() : null; + if (results.length > 1) { + for (int i = 1; i < results.length; i++) { + final PsiElement element = results[i].getElement(); + if (resolved instanceof PsiMethod && !(element instanceof PsiMethod) || resolved instanceof PsiVariable && !(element instanceof PsiVariable) || resolved instanceof PsiClass && ! + (element instanceof PsiClass)) { + resolved = null; + break; + } + } + } + final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); + if (resolved instanceof PsiClass) { + myHolder.add(HighlightNamesUtil.highlightClassName((PsiClass)resolved, ref, colorsScheme)); + } + else { + myHolder.add(HighlightNamesUtil.highlightClassNameInQualifier(ref, colorsScheme)); + if (referenceNameElement != null) { + if (resolved instanceof PsiVariable) { + myHolder.add(HighlightNamesUtil.highlightVariableName((PsiVariable)resolved, referenceNameElement, colorsScheme)); + } + else if (resolved instanceof PsiMethod) { + myHolder.add(HighlightNamesUtil.highlightMethodName( + (PsiMethod)resolved, + referenceNameElement, + false, + colorsScheme + )); + } + } + } + } + } + + @Override + public void visitInstanceOfExpression(PsiInstanceOfExpression expression) { + super.visitInstanceOfExpression(expression); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkInstanceOfApplicable(expression)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkInstanceOfGenericType(expression)); + } + } + + @Override + public void visitKeyword(PsiKeyword keyword) { + super.visitKeyword(keyword); + PsiElement parent = keyword.getParent(); + String text = keyword.getText(); + if (parent instanceof PsiModifierList) { + PsiModifierList psiModifierList = (PsiModifierList)parent; + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkNotAllowedModifier(keyword, psiModifierList)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkIllegalModifierCombination(keyword, psiModifierList)); + } + if (PsiModifier.ABSTRACT.equals(text) && psiModifierList.getParent() instanceof PsiMethod) { + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightMethodUtil.checkAbstractMethodInConcreteClass((PsiMethod)psiModifierList.getParent(), keyword)); + } + } + } + else if (PsiKeyword.INTERFACE.equals(text) && parent instanceof PsiClass) { + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkInterfaceCannotBeLocal((PsiClass)parent)); + } + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkStaticDeclarationInInnerClass(keyword, myLanguageLevel)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkIllegalVoidType(keyword)); + } + } + + @Override + public void visitLabeledStatement(PsiLabeledStatement statement) { + super.visitLabeledStatement(statement); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkLabelWithoutStatement(statement)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkLabelAlreadyInUse(statement)); + } + } + + @Override + public void visitLiteralExpression(PsiLiteralExpression expression) { + super.visitLiteralExpression(expression); + if (myHolder.hasErrorResults()) { + return; + } + myHolder.add(HighlightUtil.checkLiteralExpressionParsingError(expression, myLanguageLevel, myFile)); + if (myRefCountHolder != null && !myHolder.hasErrorResults()) { + registerReferencesFromInjectedFragments(expression); + } + + if (myRefCountHolder != null && !myHolder.hasErrorResults()) { + for (PsiReference reference : expression.getReferences()) { + PsiElement resolve = reference.resolve(); + if (resolve instanceof PsiMember) { + myRefCountHolder.registerReference(reference, new CandidateInfo(resolve, PsiSubstitutor.EMPTY)); + } + } + } + } + + @Override + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement(method.getBody())); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightMethodUtil.checkConstructorHandleSuperClassExceptions(method)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightMethodUtil.checkRecursiveConstructorInvocation(method)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkSafeVarargsAnnotation(method, myLanguageLevel)); + } + + PsiClass aClass = method.getContainingClass(); + if (!myHolder.hasErrorResults() && method.isConstructor()) { + myHolder.add(HighlightClassUtil.checkThingNotAllowedInInterface(method, aClass)); + } + if (!myHolder.hasErrorResults() && method.hasModifierProperty(PsiModifier.DEFAULT)) { + myHolder.add(checkFeature(method, JavaFeature.EXTENSION_METHODS)); + } + if (!myHolder.hasErrorResults() && aClass != null && aClass.isInterface() && method.hasModifierProperty(PsiModifier.STATIC)) { + myHolder.add(checkFeature(method, JavaFeature.EXTENSION_METHODS)); + } + if (!myHolder.hasErrorResults() && aClass != null) { + myHolder.add(HighlightMethodUtil.checkDuplicateMethod(aClass, method, getDuplicateMethods(aClass))); + } + + // method params are highlighted in visitMethod since we should make sure the method body was visited before + PsiParameter[] parameters = method.getParameterList().getParameters(); + final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); + + for (PsiParameter parameter : parameters) { + int info = myReassignedParameters.getInt(parameter); + if (info == 0) { + continue; // out of this file + } + + PsiIdentifier nameIdentifier = parameter.getNameIdentifier(); + if (nameIdentifier != null) { + if (info == 2) { // reassigned + myHolder.add(HighlightNamesUtil.highlightReassignedVariable(parameter, nameIdentifier)); + } + else { + myHolder.add(HighlightNamesUtil.highlightVariableName(parameter, nameIdentifier, colorsScheme)); + } + } + } + } + + private void highlightReferencedMethodOrClassName(@Nonnull PsiJavaCodeReferenceElement element, PsiElement resolved) { + PsiElement parent = element.getParent(); + final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); + if (parent instanceof PsiMethodCallExpression) { + PsiMethod method = ((PsiMethodCallExpression)parent).resolveMethod(); + PsiElement methodNameElement = element.getReferenceNameElement(); + if (method != null && methodNameElement != null && !(methodNameElement instanceof PsiKeyword)) { + myHolder.add(HighlightNamesUtil.highlightMethodName(method, methodNameElement, false, colorsScheme)); + myHolder.add(HighlightNamesUtil.highlightClassNameInQualifier(element, colorsScheme)); + } + } + else if (parent instanceof PsiConstructorCall) { + try { + PsiMethod method = ((PsiConstructorCall)parent).resolveConstructor(); + PsiMember methodOrClass = method != null ? method : resolved instanceof PsiClass ? (PsiClass)resolved : null; + if (methodOrClass != null) { + final PsiElement referenceNameElement = element.getReferenceNameElement(); + if (referenceNameElement != null) { + // exclude type parameters from the highlighted text range + TextRange range = referenceNameElement.getTextRange(); + myHolder.add(HighlightNamesUtil.highlightMethodName( + methodOrClass, + referenceNameElement, + range, + colorsScheme, + false + )); + } + } + } + catch (IndexNotReadyException ignored) { + } + } + else if (resolved instanceof PsiPackage) { + // highlight package (and following dot) as a class + myHolder.add(HighlightNamesUtil.highlightPackage(resolved, element, colorsScheme)); + } + else if (resolved instanceof PsiClass) { + myHolder.add(HighlightNamesUtil.highlightClassName((PsiClass)resolved, element, colorsScheme)); + } + } + + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkEnumSuperConstructorCall(expression)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkSuperQualifierType(myFile.getProject(), expression)); + } + // in case of JSP synthetic method call, do not check + if (myFile.isPhysical() && !myHolder.hasErrorResults()) { + try { + myHolder.add(HighlightMethodUtil.checkMethodCall(expression, myResolveHelper, myLanguageLevel, myJavaSdkVersion, myFile)); + } + catch (IndexNotReadyException ignored) { + } + } + + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightMethodUtil.checkConstructorCallMustBeFirstStatement(expression)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightMethodUtil.checkSuperAbstractMethodDirectCall(expression)); + } + + if (!myHolder.hasErrorResults()) { + visitExpression(expression); + } + } + + @Override + public void visitModifierList(PsiModifierList list) { + super.visitModifierList(list); + PsiElement parent = list.getParent(); + if (parent instanceof PsiMethod) { + PsiMethod method = (PsiMethod)parent; + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightMethodUtil.checkMethodCanHaveBody(method, myLanguageLevel)); + } + MethodSignatureBackedByPsiMethod methodSignature = MethodSignatureBackedByPsiMethod.create(method, PsiSubstitutor.EMPTY); + if (!method.isConstructor()) { + try { + List superMethodSignatures = method.getHierarchicalMethodSignature().getSuperSignatures(); + if (!superMethodSignatures.isEmpty()) { + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightMethodUtil.checkMethodIncompatibleReturnType( + methodSignature, + superMethodSignatures, + true + )); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightMethodUtil.checkMethodIncompatibleThrows( + methodSignature, + superMethodSignatures, + true, + method.getContainingClass() + )); + } + if (!method.hasModifierProperty(PsiModifier.STATIC)) { + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightMethodUtil.checkMethodWeakerPrivileges( + methodSignature, + superMethodSignatures, + true, + myFile + )); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightMethodUtil.checkMethodOverridesFinal(methodSignature, superMethodSignatures)); + } + } + } + } + catch (IndexNotReadyException ignored) { + } + } + PsiClass aClass = method.getContainingClass(); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightMethodUtil.checkMethodMustHaveBody(method, aClass)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightMethodUtil.checkConstructorCallsBaseClassConstructor(method, myRefCountHolder, myResolveHelper)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightMethodUtil.checkStaticMethodOverride(method, myFile)); + } + if (!myHolder.hasErrorResults() && aClass != null && myOverrideEquivalentMethodsVisitedClasses.add(aClass)) { + myHolder.addAll(GenericsHighlightUtil.checkOverrideEquivalentMethods(aClass)); + } + } + else if (parent instanceof PsiClass) { + PsiClass aClass = (PsiClass)parent; + try { + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkDuplicateNestedClass(aClass)); + } + if (!myHolder.hasErrorResults()) { + TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); + myHolder.add(HighlightClassUtil.checkClassMustBeAbstract(aClass, textRange)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkClassDoesNotCallSuperConstructorOrHandleExceptions( + aClass, + myRefCountHolder, + myResolveHelper + )); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightMethodUtil.checkOverrideEquivalentInheritedMethods(aClass, myFile, myLanguageLevel)); + } + if (!myHolder.hasErrorResults() && myOverrideEquivalentMethodsVisitedClasses.add(aClass)) { + myHolder.addAll(GenericsHighlightUtil.checkOverrideEquivalentMethods(aClass)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkCyclicInheritance(aClass)); + } + } + catch (IndexNotReadyException ignored) { + } + } + else if (parent instanceof PsiEnumConstant) { + if (!myHolder.hasErrorResults()) { + myHolder.addAll(GenericsHighlightUtil.checkEnumConstantModifierList(list)); + } + } + } + + @Override + public void visitNameValuePair(PsiNameValuePair pair) { + myHolder.add(AnnotationsHighlightUtil.checkNameValuePair(pair)); + if (!myHolder.hasErrorResults()) { + PsiIdentifier nameId = pair.getNameIdentifier(); + if (nameId != null) { + HighlightInfo result = + HighlightInfo.newHighlightInfo(JavaHighlightInfoTypes.ANNOTATION_ATTRIBUTE_NAME).range(nameId).create(); + myHolder.add(result); + } + } + } + + @Override + public void visitNewExpression(PsiNewExpression expression) { + final PsiType type = expression.getType(); + final PsiClass aClass = PsiUtil.resolveClassInType(type); + myHolder.add(HighlightUtil.checkUnhandledExceptions(expression, null)); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkAnonymousInheritFinal(expression)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkQualifiedNew(expression, type, aClass)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkCreateInnerClassFromStaticContext(expression, type, aClass)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkTypeParameterInstantiation(expression)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkInstantiationOfAbstractClass(aClass, expression)); + } + try { + if (!myHolder.hasErrorResults()) { + HighlightMethodUtil.checkNewExpression(expression, type, myHolder, myJavaSdkVersion); + } + } + catch (IndexNotReadyException ignored) { + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkEnumInstantiation(expression, aClass)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkGenericArrayCreation(expression, type)); + } + if (!myHolder.hasErrorResults()) { + registerConstructorCall(expression); + } + + if (!myHolder.hasErrorResults()) { + visitExpression(expression); + } + } + + @Override + public void visitPackageStatement(PsiPackageStatement statement) { + super.visitPackageStatement(statement); + myHolder.add(AnnotationsHighlightUtil.checkPackageAnnotationContainingFile(statement, myFile)); + if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { + if (!myHolder.hasErrorResults()) { + myHolder.add(ModuleHighlightUtil.checkPackageStatement(statement, myFile, myJavaModule)); + } + } + } + + @Override + public void visitParameter(PsiParameter parameter) { + super.visitParameter(parameter); + + final PsiElement parent = parameter.getParent(); + if (parent instanceof PsiParameterList && parameter.isVarArgs()) { + if (!myHolder.hasErrorResults()) { + myHolder.add(checkFeature(parameter, JavaFeature.VARARGS)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkVarArgParameterIsLast(parameter)); + } + } + else if (parent instanceof PsiCatchSection) { + if (!myHolder.hasErrorResults() && parameter.getType() instanceof PsiDisjunctionType) { + myHolder.add(checkFeature(parameter, JavaFeature.MULTI_CATCH)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkCatchParameterIsThrowable(parameter)); + } + if (!myHolder.hasErrorResults()) { + myHolder.addAll(GenericsHighlightUtil.checkCatchParameterIsClass(parameter)); + } + if (!myHolder.hasErrorResults()) { + myHolder.addAll(HighlightUtil.checkCatchTypeIsDisjoint(parameter)); + } + } + else if (parent instanceof PsiForeachStatement) { + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkForEachParameterType((PsiForeachStatement)parent, parameter)); + } + } + } + + @Override + public void visitParameterList(PsiParameterList list) { + super.visitParameterList(list); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkAnnotationMethodParameters(list)); + } + } + + @Override + public void visitPostfixExpression(PsiPostfixExpression expression) { + super.visitPostfixExpression(expression); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkUnaryOperatorApplicable(expression.getOperationSign(), expression.getOperand())); + } + } + + @Override + public void visitPrefixExpression(PsiPrefixExpression expression) { + super.visitPrefixExpression(expression); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkUnaryOperatorApplicable(expression.getOperationSign(), expression.getOperand())); + } + } + + private void registerConstructorCall(@Nonnull PsiConstructorCall constructorCall) { + if (myRefCountHolder != null) { + JavaResolveResult resolveResult = constructorCall.resolveMethodGenerics(); + final PsiElement resolved = resolveResult.getElement(); + if (resolved instanceof PsiNamedElement) { + myRefCountHolder.registerLocallyReferenced((PsiNamedElement)resolved); + } + } + } + + @Override + public void visitReferenceElement(PsiJavaCodeReferenceElement ref) { + JavaResolveResult result = doVisitReferenceElement(ref); + if (result != null) { + PsiElement resolved = result.getElement(); + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkRawOnParameterizedType(ref, resolved)); + } + if (!myHolder.hasErrorResults() && resolved != null && myJavaModule != null) { + myHolder.add(ModuleHighlightUtil.checkPackageAccessibility(ref, resolved, myJavaModule)); + } + } + } + + private JavaResolveResult doVisitReferenceElement(@Nonnull PsiJavaCodeReferenceElement ref) { + JavaResolveResult result = resolveOptimised(ref); + if (result == null) { + return null; + } + + PsiElement resolved = result.getElement(); + PsiElement parent = ref.getParent(); + + if (myRefCountHolder != null) { + myRefCountHolder.registerReference(ref, result); + } + + myHolder.add(HighlightUtil.checkReference(ref, result, myFile, myLanguageLevel)); + + if (parent instanceof PsiJavaCodeReferenceElement || ref.isQualified()) { + if (!myHolder.hasErrorResults() && resolved instanceof PsiTypeParameter) { + boolean canSelectFromTypeParameter = myJavaSdkVersion.isAtLeast(JavaSdkVersion.JDK_1_7); + if (canSelectFromTypeParameter) { + final PsiClass containingClass = PsiTreeUtil.getParentOfType(ref, PsiClass.class); + if (containingClass != null) { + if (PsiTreeUtil.isAncestor(containingClass.getExtendsList(), ref, false) + || PsiTreeUtil.isAncestor(containingClass.getImplementsList(), ref, false)) { + canSelectFromTypeParameter = false; + } + } + } + if (!canSelectFromTypeParameter) { + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .descriptionAndTooltip("Cannot select from a type parameter") + .range(ref) + .create()); + } + } + } + + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkAbstractInstantiation(ref)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkExtendsDuplicate(ref, resolved, myFile)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkClassExtendsForeignInnerClass(ref, resolved)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkSelectStaticClassFromParameterizedType(resolved, ref)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkParameterizedReferenceTypeArguments( + resolved, + ref, + result.getSubstitutor(), + myJavaSdkVersion + )); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkCannotPassInner(ref)); + } + + if (resolved != null && parent instanceof PsiReferenceList) { + if (!myHolder.hasErrorResults()) { + PsiReferenceList referenceList = (PsiReferenceList)parent; + myHolder.add(HighlightUtil.checkElementInReferenceList(ref, referenceList, result)); + } + } + + if (parent instanceof PsiAnonymousClass && ref.equals(((PsiAnonymousClass)parent).getBaseClassReference()) + && myOverrideEquivalentMethodsVisitedClasses.add((PsiClass)parent)) { + PsiClass aClass = (PsiClass)parent; + myHolder.addAll(GenericsHighlightUtil.checkOverrideEquivalentMethods(aClass)); + } + + if (resolved instanceof PsiVariable) { + PsiVariable variable = (PsiVariable)resolved; + + PsiElement containingClass = PsiTreeUtil.getNonStrictParentOfType(ref, PsiClass.class, PsiLambdaExpression.class); + if ((containingClass instanceof PsiAnonymousClass || containingClass instanceof PsiLambdaExpression) + && !PsiTreeUtil.isAncestor(containingClass, variable, false) + && !(variable instanceof PsiField) && (containingClass instanceof PsiLambdaExpression + || !PsiTreeUtil.isAncestor(((PsiAnonymousClass)containingClass).getArgumentList(), ref, false))) { + myHolder.add(HighlightInfo.newHighlightInfo(JavaHighlightInfoTypes.IMPLICIT_ANONYMOUS_CLASS_PARAMETER).range(ref).create()); + } + + if (variable instanceof PsiParameter && ref instanceof PsiExpression && PsiUtil.isAccessedForWriting((PsiExpression)ref)) { + myReassignedParameters.putInt((PsiParameter)variable, 2); + } + + final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); + if (!variable.hasModifierProperty(PsiModifier.FINAL) && isReassigned(variable)) { + myHolder.add(HighlightNamesUtil.highlightReassignedVariable(variable, ref)); + } + else { + PsiElement nameElement = ref.getReferenceNameElement(); + if (nameElement != null) { + myHolder.add(HighlightNamesUtil.highlightVariableName(variable, nameElement, colorsScheme)); + } + } + myHolder.add(HighlightNamesUtil.highlightClassNameInQualifier(ref, colorsScheme)); + } + else { + highlightReferencedMethodOrClassName(ref, resolved); + } + + if (parent instanceof PsiNewExpression && !(resolved instanceof PsiClass) && resolved instanceof PsiNamedElement && ((PsiNewExpression)parent).getClassOrAnonymousClassReference() == ref) { + String text = JavaErrorBundle.message("cannot.resolve.symbol", ((PsiNamedElement)resolved).getName()); + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(ref).descriptionAndTooltip(text).create()); + } + + if (!myHolder.hasErrorResults() && resolved instanceof PsiClass) { + final PsiClass aClass = ((PsiClass)resolved).getContainingClass(); + if (aClass != null) { + final PsiElement qualifier = ref.getQualifier(); + final PsiElement place; + if (qualifier instanceof PsiJavaCodeReferenceElement) { + place = ((PsiJavaCodeReferenceElement)qualifier).resolve(); + } + else if (parent instanceof PsiNewExpression) { + final PsiExpression newQualifier = ((PsiNewExpression)parent).getQualifier(); + place = newQualifier == null ? ref : PsiUtil.resolveClassInType(newQualifier.getType()); + } + else { + place = ref; + } + if (place != null && PsiTreeUtil.isAncestor(aClass, place, false) && aClass.hasTypeParameters()) { + myHolder.add(HighlightClassUtil.checkCreateInnerClassFromStaticContext(ref, place, (PsiClass)resolved)); + } + } + else if (resolved instanceof PsiTypeParameter) { + final PsiTypeParameterListOwner owner = ((PsiTypeParameter)resolved).getOwner(); + if (owner instanceof PsiClass) { + final PsiClass outerClass = (PsiClass)owner; + if (!InheritanceUtil.hasEnclosingInstanceInScope(outerClass, ref, false, false)) { + myHolder.add(HighlightClassUtil.reportIllegalEnclosingUsage(ref, null, (PsiClass)owner, ref)); + } + } + } + } + + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkPackageAndClassConflict(ref, myFile)); } - } - } - if (!myHolder.hasErrorResults() && functionalInterfaceType != null) { - final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); - final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); - if (interfaceMethod != null) { - final PsiParameter[] parameters = interfaceMethod.getParameterList().getParameters(); - myHolder.add(LambdaHighlightingUtil.checkParametersCompatible(expression, parameters, LambdaUtil.getSubstitutor(interfaceMethod, resolveResult))); - } + return result; } - if (!myHolder.hasErrorResults()) { - final PsiElement body = expression.getBody(); - if (body instanceof PsiCodeBlock) { - myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement((PsiCodeBlock) body)); - } + @Nullable + private JavaResolveResult resolveOptimised(@Nonnull PsiJavaCodeReferenceElement ref) { + try { + if (ref instanceof PsiReferenceExpressionImpl) { + PsiReferenceExpressionImpl.OurGenericsResolver resolver = PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE; + JavaResolveResult[] results = JavaResolveUtil.resolveWithContainingFile(ref, resolver, true, true, myFile); + return results.length == 1 ? results[0] : JavaResolveResult.EMPTY; + } + else { + return ref.advancedResolve(true); + } + } + catch (IndexNotReadyException e) { + return null; + } } - } - @Override - public void visitBreakStatement(PsiBreakStatement statement) { - super.visitBreakStatement(statement); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkLabelDefined(statement.getLabelIdentifier(), statement.findExitedStatement())); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkBreakOutsideLoop(statement)); + @Nullable + private JavaResolveResult[] resolveOptimised(@Nonnull PsiReferenceExpression expression) { + try { + if (expression instanceof PsiReferenceExpressionImpl) { + PsiReferenceExpressionImpl.OurGenericsResolver resolver = PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE; + return JavaResolveUtil.resolveWithContainingFile(expression, resolver, true, true, myFile); + } + else { + return expression.multiResolve(true); + } + } + catch (IndexNotReadyException e) { + return null; + } } - } - @Override - public void visitClass(PsiClass aClass) { - super.visitClass(aClass); - if (aClass instanceof PsiSyntheticClass) { - return; - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkInterfaceMultipleInheritance(aClass)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.areSupersAccessible(aClass)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkDuplicateTopLevelClass(aClass)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkEnumMustNotBeLocal(aClass)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkEnumWithoutConstantsCantHaveAbstractMethods(aClass)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkImplicitThisReferenceBeforeSuper(aClass, myJavaSdkVersion)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkClassAndPackageConflict(aClass)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkPublicClassInRightFile(aClass)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkTypeParameterOverrideEquivalentMethods(aClass, myLanguageLevel)); - } - } - - @Override - public void visitClassInitializer(PsiClassInitializer initializer) { - super.visitClassInitializer(initializer); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightControlFlowUtil.checkInitializerCompleteNormally(initializer)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement(initializer.getBody())); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkThingNotAllowedInInterface(initializer, initializer.getContainingClass())); - } - } - - @Override - public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) { - super.visitClassObjectAccessExpression(expression); - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkClassObjectAccessExpression(expression)); - } - } - - @Override - public void visitComment(PsiComment comment) { - super.visitComment(comment); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkUnclosedComment(comment)); - } - if (myRefCountHolder != null && !myHolder.hasErrorResults()) { - registerReferencesFromInjectedFragments(comment); - } - } + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + JavaResolveResult resultForIncompleteCode = doVisitReferenceElement(expression); - @Override - public void visitContinueStatement(PsiContinueStatement statement) { - super.visitContinueStatement(statement); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkLabelDefined(statement.getLabelIdentifier(), statement.findContinuedStatement())); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkContinueOutsideLoop(statement)); - } - } + if (!myHolder.hasErrorResults()) { + visitExpression(expression); + if (myHolder.hasErrorResults()) { + return; + } + } - @Override - public void visitJavaToken(PsiJavaToken token) { - super.visitJavaToken(token); - if (!myHolder.hasErrorResults() && token.getTokenType() == JavaTokenType.RBRACE && token.getParent() instanceof PsiCodeBlock) { + JavaResolveResult[] results = resolveOptimised(expression); + if (results == null) { + return; + } + JavaResolveResult result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY; - final PsiElement gParent = token.getParent().getParent(); - final PsiCodeBlock codeBlock; - final PsiType returnType; - if (gParent instanceof PsiMethod) { - PsiMethod method = (PsiMethod) gParent; - codeBlock = method.getBody(); - returnType = method.getReturnType(); - } else if (gParent instanceof PsiLambdaExpression) { - final PsiElement body = ((PsiLambdaExpression) gParent).getBody(); - if (!(body instanceof PsiCodeBlock)) { - return; + PsiElement resolved = result.getElement(); + if (resolved instanceof PsiVariable && resolved.getContainingFile() == expression.getContainingFile()) { + if (!myHolder.hasErrorResults()) { + try { + myHolder.add(HighlightControlFlowUtil.checkVariableInitializedBeforeUsage( + expression, + (PsiVariable)resolved, + myUninitializedVarProblems, + myFile + )); + } + catch (IndexNotReadyException ignored) { + } + } + PsiVariable variable = (PsiVariable)resolved; + boolean isFinal = variable.hasModifierProperty(PsiModifier.FINAL); + if (isFinal && !variable.hasInitializer()) { + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightControlFlowUtil.checkFinalVariableMightAlreadyHaveBeenAssignedTo( + variable, + expression, + myFinalVarProblems + )); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightControlFlowUtil.checkFinalVariableInitializedInLoop(expression, resolved)); + } + } } - codeBlock = (PsiCodeBlock) body; - returnType = LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression) gParent); - } else { - return; - } - myHolder.add(HighlightControlFlowUtil.checkMissingReturnStatement(codeBlock, returnType)); - } - } - @Override - public void visitDocComment(PsiDocComment comment) { - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkUnclosedComment(comment)); - } - } + PsiElement parent = expression.getParent(); + if (parent instanceof PsiMethodCallExpression && ((PsiMethodCallExpression)parent).getMethodExpression() == expression && (!result.isAccessible() || !result.isStaticsScopeCorrect())) { + PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)parent; + PsiExpressionList list = methodCallExpression.getArgumentList(); + if (!HighlightMethodUtil.isDummyConstructorCall(methodCallExpression, myResolveHelper, list, expression)) { + try { + myHolder.add(HighlightMethodUtil.checkAmbiguousMethodCallIdentifier( + expression, + results, + list, + resolved, + result, + methodCallExpression, + myResolveHelper, + myLanguageLevel, + myFile + )); + + if (!PsiTreeUtil.findChildrenOfType(methodCallExpression.getArgumentList(), PsiLambdaExpression.class).isEmpty()) { + PsiElement nameElement = expression.getReferenceNameElement(); + if (nameElement != null) { + myHolder.add(HighlightMethodUtil.checkAmbiguousMethodCallArguments( + expression, + results, + list, + resolved, + result, + methodCallExpression, + myResolveHelper, + nameElement + )); + } + } + } + catch (IndexNotReadyException ignored) { + } + } + } - @Override - public void visitDocTagValue(PsiDocTagValue value) { - PsiReference reference = value.getReference(); - if (reference != null) { - PsiElement element = reference.resolve(); - final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); - if (element instanceof PsiMethod) { - PsiElement nameElement = ((PsiDocMethodOrFieldRef) value).getNameElement(); - if (nameElement != null) { - myHolder.add(HighlightNamesUtil.highlightMethodName((PsiMethod) element, nameElement, false, colorsScheme)); + if (!myHolder.hasErrorResults() && resultForIncompleteCode != null) { + myHolder.add(HighlightUtil.checkExpressionRequired(expression, resultForIncompleteCode)); } - } else if (element instanceof PsiParameter) { - myHolder.add(HighlightNamesUtil.highlightVariableName((PsiVariable) element, value.getNavigationElement(), colorsScheme)); - } - } - } - @Override - public void visitEnumConstant(PsiEnumConstant enumConstant) { - super.visitEnumConstant(enumConstant); - if (!myHolder.hasErrorResults()) { - GenericsHighlightUtil.checkEnumConstantForConstructorProblems(enumConstant, myHolder, myJavaSdkVersion); - } - if (!myHolder.hasErrorResults()) { - registerConstructorCall(enumConstant); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkUnhandledExceptions(enumConstant, null)); - } - } + if (!myHolder.hasErrorResults() && resolved instanceof PsiField) { + try { + myHolder.add(HighlightUtil.checkIllegalForwardReferenceToField(expression, (PsiField)resolved)); + } + catch (IndexNotReadyException ignored) { + } + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkAccessStaticFieldFromEnumConstructor(expression, result)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkClassReferenceAfterQualifier(expression, resolved)); + } + final PsiExpression qualifierExpression = expression.getQualifierExpression(); + myHolder.add(HighlightUtil.checkUnqualifiedSuperInDefaultMethod(myLanguageLevel, expression, qualifierExpression)); + if (!myHolder.hasErrorResults() && qualifierExpression != null) { + PsiType type = qualifierExpression.getType(); + if (type instanceof PsiCapturedWildcardType) { + type = ((PsiCapturedWildcardType)type).getUpperBound(); + } + final PsiClass psiClass = PsiUtil.resolveClassInType(type); + if (psiClass != null) { + myHolder.add(GenericsHighlightUtil.areSupersAccessible(psiClass, expression)); + } + } - @Override - public void visitEnumConstantInitializer(PsiEnumConstantInitializer enumConstantInitializer) { - super.visitEnumConstantInitializer(enumConstantInitializer); - if (!myHolder.hasErrorResults()) { - TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(enumConstantInitializer); - myHolder.add(HighlightClassUtil.checkClassMustBeAbstract(enumConstantInitializer, textRange)); + if (!myHolder.hasErrorResults() && resolved != null && myJavaModule != null) { + myHolder.add(ModuleHighlightUtil.checkPackageAccessibility(expression, resolved, myJavaModule)); + } } - } - @Override - public void visitExpression(PsiExpression expression) { - ProgressManager.checkCanceled(); // visitLiteralExpression is invoked very often in array initializers - - super.visitExpression(expression); - PsiType type = expression.getType(); - if (myHolder.add(HighlightUtil.checkMustBeBoolean(expression, type))) { - return; - } + @Override + public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { + myHolder.add(checkFeature(expression, JavaFeature.METHOD_REFERENCES)); + final PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent()); + if (parent instanceof PsiExpressionStatement) { + return; + } - if (expression instanceof PsiArrayAccessExpression) { - myHolder.add(HighlightUtil.checkValidArrayAccessExpression((PsiArrayAccessExpression) expression)); - } + final JavaResolveResult result; + final JavaResolveResult[] results; + try { + results = expression.multiResolve(true); + result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY; + } + catch (IndexNotReadyException e) { + return; + } + if (myRefCountHolder != null) { + myRefCountHolder.registerReference(expression, result); + } + final PsiElement method = result.getElement(); + if (method != null && !result.isAccessible()) { + final String accessProblem = HighlightUtil.buildProblemWithAccessDescription(expression, result); + HighlightInfo info = + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(accessProblem).create(); + HighlightUtil.registerAccessQuickFixAction((PsiMember)method, expression, info, result.getCurrentFileResolveScope()); + myHolder.add(info); + } + else { + final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); + if (method instanceof PsiMethod && !expression.isConstructor()) { + PsiElement methodNameElement = expression.getReferenceNameElement(); + if (methodNameElement != null) { + myHolder.add(HighlightNamesUtil.highlightMethodName((PsiMethod)method, methodNameElement, false, colorsScheme)); + } + } + myHolder.add(HighlightNamesUtil.highlightClassNameInQualifier(expression, colorsScheme)); + } - PsiElement parent = expression.getParent(); - if (parent instanceof PsiNewExpression && ((PsiNewExpression) parent).getQualifier() != expression && ((PsiNewExpression) parent).getArrayInitializer() != expression) { - // like in 'new String["s"]' - myHolder.add(HighlightUtil.checkAssignability(PsiType.INT, expression.getType(), expression, expression)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightControlFlowUtil.checkCannotWriteToFinal(expression, myFile)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkVariableExpected(expression)); - } - if (!myHolder.hasErrorResults()) { - myHolder.addAll(HighlightUtil.checkArrayInitializer(expression, type)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkTernaryOperatorConditionIsBoolean(expression, type)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkAssertOperatorTypes(expression, type)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkSynchronizedExpressionType(expression, type, myFile)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkConditionalExpressionBranchTypesMatch(expression, type)); - } - if (!myHolder.hasErrorResults() && parent instanceof PsiThrowStatement && ((PsiThrowStatement) parent).getException() == expression) { - myHolder.add(HighlightUtil.checkMustBeThrowable(type, expression, true)); - } + if (!LambdaUtil.isValidLambdaContext(parent)) { + String description = "Method reference expression is not expected here"; + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(description) + .create()); + } - if (!myHolder.hasErrorResults()) { - myHolder.add(AnnotationsHighlightUtil.checkConstantExpression(expression)); - } - if (!myHolder.hasErrorResults() && parent instanceof PsiForeachStatement && ((PsiForeachStatement) parent).getIteratedValue() == expression) { - myHolder.add(GenericsHighlightUtil.checkForeachExpressionTypeIsIterable(expression)); - } - } + final PsiType functionalInterfaceType = expression.getFunctionalInterfaceType(); + if (!myHolder.hasErrorResults()) { + if (functionalInterfaceType != null) { + final boolean notFunctional = !LambdaUtil.isFunctionalType(functionalInterfaceType); + if (notFunctional) { + String description = functionalInterfaceType.getPresentableText() + " is not a functional interface"; + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(description) + .create()); + } + } + } + if (!myHolder.hasErrorResults()) { + final PsiElement referenceNameElement = expression.getReferenceNameElement(); + if (referenceNameElement instanceof PsiKeyword) { + if (!PsiMethodReferenceUtil.isValidQualifier(expression)) { + PsiElement qualifier = expression.getQualifier(); + if (qualifier != null) { + String description = "Cannot find class " + qualifier.getText(); + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(qualifier) + .descriptionAndTooltip(description) + .create()); + } + } + } + } + if (!myHolder.hasErrorResults()) { + checkFunctionalInterfaceTypeAccessible(expression, functionalInterfaceType); + } - @Override - public void visitExpressionList(PsiExpressionList list) { - super.visitExpressionList(list); - PsiElement parent = list.getParent(); - if (parent instanceof PsiMethodCallExpression) { - PsiMethodCallExpression expression = (PsiMethodCallExpression) parent; - if (expression.getArgumentList() == list) { - PsiReferenceExpression referenceExpression = expression.getMethodExpression(); - JavaResolveResult[] results = resolveOptimised(referenceExpression); - if (results == null) { - return; + if (!myHolder.hasErrorResults() && functionalInterfaceType != null) { + final String errorMessage = PsiMethodReferenceUtil.checkMethodReferenceContext(expression); + if (errorMessage != null) { + final HighlightInfo info = + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(errorMessage).create(); + if (method instanceof PsiMethod && !((PsiMethod)method).isConstructor() && !((PsiMethod)method).hasModifierProperty( + PsiModifier.ABSTRACT)) { + final boolean shouldHave = !((PsiMethod)method).hasModifierProperty(PsiModifier.STATIC); + final LocalQuickFixAndIntentionActionOnPsiElement fixStaticModifier = + QuickFixFactory.getInstance().createModifierListFix( + (PsiModifierListOwner)method, + PsiModifier.STATIC, + shouldHave, false + ); + QuickFixAction.registerQuickFixAction(info, fixStaticModifier); + } + myHolder.add(info); + } } - JavaResolveResult result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY; - PsiElement resolved = result.getElement(); - if ((!result.isAccessible() || !result.isStaticsScopeCorrect()) && !HighlightMethodUtil.isDummyConstructorCall(expression, myResolveHelper, list, referenceExpression) && - // this check is for fake expression from JspMethodCallImpl - referenceExpression.getParent() == expression) { - try { - if (PsiTreeUtil.findChildrenOfType(expression.getArgumentList(), PsiLambdaExpression.class).isEmpty()) { - myHolder.add(HighlightMethodUtil.checkAmbiguousMethodCallArguments(referenceExpression, results, list, resolved, result, expression, myResolveHelper, list)); + if (!myHolder.hasErrorResults()) { + PsiElement qualifier = expression.getQualifier(); + if (qualifier instanceof PsiTypeElement) { + final PsiType psiType = ((PsiTypeElement)qualifier).getType(); + final HighlightInfo genericArrayCreationInfo = GenericsHighlightUtil.checkGenericArrayCreation(qualifier, psiType); + if (genericArrayCreationInfo != null) { + myHolder.add(genericArrayCreationInfo); + } + else { + final String wildcardMessage = PsiMethodReferenceUtil.checkTypeArguments((PsiTypeElement)qualifier, psiType); + if (wildcardMessage != null) { + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(qualifier) + .descriptionAndTooltip(wildcardMessage) + .create()); + } + } } - } catch (IndexNotReadyException ignored) { - } } - } - } - } - @Override - public void visitField(PsiField field) { - super.visitField(field); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightControlFlowUtil.checkFinalFieldInitialized(field)); - } - } + if (!myHolder.hasErrorResults()) { + myHolder.add(PsiMethodReferenceHighlightingUtil.checkRawConstructorReference(expression)); + } - @Override - public void visitForStatement(PsiForStatement statement) { - myHolder.add(HighlightUtil.checkForStatement(statement)); - } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkUnhandledExceptions(expression, expression.getTextRange())); + } - @Override - public void visitForeachStatement(PsiForeachStatement statement) { - myHolder.add(checkFeature(statement, JavaFeature.FOR_EACH)); - } + if (!myHolder.hasErrorResults()) { + final String badReturnTypeMessage = PsiMethodReferenceUtil.checkReturnType(expression, result, functionalInterfaceType); + if (badReturnTypeMessage != null) { + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(badReturnTypeMessage) + .create()); + } + } - @Override - public void visitImportStaticStatement(PsiImportStaticStatement statement) { - myHolder.add(checkFeature(statement, JavaFeature.STATIC_IMPORTS)); - if (!myHolder.hasErrorResults()) { - myHolder.add(ImportsHighlightUtil.checkStaticOnDemandImportResolvesToClass(statement)); + if (!myHolder.hasErrorResults()) { + if (results.length == 0 || results[0] instanceof MethodCandidateInfo && !((MethodCandidateInfo)results[0]).isApplicable() && functionalInterfaceType != null) { + String description = null; + if (results.length == 1) { + description = ((MethodCandidateInfo)results[0]).getInferenceErrorMessage(); + } + if (expression.isConstructor()) { + final PsiClass containingClass = PsiMethodReferenceUtil.getQualifierResolveResult(expression).getContainingClass(); + + if (containingClass != null) { + if (!myHolder.add(HighlightClassUtil.checkInstantiationOfAbstractClass( + containingClass, + expression + )) && !myHolder.add(GenericsHighlightUtil.checkEnumInstantiation( + expression, + containingClass + )) && containingClass.isPhysical() && description == null) { + description = JavaErrorBundle.message("cannot.resolve.constructor", containingClass.getName()); + } + } + } + else if (description == null) { + description = JavaErrorBundle.message("cannot.resolve.method", expression.getReferenceName()); + } + + if (description != null) { + PsiElement referenceNameElement = notNull(expression.getReferenceNameElement(), expression); + HighlightInfoType type = results.length == 0 ? HighlightInfoType.WRONG_REF : HighlightInfoType.ERROR; + HighlightInfo highlightInfo = + HighlightInfo.newHighlightInfo(type).descriptionAndTooltip(description).range(referenceNameElement).create(); + myHolder.add(highlightInfo); + TextRange fixRange = HighlightMethodUtil.getFixRange(referenceNameElement); + QuickFixAction.registerQuickFixAction( + highlightInfo, + fixRange, + QuickFixFactory.getInstance().createCreateMethodFromUsageFix(expression) + ); + } + } + } } - } - - @Override - public void visitIdentifier(final PsiIdentifier identifier) { - TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); - PsiElement parent = identifier.getParent(); - if (parent instanceof PsiVariable) { - PsiVariable variable = (PsiVariable) parent; - myHolder.add(HighlightUtil.checkVariableAlreadyDefined(variable)); - - if (variable.getInitializer() == null) { - final PsiElement child = variable.getLastChild(); - if (child instanceof PsiErrorElement && child.getPrevSibling() == identifier) { - return; + // 15.13 | 15.27 + // It is a compile-time error if any class or interface mentioned by either U or the function type of U + // is not accessible from the class or interface in which the method reference expression appears. + private void checkFunctionalInterfaceTypeAccessible(@Nonnull PsiFunctionalExpression expression, PsiType functionalInterfaceType) { + PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); + final PsiClass psiClass = resolveResult.getElement(); + if (psiClass != null) { + if (!PsiUtil.isAccessible(myFile.getProject(), psiClass, expression, null)) { + String text = HighlightUtil.buildProblemWithAccessDescription(expression, resolveResult); + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(text) + .create()); + } + else { + for (PsiType type : resolveResult.getSubstitutor().getSubstitutionMap().values()) { + checkFunctionalInterfaceTypeAccessible(expression, type); + } + } } - } + } - boolean isMethodParameter = variable instanceof PsiParameter && ((PsiParameter) variable).getDeclarationScope() instanceof PsiMethod; - if (isMethodParameter) { - myReassignedParameters.putInt((PsiParameter) variable, 1); // mark param as present in current file - } else { - // method params are highlighted in visitMethod since we should make sure the method body was visited before - if (HighlightControlFlowUtil.isReassigned(variable, myFinalVarProblems)) { - myHolder.add(HighlightNamesUtil.highlightReassignedVariable(variable, identifier)); - } else { - myHolder.add(HighlightNamesUtil.highlightVariableName(variable, identifier, colorsScheme)); - } - } - } else if (parent instanceof PsiClass) { - PsiClass aClass = (PsiClass) parent; - if (aClass.isAnnotationType()) { - myHolder.add(checkFeature(identifier, JavaFeature.ANNOTATIONS)); - } - - myHolder.add(HighlightClassUtil.checkClassAlreadyImported(aClass, identifier)); - if (!(parent instanceof PsiAnonymousClass) && aClass.getNameIdentifier() == identifier) { - myHolder.add(HighlightNamesUtil.highlightClassName(aClass, identifier, colorsScheme)); - } - if (!myHolder.hasErrorResults() && myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { - myHolder.add(GenericsHighlightUtil.checkUnrelatedDefaultMethods(aClass, identifier)); - } - - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkUnrelatedConcrete(aClass, identifier)); - } - } else if (parent instanceof PsiMethod) { - PsiMethod method = (PsiMethod) parent; - if (method.isConstructor()) { - myHolder.add(HighlightMethodUtil.checkConstructorName(method)); - } - myHolder.add(HighlightNamesUtil.highlightMethodName(method, identifier, true, colorsScheme)); - final PsiClass aClass = method.getContainingClass(); - if (aClass != null) { - myHolder.add(GenericsHighlightUtil.checkDefaultMethodOverrideEquivalentToObjectNonPrivate(myLanguageLevel, aClass, method, identifier)); - } - } - - myHolder.add(HighlightUtil.checkUnderscore(identifier, myLanguageLevel)); - - super.visitIdentifier(identifier); - } - - @Override - public void visitImportStatement(final PsiImportStatement statement) { - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkSingleImportClassConflict(statement, mySingleImportedClasses, myFile)); - } - } - - @Override - public void visitImportStaticReferenceElement(@Nonnull PsiImportStaticReferenceElement ref) { - final String refName = ref.getReferenceName(); - final JavaResolveResult[] results = ref.multiResolve(false); - - final PsiElement referenceNameElement = ref.getReferenceNameElement(); - if (results.length == 0) { - final String description = JavaErrorBundle.message("cannot.resolve.symbol", refName); - assert referenceNameElement != null : ref; - final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(referenceNameElement).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createSetupJDKFix()); - myHolder.add(info); - } else { - final PsiManager manager = ref.getManager(); - for (JavaResolveResult result : results) { - final PsiElement element = result.getElement(); - - String description = null; - if (element instanceof PsiClass) { - final Pair imported = mySingleImportedClasses.get(refName); - final PsiClass aClass = imported == null ? null : imported.getSecond(); - if (aClass != null && !manager.areElementsEquivalent(aClass, element)) { - //noinspection ConditionalExpressionWithIdenticalBranches - description = imported.first == null ? JavaErrorBundle.message("single.import.class.conflict", refName) : imported.first.equals(ref) ? JavaErrorBundle.message("class.is" + - ".ambiguous.in.single.static.import", refName) : JavaErrorBundle.message("class.is.already.defined.in.single.static.import", refName); - } - mySingleImportedClasses.put(refName, Pair.create(ref, (PsiClass) element)); - } else if (element instanceof PsiField) { - final Pair imported = mySingleImportedFields.get(refName); - final PsiField field = imported == null ? null : imported.getSecond(); - if (field != null && !manager.areElementsEquivalent(field, element)) { - //noinspection ConditionalExpressionWithIdenticalBranches - description = imported.first.equals(ref) ? JavaErrorBundle.message("field.is.ambiguous.in.single.static.import", refName) : JavaErrorBundle.message("field.is.already" + - ".defined.in.single.static.import", refName); - } - mySingleImportedFields.put(refName, Pair.create(ref, (PsiField) element)); - } - - if (description != null) { - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(ref).descriptionAndTooltip(description).create()); - } - } - } - if (!myHolder.hasErrorResults()) { - PsiElement resolved = results.length >= 1 ? results[0].getElement() : null; - if (results.length > 1) { - for (int i = 1; i < results.length; i++) { - final PsiElement element = results[i].getElement(); - if (resolved instanceof PsiMethod && !(element instanceof PsiMethod) || resolved instanceof PsiVariable && !(element instanceof PsiVariable) || resolved instanceof PsiClass && ! - (element instanceof PsiClass)) { - resolved = null; - break; - } - } - } - final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); - if (resolved instanceof PsiClass) { - myHolder.add(HighlightNamesUtil.highlightClassName((PsiClass) resolved, ref, colorsScheme)); - } else { - myHolder.add(HighlightNamesUtil.highlightClassNameInQualifier(ref, colorsScheme)); - if (referenceNameElement != null) { - if (resolved instanceof PsiVariable) { - myHolder.add(HighlightNamesUtil.highlightVariableName((PsiVariable) resolved, referenceNameElement, colorsScheme)); - } else if (resolved instanceof PsiMethod) { - myHolder.add(HighlightNamesUtil.highlightMethodName((PsiMethod) resolved, referenceNameElement, false, colorsScheme)); - } - } - } - } - } - - @Override - public void visitInstanceOfExpression(PsiInstanceOfExpression expression) { - super.visitInstanceOfExpression(expression); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkInstanceOfApplicable(expression)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkInstanceOfGenericType(expression)); - } - } - - @Override - public void visitKeyword(PsiKeyword keyword) { - super.visitKeyword(keyword); - PsiElement parent = keyword.getParent(); - String text = keyword.getText(); - if (parent instanceof PsiModifierList) { - PsiModifierList psiModifierList = (PsiModifierList) parent; - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkNotAllowedModifier(keyword, psiModifierList)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkIllegalModifierCombination(keyword, psiModifierList)); - } - if (PsiModifier.ABSTRACT.equals(text) && psiModifierList.getParent() instanceof PsiMethod) { - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightMethodUtil.checkAbstractMethodInConcreteClass((PsiMethod) psiModifierList.getParent(), keyword)); - } - } - } else if (PsiKeyword.INTERFACE.equals(text) && parent instanceof PsiClass) { - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkInterfaceCannotBeLocal((PsiClass) parent)); - } - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkStaticDeclarationInInnerClass(keyword, myLanguageLevel)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkIllegalVoidType(keyword)); - } - } - - @Override - public void visitLabeledStatement(PsiLabeledStatement statement) { - super.visitLabeledStatement(statement); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkLabelWithoutStatement(statement)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkLabelAlreadyInUse(statement)); - } - } - - @Override - public void visitLiteralExpression(PsiLiteralExpression expression) { - super.visitLiteralExpression(expression); - if (myHolder.hasErrorResults()) { - return; - } - myHolder.add(HighlightUtil.checkLiteralExpressionParsingError(expression, myLanguageLevel, myFile)); - if (myRefCountHolder != null && !myHolder.hasErrorResults()) { - registerReferencesFromInjectedFragments(expression); - } - - if (myRefCountHolder != null && !myHolder.hasErrorResults()) { - for (PsiReference reference : expression.getReferences()) { - PsiElement resolve = reference.resolve(); - if (resolve instanceof PsiMember) { - myRefCountHolder.registerReference(reference, new CandidateInfo(resolve, PsiSubstitutor.EMPTY)); - } - } - } - } - - @Override - public void visitMethod(PsiMethod method) { - super.visitMethod(method); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement(method.getBody())); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightMethodUtil.checkConstructorHandleSuperClassExceptions(method)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightMethodUtil.checkRecursiveConstructorInvocation(method)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkSafeVarargsAnnotation(method, myLanguageLevel)); - } - - PsiClass aClass = method.getContainingClass(); - if (!myHolder.hasErrorResults() && method.isConstructor()) { - myHolder.add(HighlightClassUtil.checkThingNotAllowedInInterface(method, aClass)); - } - if (!myHolder.hasErrorResults() && method.hasModifierProperty(PsiModifier.DEFAULT)) { - myHolder.add(checkFeature(method, JavaFeature.EXTENSION_METHODS)); - } - if (!myHolder.hasErrorResults() && aClass != null && aClass.isInterface() && method.hasModifierProperty(PsiModifier.STATIC)) { - myHolder.add(checkFeature(method, JavaFeature.EXTENSION_METHODS)); - } - if (!myHolder.hasErrorResults() && aClass != null) { - myHolder.add(HighlightMethodUtil.checkDuplicateMethod(aClass, method, getDuplicateMethods(aClass))); - } - - // method params are highlighted in visitMethod since we should make sure the method body was visited before - PsiParameter[] parameters = method.getParameterList().getParameters(); - final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); - - for (PsiParameter parameter : parameters) { - int info = myReassignedParameters.getInt(parameter); - if (info == 0) { - continue; // out of this file - } - - PsiIdentifier nameIdentifier = parameter.getNameIdentifier(); - if (nameIdentifier != null) { - if (info == 2) { // reassigned - myHolder.add(HighlightNamesUtil.highlightReassignedVariable(parameter, nameIdentifier)); - } else { - myHolder.add(HighlightNamesUtil.highlightVariableName(parameter, nameIdentifier, colorsScheme)); - } - } - } - } - - private void highlightReferencedMethodOrClassName(@Nonnull PsiJavaCodeReferenceElement element, PsiElement resolved) { - PsiElement parent = element.getParent(); - final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); - if (parent instanceof PsiMethodCallExpression) { - PsiMethod method = ((PsiMethodCallExpression) parent).resolveMethod(); - PsiElement methodNameElement = element.getReferenceNameElement(); - if (method != null && methodNameElement != null && !(methodNameElement instanceof PsiKeyword)) { - myHolder.add(HighlightNamesUtil.highlightMethodName(method, methodNameElement, false, colorsScheme)); - myHolder.add(HighlightNamesUtil.highlightClassNameInQualifier(element, colorsScheme)); - } - } else if (parent instanceof PsiConstructorCall) { - try { - PsiMethod method = ((PsiConstructorCall) parent).resolveConstructor(); - PsiMember methodOrClass = method != null ? method : resolved instanceof PsiClass ? (PsiClass) resolved : null; - if (methodOrClass != null) { - final PsiElement referenceNameElement = element.getReferenceNameElement(); - if (referenceNameElement != null) { - // exclude type parameters from the highlighted text range - TextRange range = referenceNameElement.getTextRange(); - myHolder.add(HighlightNamesUtil.highlightMethodName(methodOrClass, referenceNameElement, range, colorsScheme, false)); - } - } - } catch (IndexNotReadyException ignored) { - } - } else if (resolved instanceof PsiPackage) { - // highlight package (and following dot) as a class - myHolder.add(HighlightNamesUtil.highlightPackage(resolved, element, colorsScheme)); - } else if (resolved instanceof PsiClass) { - myHolder.add(HighlightNamesUtil.highlightClassName((PsiClass) resolved, element, colorsScheme)); - } - } - - @Override - public void visitMethodCallExpression(PsiMethodCallExpression expression) { - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkEnumSuperConstructorCall(expression)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkSuperQualifierType(myFile.getProject(), expression)); - } - // in case of JSP synthetic method call, do not check - if (myFile.isPhysical() && !myHolder.hasErrorResults()) { - try { - myHolder.add(HighlightMethodUtil.checkMethodCall(expression, myResolveHelper, myLanguageLevel, myJavaSdkVersion, myFile)); - } catch (IndexNotReadyException ignored) { - } - } - - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightMethodUtil.checkConstructorCallMustBeFirstStatement(expression)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightMethodUtil.checkSuperAbstractMethodDirectCall(expression)); - } - - if (!myHolder.hasErrorResults()) { - visitExpression(expression); - } - } - - @Override - public void visitModifierList(PsiModifierList list) { - super.visitModifierList(list); - PsiElement parent = list.getParent(); - if (parent instanceof PsiMethod) { - PsiMethod method = (PsiMethod) parent; - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightMethodUtil.checkMethodCanHaveBody(method, myLanguageLevel)); - } - MethodSignatureBackedByPsiMethod methodSignature = MethodSignatureBackedByPsiMethod.create(method, PsiSubstitutor.EMPTY); - if (!method.isConstructor()) { - try { - List superMethodSignatures = method.getHierarchicalMethodSignature().getSuperSignatures(); - if (!superMethodSignatures.isEmpty()) { + @Override + public void visitReferenceList(PsiReferenceList list) { + if (list.getFirstChild() == null) { + return; + } + PsiElement parent = list.getParent(); + if (!(parent instanceof PsiTypeParameter)) { + myHolder.add(AnnotationsHighlightUtil.checkAnnotationDeclaration(parent, list)); if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightMethodUtil.checkMethodIncompatibleReturnType(methodSignature, superMethodSignatures, true)); + myHolder.add(HighlightClassUtil.checkExtendsAllowed(list)); } if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightMethodUtil.checkMethodIncompatibleThrows(methodSignature, superMethodSignatures, true, method.getContainingClass())); + myHolder.add(HighlightClassUtil.checkImplementsAllowed(list)); } - if (!method.hasModifierProperty(PsiModifier.STATIC)) { - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightMethodUtil.checkMethodWeakerPrivileges(methodSignature, superMethodSignatures, true, myFile)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightMethodUtil.checkMethodOverridesFinal(methodSignature, superMethodSignatures)); - } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkClassExtendsOnlyOneClass(list)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkGenericCannotExtendException(list)); } - } - } catch (IndexNotReadyException ignored) { } - } - PsiClass aClass = method.getContainingClass(); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightMethodUtil.checkMethodMustHaveBody(method, aClass)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightMethodUtil.checkConstructorCallsBaseClassConstructor(method, myRefCountHolder, myResolveHelper)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightMethodUtil.checkStaticMethodOverride(method, myFile)); - } - if (!myHolder.hasErrorResults() && aClass != null && myOverrideEquivalentMethodsVisitedClasses.add(aClass)) { - myHolder.addAll(GenericsHighlightUtil.checkOverrideEquivalentMethods(aClass)); - } - } else if (parent instanceof PsiClass) { - PsiClass aClass = (PsiClass) parent; - try { + } + + @Override + public void visitReferenceParameterList(PsiReferenceParameterList list) { + if (list.getTextLength() == 0) { + return; + } + + myHolder.add(checkFeature(list, JavaFeature.GENERICS)); + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkParametersAllowed(list)); + } if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkDuplicateNestedClass(aClass)); + myHolder.add(GenericsHighlightUtil.checkParametersOnRaw(list)); } if (!myHolder.hasErrorResults()) { - TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - myHolder.add(HighlightClassUtil.checkClassMustBeAbstract(aClass, textRange)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkClassDoesNotCallSuperConstructorOrHandleExceptions(aClass, myRefCountHolder, myResolveHelper)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightMethodUtil.checkOverrideEquivalentInheritedMethods(aClass, myFile, myLanguageLevel)); - } - if (!myHolder.hasErrorResults() && myOverrideEquivalentMethodsVisitedClasses.add(aClass)) { - myHolder.addAll(GenericsHighlightUtil.checkOverrideEquivalentMethods(aClass)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkCyclicInheritance(aClass)); - } - } catch (IndexNotReadyException ignored) { - } - } else if (parent instanceof PsiEnumConstant) { - if (!myHolder.hasErrorResults()) { - myHolder.addAll(GenericsHighlightUtil.checkEnumConstantModifierList(list)); - } - } - } - - @Override - public void visitNameValuePair(PsiNameValuePair pair) { - myHolder.add(AnnotationsHighlightUtil.checkNameValuePair(pair)); - if (!myHolder.hasErrorResults()) { - PsiIdentifier nameId = pair.getNameIdentifier(); - if (nameId != null) { - HighlightInfo result = HighlightInfo.newHighlightInfo(JavaHighlightInfoTypes.ANNOTATION_ATTRIBUTE_NAME).range(nameId).create(); - myHolder.add(result); - } - } - } - - @Override - public void visitNewExpression(PsiNewExpression expression) { - final PsiType type = expression.getType(); - final PsiClass aClass = PsiUtil.resolveClassInType(type); - myHolder.add(HighlightUtil.checkUnhandledExceptions(expression, null)); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkAnonymousInheritFinal(expression)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkQualifiedNew(expression, type, aClass)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkCreateInnerClassFromStaticContext(expression, type, aClass)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkTypeParameterInstantiation(expression)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkInstantiationOfAbstractClass(aClass, expression)); - } - try { - if (!myHolder.hasErrorResults()) { - HighlightMethodUtil.checkNewExpression(expression, type, myHolder, myJavaSdkVersion); - } - } catch (IndexNotReadyException ignored) { - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkEnumInstantiation(expression, aClass)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkGenericArrayCreation(expression, type)); - } - if (!myHolder.hasErrorResults()) { - registerConstructorCall(expression); - } - - if (!myHolder.hasErrorResults()) { - visitExpression(expression); - } - } - - @Override - public void visitPackageStatement(PsiPackageStatement statement) { - super.visitPackageStatement(statement); - myHolder.add(AnnotationsHighlightUtil.checkPackageAnnotationContainingFile(statement, myFile)); - if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { - if (!myHolder.hasErrorResults()) { - myHolder.add(ModuleHighlightUtil.checkPackageStatement(statement, myFile, myJavaModule)); - } - } - } - - @Override - public void visitParameter(PsiParameter parameter) { - super.visitParameter(parameter); - - final PsiElement parent = parameter.getParent(); - if (parent instanceof PsiParameterList && parameter.isVarArgs()) { - if (!myHolder.hasErrorResults()) { - myHolder.add(checkFeature(parameter, JavaFeature.VARARGS)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkVarArgParameterIsLast(parameter)); - } - } else if (parent instanceof PsiCatchSection) { - if (!myHolder.hasErrorResults() && parameter.getType() instanceof PsiDisjunctionType) { - myHolder.add(checkFeature(parameter, JavaFeature.MULTI_CATCH)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkCatchParameterIsThrowable(parameter)); - } - if (!myHolder.hasErrorResults()) { - myHolder.addAll(GenericsHighlightUtil.checkCatchParameterIsClass(parameter)); - } - if (!myHolder.hasErrorResults()) { - myHolder.addAll(HighlightUtil.checkCatchTypeIsDisjoint(parameter)); - } - } else if (parent instanceof PsiForeachStatement) { - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkForEachParameterType((PsiForeachStatement) parent, parameter)); - } - } - } - - @Override - public void visitParameterList(PsiParameterList list) { - super.visitParameterList(list); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkAnnotationMethodParameters(list)); - } - } - - @Override - public void visitPostfixExpression(PsiPostfixExpression expression) { - super.visitPostfixExpression(expression); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkUnaryOperatorApplicable(expression.getOperationSign(), expression.getOperand())); + for (PsiTypeElement typeElement : list.getTypeParameterElements()) { + if (typeElement.getType() instanceof PsiDiamondType) { + myHolder.add(checkFeature(list, JavaFeature.DIAMOND_TYPES)); + } + } + } } - } - @Override - public void visitPrefixExpression(PsiPrefixExpression expression) { - super.visitPrefixExpression(expression); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkUnaryOperatorApplicable(expression.getOperationSign(), expression.getOperand())); + @Override + public void visitReturnStatement(PsiReturnStatement statement) { + try { + myHolder.add(HighlightUtil.checkReturnStatementType(statement)); + } + catch (IndexNotReadyException ignore) { + } } - } - private void registerConstructorCall(@Nonnull PsiConstructorCall constructorCall) { - if (myRefCountHolder != null) { - JavaResolveResult resolveResult = constructorCall.resolveMethodGenerics(); - final PsiElement resolved = resolveResult.getElement(); - if (resolved instanceof PsiNamedElement) { - myRefCountHolder.registerLocallyReferenced((PsiNamedElement) resolved); - } - } - } - - @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement ref) { - JavaResolveResult result = doVisitReferenceElement(ref); - if (result != null) { - PsiElement resolved = result.getElement(); - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkRawOnParameterizedType(ref, resolved)); - } - if (!myHolder.hasErrorResults() && resolved != null && myJavaModule != null) { - myHolder.add(ModuleHighlightUtil.checkPackageAccessibility(ref, resolved, myJavaModule)); - } + @Override + public void visitStatement(PsiStatement statement) { + super.visitStatement(statement); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkNotAStatement(statement)); + } } - } - private JavaResolveResult doVisitReferenceElement(@Nonnull PsiJavaCodeReferenceElement ref) { - JavaResolveResult result = resolveOptimised(ref); - if (result == null) { - return null; - } - - PsiElement resolved = result.getElement(); - PsiElement parent = ref.getParent(); - - if (myRefCountHolder != null) { - myRefCountHolder.registerReference(ref, result); - } - - myHolder.add(HighlightUtil.checkReference(ref, result, myFile, myLanguageLevel)); - - if (parent instanceof PsiJavaCodeReferenceElement || ref.isQualified()) { - if (!myHolder.hasErrorResults() && resolved instanceof PsiTypeParameter) { - boolean canSelectFromTypeParameter = myJavaSdkVersion.isAtLeast(JavaSdkVersion.JDK_1_7); - if (canSelectFromTypeParameter) { - final PsiClass containingClass = PsiTreeUtil.getParentOfType(ref, PsiClass.class); - if (containingClass != null) { - if (PsiTreeUtil.isAncestor(containingClass.getExtendsList(), ref, false) || PsiTreeUtil.isAncestor(containingClass.getImplementsList(), ref, false)) { - canSelectFromTypeParameter = false; - } - } - } - if (!canSelectFromTypeParameter) { - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip("Cannot select from a type parameter").range(ref).create()); - } - } + @Override + public void visitSuperExpression(PsiSuperExpression expr) { + myHolder.add(HighlightUtil.checkThisOrSuperExpressionInIllegalContext(expr, expr.getQualifier(), myLanguageLevel)); + if (!myHolder.hasErrorResults()) { + visitExpression(expr); + } } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkAbstractInstantiation(ref)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkExtendsDuplicate(ref, resolved, myFile)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkClassExtendsForeignInnerClass(ref, resolved)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkSelectStaticClassFromParameterizedType(resolved, ref)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, ref, result.getSubstitutor(), myJavaSdkVersion)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkCannotPassInner(ref)); + @Override + public void visitSwitchLabelStatement(PsiSwitchLabelStatement statement) { + super.visitSwitchLabelStatement(statement); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkCaseStatement(statement)); + } } - if (resolved != null && parent instanceof PsiReferenceList) { - if (!myHolder.hasErrorResults()) { - PsiReferenceList referenceList = (PsiReferenceList) parent; - myHolder.add(HighlightUtil.checkElementInReferenceList(ref, referenceList, result)); - } + @Override + public void visitSwitchLabeledRuleStatement(PsiSwitchLabeledRuleStatement statement) { + super.visitSwitchLabeledRuleStatement(statement); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkCaseStatement(statement)); + } } - if (parent instanceof PsiAnonymousClass && ref.equals(((PsiAnonymousClass) parent).getBaseClassReference()) && myOverrideEquivalentMethodsVisitedClasses.add((PsiClass) parent)) { - PsiClass aClass = (PsiClass) parent; - myHolder.addAll(GenericsHighlightUtil.checkOverrideEquivalentMethods(aClass)); - } - if (resolved instanceof PsiVariable) { - PsiVariable variable = (PsiVariable) resolved; + @Override + public void visitSwitchStatement(PsiSwitchStatement statement) { + super.visitSwitchStatement(statement); + checkSwitchBlock(statement); + } - PsiElement containingClass = PsiTreeUtil.getNonStrictParentOfType(ref, PsiClass.class, PsiLambdaExpression.class); - if ((containingClass instanceof PsiAnonymousClass || containingClass instanceof PsiLambdaExpression) && !PsiTreeUtil.isAncestor(containingClass, variable, false) && !(variable instanceof - PsiField) && (containingClass instanceof PsiLambdaExpression || !PsiTreeUtil.isAncestor(((PsiAnonymousClass) containingClass).getArgumentList(), ref, false))) { - myHolder.add(HighlightInfo.newHighlightInfo(JavaHighlightInfoTypes.IMPLICIT_ANONYMOUS_CLASS_PARAMETER).range(ref).create()); - } + private void checkSwitchBlock(PsiSwitchBlock switchBlock) { + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkSwitchBlockStatements(switchBlock, myLanguageLevel, myFile)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkSwitchSelectorType(switchBlock, myLanguageLevel)); + } + if (!myHolder.hasErrorResults()) { + myHolder.addAll(HighlightUtil.checkSwitchLabelValues(switchBlock)); + } + } - if (variable instanceof PsiParameter && ref instanceof PsiExpression && PsiUtil.isAccessedForWriting((PsiExpression) ref)) { - myReassignedParameters.putInt((PsiParameter) variable, 2); - } + @Override + public void visitThisExpression(PsiThisExpression expr) { + if (!(expr.getParent() instanceof PsiReceiverParameter)) { + myHolder.add(HighlightUtil.checkThisOrSuperExpressionInIllegalContext(expr, expr.getQualifier(), myLanguageLevel)); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkMemberReferencedBeforeConstructorCalled(expr, null, myFile)); + } + if (!myHolder.hasErrorResults()) { + visitExpression(expr); + } + } + } - final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); - if (!variable.hasModifierProperty(PsiModifier.FINAL) && isReassigned(variable)) { - myHolder.add(HighlightNamesUtil.highlightReassignedVariable(variable, ref)); - } else { - PsiElement nameElement = ref.getReferenceNameElement(); - if (nameElement != null) { - myHolder.add(HighlightNamesUtil.highlightVariableName(variable, nameElement, colorsScheme)); + @Override + public void visitThrowStatement(PsiThrowStatement statement) { + myHolder.add(HighlightUtil.checkUnhandledExceptions(statement, null)); + if (!myHolder.hasErrorResults()) { + visitStatement(statement); } - } - myHolder.add(HighlightNamesUtil.highlightClassNameInQualifier(ref, colorsScheme)); - } else { - highlightReferencedMethodOrClassName(ref, resolved); } - if (parent instanceof PsiNewExpression && !(resolved instanceof PsiClass) && resolved instanceof PsiNamedElement && ((PsiNewExpression) parent).getClassOrAnonymousClassReference() == ref) { - String text = JavaErrorBundle.message("cannot.resolve.symbol", ((PsiNamedElement) resolved).getName()); - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(ref).descriptionAndTooltip(text).create()); + @Override + public void visitTryStatement(PsiTryStatement statement) { + super.visitTryStatement(statement); + if (!myHolder.hasErrorResults()) { + final Set thrownTypes = HighlightUtil.collectUnhandledExceptions(statement); + for (PsiParameter parameter : statement.getCatchBlockParameters()) { + boolean added = myHolder.addAll(HighlightUtil.checkExceptionAlreadyCaught(parameter)); + if (!added) { + added = myHolder.addAll(HighlightUtil.checkExceptionThrownInTry(parameter, thrownTypes)); + } + if (!added) { + myHolder.addAll(HighlightUtil.checkWithImprovedCatchAnalysis(parameter, thrownTypes, myFile)); + } + } + } } - if (!myHolder.hasErrorResults() && resolved instanceof PsiClass) { - final PsiClass aClass = ((PsiClass) resolved).getContainingClass(); - if (aClass != null) { - final PsiElement qualifier = ref.getQualifier(); - final PsiElement place; - if (qualifier instanceof PsiJavaCodeReferenceElement) { - place = ((PsiJavaCodeReferenceElement) qualifier).resolve(); - } else { - if (parent instanceof PsiNewExpression) { - final PsiExpression newQualifier = ((PsiNewExpression) parent).getQualifier(); - place = newQualifier == null ? ref : PsiUtil.resolveClassInType(newQualifier.getType()); - } else { - place = ref; - } + @Override + public void visitResourceList(PsiResourceList resourceList) { + super.visitResourceList(resourceList); + if (!myHolder.hasErrorResults()) { + myHolder.add(checkFeature(resourceList, JavaFeature.TRY_WITH_RESOURCES)); } - if (place != null && PsiTreeUtil.isAncestor(aClass, place, false) && aClass.hasTypeParameters()) { - myHolder.add(HighlightClassUtil.checkCreateInnerClassFromStaticContext(ref, place, (PsiClass) resolved)); + } + + @Override + public void visitResourceVariable(PsiResourceVariable resource) { + super.visitResourceVariable(resource); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resource)); } - } else if (resolved instanceof PsiTypeParameter) { - final PsiTypeParameterListOwner owner = ((PsiTypeParameter) resolved).getOwner(); - if (owner instanceof PsiClass) { - final PsiClass outerClass = (PsiClass) owner; - if (!InheritanceUtil.hasEnclosingInstanceInScope(outerClass, ref, false, false)) { - myHolder.add(HighlightClassUtil.reportIllegalEnclosingUsage(ref, null, (PsiClass) owner, ref)); - } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resource)); } - } } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkPackageAndClassConflict(ref, myFile)); + @Override + public void visitResourceExpression(PsiResourceExpression resource) { + super.visitResourceExpression(resource); + if (!myHolder.hasErrorResults()) { + myHolder.add(checkFeature(resource, JavaFeature.REFS_AS_RESOURCE)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkResourceVariableIsFinal(resource)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resource)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resource)); + } } - return result; - } - - @Nullable - private JavaResolveResult resolveOptimised(@Nonnull PsiJavaCodeReferenceElement ref) { - try { - if (ref instanceof PsiReferenceExpressionImpl) { - PsiReferenceExpressionImpl.OurGenericsResolver resolver = PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE; - JavaResolveResult[] results = JavaResolveUtil.resolveWithContainingFile(ref, resolver, true, true, myFile); - return results.length == 1 ? results[0] : JavaResolveResult.EMPTY; - } else { - return ref.advancedResolve(true); - } - } catch (IndexNotReadyException e) { - return null; - } - } - - @Nullable - private JavaResolveResult[] resolveOptimised(@Nonnull PsiReferenceExpression expression) { - try { - if (expression instanceof PsiReferenceExpressionImpl) { - PsiReferenceExpressionImpl.OurGenericsResolver resolver = PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE; - return JavaResolveUtil.resolveWithContainingFile(expression, resolver, true, true, myFile); - } else { - return expression.multiResolve(true); - } - } catch (IndexNotReadyException e) { - return null; - } - } - - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - JavaResolveResult resultForIncompleteCode = doVisitReferenceElement(expression); - - if (!myHolder.hasErrorResults()) { - visitExpression(expression); - if (myHolder.hasErrorResults()) { - return; - } - } - - JavaResolveResult[] results = resolveOptimised(expression); - if (results == null) { - return; - } - JavaResolveResult result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY; - - PsiElement resolved = result.getElement(); - if (resolved instanceof PsiVariable && resolved.getContainingFile() == expression.getContainingFile()) { - if (!myHolder.hasErrorResults()) { - try { - myHolder.add(HighlightControlFlowUtil.checkVariableInitializedBeforeUsage(expression, (PsiVariable) resolved, myUninitializedVarProblems, myFile)); - } catch (IndexNotReadyException ignored) { + @Override + public void visitTypeElement(PsiTypeElement type) { + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkIllegalType(type)); } - } - PsiVariable variable = (PsiVariable) resolved; - boolean isFinal = variable.hasModifierProperty(PsiModifier.FINAL); - if (isFinal && !variable.hasInitializer()) { if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightControlFlowUtil.checkFinalVariableMightAlreadyHaveBeenAssignedTo(variable, expression, myFinalVarProblems)); + myHolder.add(GenericsHighlightUtil.checkReferenceTypeUsedAsTypeArgument(type, myLanguageLevel)); } if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightControlFlowUtil.checkFinalVariableInitializedInLoop(expression, resolved)); + myHolder.add(GenericsHighlightUtil.checkWildcardUsage(type)); } - } } - PsiElement parent = expression.getParent(); - if (parent instanceof PsiMethodCallExpression && ((PsiMethodCallExpression) parent).getMethodExpression() == expression && (!result.isAccessible() || !result.isStaticsScopeCorrect())) { - PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) parent; - PsiExpressionList list = methodCallExpression.getArgumentList(); - if (!HighlightMethodUtil.isDummyConstructorCall(methodCallExpression, myResolveHelper, list, expression)) { + @Override + public void visitTypeCastExpression(PsiTypeCastExpression typeCast) { + super.visitTypeCastExpression(typeCast); try { - myHolder.add(HighlightMethodUtil.checkAmbiguousMethodCallIdentifier(expression, results, list, resolved, result, methodCallExpression, myResolveHelper, myLanguageLevel, myFile)); - - if (!PsiTreeUtil.findChildrenOfType(methodCallExpression.getArgumentList(), PsiLambdaExpression.class).isEmpty()) { - PsiElement nameElement = expression.getReferenceNameElement(); - if (nameElement != null) { - myHolder.add(HighlightMethodUtil.checkAmbiguousMethodCallArguments(expression, results, list, resolved, result, methodCallExpression, myResolveHelper, nameElement)); - } - } - } catch (IndexNotReadyException ignored) { + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkIntersectionInTypeCast(typeCast, myLanguageLevel, myFile)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkInconvertibleTypeCast(typeCast)); + } + } + catch (IndexNotReadyException ignored) { } - } - } + } - if (!myHolder.hasErrorResults() && resultForIncompleteCode != null) { - myHolder.add(HighlightUtil.checkExpressionRequired(expression, resultForIncompleteCode)); + @Override + public void visitTypeParameterList(PsiTypeParameterList list) { + PsiTypeParameter[] typeParameters = list.getTypeParameters(); + if (typeParameters.length > 0) { + myHolder.add(checkFeature(list, JavaFeature.GENERICS)); + if (!myHolder.hasErrorResults()) { + myHolder.add(GenericsHighlightUtil.checkTypeParametersList(list, typeParameters, myLanguageLevel)); + } + } } - if (!myHolder.hasErrorResults() && resolved instanceof PsiField) { - try { - myHolder.add(HighlightUtil.checkIllegalForwardReferenceToField(expression, (PsiField) resolved)); - } catch (IndexNotReadyException ignored) { - } - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkAccessStaticFieldFromEnumConstructor(expression, result)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkClassReferenceAfterQualifier(expression, resolved)); + @Override + public void visitVariable(PsiVariable variable) { + super.visitVariable(variable); + try { + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkVariableInitializerType(variable)); + } + } + catch (IndexNotReadyException ignored) { + } } - final PsiExpression qualifierExpression = expression.getQualifierExpression(); - myHolder.add(HighlightUtil.checkUnqualifiedSuperInDefaultMethod(myLanguageLevel, expression, qualifierExpression)); - if (!myHolder.hasErrorResults() && qualifierExpression != null) { - PsiType type = qualifierExpression.getType(); - if (type instanceof PsiCapturedWildcardType) { - type = ((PsiCapturedWildcardType) type).getUpperBound(); - } - final PsiClass psiClass = PsiUtil.resolveClassInType(type); - if (psiClass != null) { - myHolder.add(GenericsHighlightUtil.areSupersAccessible(psiClass, expression)); - } - } - - if (!myHolder.hasErrorResults() && resolved != null && myJavaModule != null) { - myHolder.add(ModuleHighlightUtil.checkPackageAccessibility(expression, resolved, myJavaModule)); - } - } - @Override - public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { - myHolder.add(checkFeature(expression, JavaFeature.METHOD_REFERENCES)); - final PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent()); - if (parent instanceof PsiExpressionStatement) { - return; + private boolean isReassigned(@Nonnull PsiVariable variable) { + try { + boolean reassigned; + if (variable instanceof PsiParameter) { + reassigned = myReassignedParameters.getInt((PsiParameter)variable) == 2; + } + else { + reassigned = HighlightControlFlowUtil.isReassigned(variable, myFinalVarProblems); + } + + return reassigned; + } + catch (IndexNotReadyException e) { + return false; + } } - final JavaResolveResult result; - final JavaResolveResult[] results; - try { - results = expression.multiResolve(true); - result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY; - } catch (IndexNotReadyException e) { - return; + @Override + public void visitConditionalExpression(PsiConditionalExpression expression) { + super.visitConditionalExpression(expression); + if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8) && PsiPolyExpressionUtil.isPolyExpression(expression)) { + final PsiExpression thenExpression = expression.getThenExpression(); + final PsiExpression elseExpression = expression.getElseExpression(); + if (thenExpression != null && elseExpression != null) { + final PsiType conditionalType = expression.getType(); + if (conditionalType != null) { + final PsiExpression[] sides = { + thenExpression, + elseExpression + }; + for (PsiExpression side : sides) { + final PsiType sideType = side.getType(); + if (sideType != null && !TypeConversionUtil.isAssignable(conditionalType, sideType)) { + myHolder.add(HighlightUtil.checkAssignability(conditionalType, sideType, side, side)); + } + } + } + } + } } - if (myRefCountHolder != null) { - myRefCountHolder.registerReference(expression, result); + + @Override + public void visitReceiverParameter(PsiReceiverParameter parameter) { + super.visitReceiverParameter(parameter); + if (!myHolder.hasErrorResults()) { + myHolder.add(checkFeature(parameter, JavaFeature.RECEIVERS)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(AnnotationsHighlightUtil.checkReceiverPlacement(parameter)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(AnnotationsHighlightUtil.checkReceiverType(parameter)); + } } - final PsiElement method = result.getElement(); - if (method != null && !result.isAccessible()) { - final String accessProblem = HighlightUtil.buildProblemWithAccessDescription(expression, result); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(accessProblem).create(); - HighlightUtil.registerAccessQuickFixAction((PsiMember) method, expression, info, result.getCurrentFileResolveScope()); - myHolder.add(info); - } else { - final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); - if (method instanceof PsiMethod && !expression.isConstructor()) { - PsiElement methodNameElement = expression.getReferenceNameElement(); - if (methodNameElement != null) { - myHolder.add(HighlightNamesUtil.highlightMethodName((PsiMethod) method, methodNameElement, false, colorsScheme)); + + @Override + public void visitModule(PsiJavaModule module) { + super.visitModule(module); + if (!myHolder.hasErrorResults()) { + myHolder.add(checkFeature(module, JavaFeature.MODULES)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(ModuleHighlightUtil.checkFileName(module, myFile)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(ModuleHighlightUtil.checkFileDuplicates(module, myFile)); + } + if (!myHolder.hasErrorResults()) { + myHolder.addAll(ModuleHighlightUtil.checkDuplicateStatements(module)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(ModuleHighlightUtil.checkClashingReads(module)); + } + if (!myHolder.hasErrorResults()) { + myHolder.addAll(ModuleHighlightUtil.checkUnusedServices(module)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(ModuleHighlightUtil.checkFileLocation(module, myFile)); } - } - myHolder.add(HighlightNamesUtil.highlightClassNameInQualifier(expression, colorsScheme)); } - if (!LambdaUtil.isValidLambdaContext(parent)) { - String description = "Method reference expression is not expected here"; - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description).create()); + @Override + public void visitRequiresStatement(PsiRequiresStatement statement) { + super.visitRequiresStatement(statement); + if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { + PsiJavaModule container = (PsiJavaModule)statement.getParent(); + PsiJavaModuleReferenceElement ref = statement.getReferenceElement(); + if (!myHolder.hasErrorResults()) { + myHolder.add(ModuleHighlightUtil.checkModuleReference(ref, container)); + } + } } - final PsiType functionalInterfaceType = expression.getFunctionalInterfaceType(); - if (!myHolder.hasErrorResults()) { - if (functionalInterfaceType != null) { - final boolean notFunctional = !LambdaUtil.isFunctionalType(functionalInterfaceType); - if (notFunctional) { - String description = functionalInterfaceType.getPresentableText() + " is not a functional interface"; - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description).create()); + @Override + public void visitPackageAccessibilityStatement(PsiPackageAccessibilityStatement statement) { + super.visitPackageAccessibilityStatement(statement); + if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { + if (!myHolder.hasErrorResults()) { + myHolder.add(ModuleHighlightUtil.checkHostModuleStrength(statement)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(ModuleHighlightUtil.checkPackageReference(statement)); + } + if (!myHolder.hasErrorResults()) { + myHolder.addAll(ModuleHighlightUtil.checkPackageAccessTargets(statement)); + } } - } } - if (!myHolder.hasErrorResults()) { - final PsiElement referenceNameElement = expression.getReferenceNameElement(); - if (referenceNameElement instanceof PsiKeyword) { - if (!PsiMethodReferenceUtil.isValidQualifier(expression)) { - PsiElement qualifier = expression.getQualifier(); - if (qualifier != null) { - String description = "Cannot find class " + qualifier.getText(); - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(qualifier).descriptionAndTooltip(description).create()); - } + + @Override + public void visitUsesStatement(PsiUsesStatement statement) { + super.visitUsesStatement(statement); + if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { + if (!myHolder.hasErrorResults()) { + myHolder.add(ModuleHighlightUtil.checkServiceReference(statement.getClassReference())); + } } - } } - if (!myHolder.hasErrorResults()) { - checkFunctionalInterfaceTypeAccessible(expression, functionalInterfaceType); - } - - if (!myHolder.hasErrorResults() && functionalInterfaceType != null) { - final String errorMessage = PsiMethodReferenceUtil.checkMethodReferenceContext(expression); - if (errorMessage != null) { - final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(errorMessage).create(); - if (method instanceof PsiMethod && !((PsiMethod) method).isConstructor() && !((PsiMethod) method).hasModifierProperty(PsiModifier.ABSTRACT)) { - final boolean shouldHave = !((PsiMethod) method).hasModifierProperty(PsiModifier.STATIC); - final LocalQuickFixAndIntentionActionOnPsiElement fixStaticModifier = QuickFixFactory.getInstance().createModifierListFix((PsiModifierListOwner) method, PsiModifier.STATIC, - shouldHave, false); - QuickFixAction.registerQuickFixAction(info, fixStaticModifier); - } - myHolder.add(info); - } - } - - if (!myHolder.hasErrorResults()) { - PsiElement qualifier = expression.getQualifier(); - if (qualifier instanceof PsiTypeElement) { - final PsiType psiType = ((PsiTypeElement) qualifier).getType(); - final HighlightInfo genericArrayCreationInfo = GenericsHighlightUtil.checkGenericArrayCreation(qualifier, psiType); - if (genericArrayCreationInfo != null) { - myHolder.add(genericArrayCreationInfo); - } else { - final String wildcardMessage = PsiMethodReferenceUtil.checkTypeArguments((PsiTypeElement) qualifier, psiType); - if (wildcardMessage != null) { - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(qualifier).descriptionAndTooltip(wildcardMessage).create()); - } - } - } - } - - if (!myHolder.hasErrorResults()) { - myHolder.add(PsiMethodReferenceHighlightingUtil.checkRawConstructorReference(expression)); - } - - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkUnhandledExceptions(expression, expression.getTextRange())); - } - - if (!myHolder.hasErrorResults()) { - final String badReturnTypeMessage = PsiMethodReferenceUtil.checkReturnType(expression, result, functionalInterfaceType); - if (badReturnTypeMessage != null) { - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(badReturnTypeMessage).create()); - } - } - - if (!myHolder.hasErrorResults()) { - if (results.length == 0 || results[0] instanceof MethodCandidateInfo && !((MethodCandidateInfo) results[0]).isApplicable() && functionalInterfaceType != null) { - String description = null; - if (results.length == 1) { - description = ((MethodCandidateInfo) results[0]).getInferenceErrorMessage(); - } - if (expression.isConstructor()) { - final PsiClass containingClass = PsiMethodReferenceUtil.getQualifierResolveResult(expression).getContainingClass(); - - if (containingClass != null) { - if (!myHolder.add(HighlightClassUtil.checkInstantiationOfAbstractClass(containingClass, expression)) && !myHolder.add(GenericsHighlightUtil.checkEnumInstantiation(expression, - containingClass)) && containingClass.isPhysical() && description == null) { - description = JavaErrorBundle.message("cannot.resolve.constructor", containingClass.getName()); - } - } - } else if (description == null) { - description = JavaErrorBundle.message("cannot.resolve.method", expression.getReferenceName()); + + @Override + public void visitProvidesStatement(PsiProvidesStatement statement) { + super.visitProvidesStatement(statement); + if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { + if (!myHolder.hasErrorResults()) { + myHolder.addAll(ModuleHighlightUtil.checkServiceImplementations(statement)); + } } + } - if (description != null) { - PsiElement referenceNameElement = notNull(expression.getReferenceNameElement(), expression); - HighlightInfoType type = results.length == 0 ? HighlightInfoType.WRONG_REF : HighlightInfoType.ERROR; - HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(type).descriptionAndTooltip(description).range(referenceNameElement).create(); - myHolder.add(highlightInfo); - TextRange fixRange = HighlightMethodUtil.getFixRange(referenceNameElement); - QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QuickFixFactory.getInstance().createCreateMethodFromUsageFix(expression)); - } - } - } - } - - // 15.13 | 15.27 - // It is a compile-time error if any class or interface mentioned by either U or the function type of U - // is not accessible from the class or interface in which the method reference expression appears. - private void checkFunctionalInterfaceTypeAccessible(@Nonnull PsiFunctionalExpression expression, PsiType functionalInterfaceType) { - PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); - final PsiClass psiClass = resolveResult.getElement(); - if (psiClass != null) { - if (!PsiUtil.isAccessible(myFile.getProject(), psiClass, expression, null)) { - String text = HighlightUtil.buildProblemWithAccessDescription(expression, resolveResult); - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(text).create()); - } else { - for (PsiType type : resolveResult.getSubstitutor().getSubstitutionMap().values()) { - checkFunctionalInterfaceTypeAccessible(expression, type); - } - } - } - } - - @Override - public void visitReferenceList(PsiReferenceList list) { - if (list.getFirstChild() == null) { - return; - } - PsiElement parent = list.getParent(); - if (!(parent instanceof PsiTypeParameter)) { - myHolder.add(AnnotationsHighlightUtil.checkAnnotationDeclaration(parent, list)); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkExtendsAllowed(list)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkImplementsAllowed(list)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightClassUtil.checkClassExtendsOnlyOneClass(list)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkGenericCannotExtendException(list)); - } - } - } - - @Override - public void visitReferenceParameterList(PsiReferenceParameterList list) { - if (list.getTextLength() == 0) { - return; - } - - myHolder.add(checkFeature(list, JavaFeature.GENERICS)); - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkParametersAllowed(list)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkParametersOnRaw(list)); - } - if (!myHolder.hasErrorResults()) { - for (PsiTypeElement typeElement : list.getTypeParameterElements()) { - if (typeElement.getType() instanceof PsiDiamondType) { - myHolder.add(checkFeature(list, JavaFeature.DIAMOND_TYPES)); - } - } - } - } - - @Override - public void visitReturnStatement(PsiReturnStatement statement) { - try { - myHolder.add(HighlightUtil.checkReturnStatementType(statement)); - } catch (IndexNotReadyException ignore) { - } - } - - @Override - public void visitStatement(PsiStatement statement) { - super.visitStatement(statement); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkNotAStatement(statement)); - } - } - - @Override - public void visitSuperExpression(PsiSuperExpression expr) { - myHolder.add(HighlightUtil.checkThisOrSuperExpressionInIllegalContext(expr, expr.getQualifier(), myLanguageLevel)); - if (!myHolder.hasErrorResults()) { - visitExpression(expr); - } - } - - @Override - public void visitSwitchLabelStatement(PsiSwitchLabelStatement statement) { - super.visitSwitchLabelStatement(statement); - if (!myHolder.hasErrorResults()) - myHolder.add(HighlightUtil.checkCaseStatement(statement)); - } - - @Override - public void visitSwitchLabeledRuleStatement(PsiSwitchLabeledRuleStatement statement) { - super.visitSwitchLabeledRuleStatement(statement); - if (!myHolder.hasErrorResults()) - myHolder.add(HighlightUtil.checkCaseStatement(statement)); - } - - - @Override - public void visitSwitchStatement(PsiSwitchStatement statement) { - super.visitSwitchStatement(statement); - checkSwitchBlock(statement); - } - - private void checkSwitchBlock(PsiSwitchBlock switchBlock) { - if (!myHolder.hasErrorResults()) - myHolder.add(HighlightUtil.checkSwitchBlockStatements(switchBlock, myLanguageLevel, myFile)); - if (!myHolder.hasErrorResults()) - myHolder.add(HighlightUtil.checkSwitchSelectorType(switchBlock, myLanguageLevel)); - if (!myHolder.hasErrorResults()) - myHolder.addAll(HighlightUtil.checkSwitchLabelValues(switchBlock)); - } - - @Override - public void visitThisExpression(PsiThisExpression expr) { - if (!(expr.getParent() instanceof PsiReceiverParameter)) { - myHolder.add(HighlightUtil.checkThisOrSuperExpressionInIllegalContext(expr, expr.getQualifier(), myLanguageLevel)); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkMemberReferencedBeforeConstructorCalled(expr, null, myFile)); - } - if (!myHolder.hasErrorResults()) { - visitExpression(expr); - } - } - } - - @Override - public void visitThrowStatement(PsiThrowStatement statement) { - myHolder.add(HighlightUtil.checkUnhandledExceptions(statement, null)); - if (!myHolder.hasErrorResults()) { - visitStatement(statement); - } - } - - @Override - public void visitTryStatement(PsiTryStatement statement) { - super.visitTryStatement(statement); - if (!myHolder.hasErrorResults()) { - final Set thrownTypes = HighlightUtil.collectUnhandledExceptions(statement); - for (PsiParameter parameter : statement.getCatchBlockParameters()) { - boolean added = myHolder.addAll(HighlightUtil.checkExceptionAlreadyCaught(parameter)); - if (!added) { - added = myHolder.addAll(HighlightUtil.checkExceptionThrownInTry(parameter, thrownTypes)); - } - if (!added) { - myHolder.addAll(HighlightUtil.checkWithImprovedCatchAnalysis(parameter, thrownTypes, myFile)); - } - } - } - } - - @Override - public void visitResourceList(PsiResourceList resourceList) { - super.visitResourceList(resourceList); - if (!myHolder.hasErrorResults()) { - myHolder.add(checkFeature(resourceList, JavaFeature.TRY_WITH_RESOURCES)); - } - } - - @Override - public void visitResourceVariable(PsiResourceVariable resource) { - super.visitResourceVariable(resource); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resource)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resource)); - } - } - - @Override - public void visitResourceExpression(PsiResourceExpression resource) { - super.visitResourceExpression(resource); - if (!myHolder.hasErrorResults()) { - myHolder.add(checkFeature(resource, JavaFeature.REFS_AS_RESOURCE)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkResourceVariableIsFinal(resource)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resource)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resource)); - } - } - - @Override - public void visitTypeElement(PsiTypeElement type) { - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkIllegalType(type)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkReferenceTypeUsedAsTypeArgument(type, myLanguageLevel)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkWildcardUsage(type)); - } - } - - @Override - public void visitTypeCastExpression(PsiTypeCastExpression typeCast) { - super.visitTypeCastExpression(typeCast); - try { - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkIntersectionInTypeCast(typeCast, myLanguageLevel, myFile)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkInconvertibleTypeCast(typeCast)); - } - } catch (IndexNotReadyException ignored) { - } - } - - @Override - public void visitTypeParameterList(PsiTypeParameterList list) { - PsiTypeParameter[] typeParameters = list.getTypeParameters(); - if (typeParameters.length > 0) { - myHolder.add(checkFeature(list, JavaFeature.GENERICS)); - if (!myHolder.hasErrorResults()) { - myHolder.add(GenericsHighlightUtil.checkTypeParametersList(list, typeParameters, myLanguageLevel)); - } - } - } - - @Override - public void visitVariable(PsiVariable variable) { - super.visitVariable(variable); - try { - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkVariableInitializerType(variable)); - } - } catch (IndexNotReadyException ignored) { - } - } - - private boolean isReassigned(@Nonnull PsiVariable variable) { - try { - boolean reassigned; - if (variable instanceof PsiParameter) { - reassigned = myReassignedParameters.getInt((PsiParameter) variable) == 2; - } else { - reassigned = HighlightControlFlowUtil.isReassigned(variable, myFinalVarProblems); - } - - return reassigned; - } catch (IndexNotReadyException e) { - return false; - } - } - - @Override - public void visitConditionalExpression(PsiConditionalExpression expression) { - super.visitConditionalExpression(expression); - if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8) && PsiPolyExpressionUtil.isPolyExpression(expression)) { - final PsiExpression thenExpression = expression.getThenExpression(); - final PsiExpression elseExpression = expression.getElseExpression(); - if (thenExpression != null && elseExpression != null) { - final PsiType conditionalType = expression.getType(); - if (conditionalType != null) { - final PsiExpression[] sides = { - thenExpression, - elseExpression - }; - for (PsiExpression side : sides) { - final PsiType sideType = side.getType(); - if (sideType != null && !TypeConversionUtil.isAssignable(conditionalType, sideType)) { - myHolder.add(HighlightUtil.checkAssignability(conditionalType, sideType, side, side)); - } - } - } - } - } - } - - @Override - public void visitReceiverParameter(PsiReceiverParameter parameter) { - super.visitReceiverParameter(parameter); - if (!myHolder.hasErrorResults()) { - myHolder.add(checkFeature(parameter, JavaFeature.RECEIVERS)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(AnnotationsHighlightUtil.checkReceiverPlacement(parameter)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(AnnotationsHighlightUtil.checkReceiverType(parameter)); - } - } - - @Override - public void visitModule(PsiJavaModule module) { - super.visitModule(module); - if (!myHolder.hasErrorResults()) { - myHolder.add(checkFeature(module, JavaFeature.MODULES)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(ModuleHighlightUtil.checkFileName(module, myFile)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(ModuleHighlightUtil.checkFileDuplicates(module, myFile)); - } - if (!myHolder.hasErrorResults()) { - myHolder.addAll(ModuleHighlightUtil.checkDuplicateStatements(module)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(ModuleHighlightUtil.checkClashingReads(module)); - } - if (!myHolder.hasErrorResults()) { - myHolder.addAll(ModuleHighlightUtil.checkUnusedServices(module)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(ModuleHighlightUtil.checkFileLocation(module, myFile)); - } - } - - @Override - public void visitRequiresStatement(PsiRequiresStatement statement) { - super.visitRequiresStatement(statement); - if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { - PsiJavaModule container = (PsiJavaModule) statement.getParent(); - PsiJavaModuleReferenceElement ref = statement.getReferenceElement(); - if (!myHolder.hasErrorResults()) { - myHolder.add(ModuleHighlightUtil.checkModuleReference(ref, container)); - } - } - } - - @Override - public void visitPackageAccessibilityStatement(PsiPackageAccessibilityStatement statement) { - super.visitPackageAccessibilityStatement(statement); - if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { - if (!myHolder.hasErrorResults()) { - myHolder.add(ModuleHighlightUtil.checkHostModuleStrength(statement)); - } - if (!myHolder.hasErrorResults()) { - myHolder.add(ModuleHighlightUtil.checkPackageReference(statement)); - } - if (!myHolder.hasErrorResults()) { - myHolder.addAll(ModuleHighlightUtil.checkPackageAccessTargets(statement)); - } - } - } - - @Override - public void visitUsesStatement(PsiUsesStatement statement) { - super.visitUsesStatement(statement); - if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { - if (!myHolder.hasErrorResults()) { - myHolder.add(ModuleHighlightUtil.checkServiceReference(statement.getClassReference())); - } - } - } - - @Override - public void visitProvidesStatement(PsiProvidesStatement statement) { - super.visitProvidesStatement(statement); - if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { - if (!myHolder.hasErrorResults()) { - myHolder.addAll(ModuleHighlightUtil.checkServiceImplementations(statement)); - } - } - } - - @Nullable - private HighlightInfo checkFeature(@Nonnull PsiElement element, @Nonnull JavaFeature feature) { - return HighlightUtil.checkFeature(element, feature, myLanguageLevel, myFile); - } + @Nullable + private HighlightInfo checkFeature(@Nonnull PsiElement element, @Nonnull JavaFeature feature) { + return HighlightUtil.checkFeature(element, feature, myLanguageLevel, myFile); + } } \ No newline at end of file diff --git a/java-language-impl/src/main/java/com/intellij/java/language/impl/refactoring/util/RefactoringChangeUtil.java b/java-language-impl/src/main/java/com/intellij/java/language/impl/refactoring/util/RefactoringChangeUtil.java index 76d278d374..6eb0654282 100644 --- a/java-language-impl/src/main/java/com/intellij/java/language/impl/refactoring/util/RefactoringChangeUtil.java +++ b/java-language-impl/src/main/java/com/intellij/java/language/impl/refactoring/util/RefactoringChangeUtil.java @@ -29,138 +29,151 @@ import jakarta.annotation.Nullable; public class RefactoringChangeUtil { - private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.util.ChangeUtil"); + private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.util.ChangeUtil"); - @Nullable - private static String getMethodExpressionName(@Nullable PsiElement element) { - if (!(element instanceof PsiMethodCallExpression)) { - return null; + @Nullable + private static String getMethodExpressionName(@Nullable PsiElement element) { + if (!(element instanceof PsiMethodCallExpression)) { + return null; + } + PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)element).getMethodExpression(); + return methodExpression.getReferenceName(); } - PsiReferenceExpression methodExpression = ((PsiMethodCallExpression) element).getMethodExpression(); - return methodExpression.getReferenceName(); - } - public static boolean isSuperOrThisMethodCall(@Nullable PsiElement element) { - String name = getMethodExpressionName(element); - return PsiKeyword.SUPER.equals(name) || PsiKeyword.THIS.equals(name); - } + public static boolean isSuperOrThisMethodCall(@Nullable PsiElement element) { + String name = getMethodExpressionName(element); + return PsiKeyword.SUPER.equals(name) || PsiKeyword.THIS.equals(name); + } + + public static boolean isSuperMethodCall(@Nullable PsiElement element) { + String name = getMethodExpressionName(element); + return PsiKeyword.SUPER.equals(name); + } - public static boolean isSuperMethodCall(@Nullable PsiElement element) { - String name = getMethodExpressionName(element); - return PsiKeyword.SUPER.equals(name); - } + public static PsiType getTypeByExpression(PsiExpression expr) { + PsiType type = expr.getType(); + if (type == null) { + if (expr instanceof PsiArrayInitializerExpression) { + PsiExpression[] initializers = ((PsiArrayInitializerExpression)expr).getInitializers(); + if (initializers.length > 0) { + PsiType initType = getTypeByExpression(initializers[0]); + if (initType == null) { + return null; + } + return initType.createArrayType(); + } + } - public static PsiType getTypeByExpression(PsiExpression expr) { - PsiType type = expr.getType(); - if (type == null) { - if (expr instanceof PsiArrayInitializerExpression) { - PsiExpression[] initializers = ((PsiArrayInitializerExpression) expr).getInitializers(); - if (initializers.length > 0) { - PsiType initType = getTypeByExpression(initializers[0]); - if (initType == null) { + if (expr instanceof PsiReferenceExpression && PsiUtil.isOnAssignmentLeftHand(expr)) { + return getTypeByExpression(((PsiAssignmentExpression)expr.getParent()).getRExpression()); + } return null; - } - return initType.createArrayType(); } - } + PsiClass refClass = PsiUtil.resolveClassInType(type); + if (refClass instanceof PsiAnonymousClass) { + type = ((PsiAnonymousClass)refClass).getBaseClassType(); + } - if (expr instanceof PsiReferenceExpression && PsiUtil.isOnAssignmentLeftHand(expr)) { - return getTypeByExpression(((PsiAssignmentExpression) expr.getParent()).getRExpression()); - } - return null; - } - PsiClass refClass = PsiUtil.resolveClassInType(type); - if (refClass instanceof PsiAnonymousClass) { - type = ((PsiAnonymousClass) refClass).getBaseClassType(); + return GenericsUtil.getVariableTypeByExpressionType(type); } - return GenericsUtil.getVariableTypeByExpressionType(type); - } - - public static PsiReferenceExpression qualifyReference(@Nonnull PsiReferenceExpression referenceExpression, - @Nonnull PsiMember member, - @Nullable final PsiClass qualifyingClass) throws IncorrectOperationException { - PsiManager manager = referenceExpression.getManager(); - PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(referenceExpression, - PsiMethodCallExpression.class, true); - while (methodCallExpression != null) { - if (isSuperOrThisMethodCall(methodCallExpression)) { - return referenceExpression; - } - methodCallExpression = PsiTreeUtil.getParentOfType(methodCallExpression, PsiMethodCallExpression.class, - true); - } - PsiReferenceExpression expressionFromText; - final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); - if (qualifyingClass == null) { - PsiClass parentClass = PsiTreeUtil.getParentOfType(referenceExpression, PsiClass.class); - final PsiClass containingClass = member.getContainingClass(); - if (parentClass != null && !InheritanceUtil.isInheritorOrSelf(parentClass, containingClass, true)) { - while (parentClass != null && !InheritanceUtil.isInheritorOrSelf(parentClass, containingClass, true)) { - parentClass = PsiTreeUtil.getParentOfType(parentClass, PsiClass.class, true); + public static PsiReferenceExpression qualifyReference( + @Nonnull PsiReferenceExpression referenceExpression, + @Nonnull PsiMember member, + @Nullable final PsiClass qualifyingClass + ) throws IncorrectOperationException { + PsiManager manager = referenceExpression.getManager(); + PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType( + referenceExpression, + PsiMethodCallExpression.class, + true + ); + while (methodCallExpression != null) { + if (isSuperOrThisMethodCall(methodCallExpression)) { + return referenceExpression; + } + methodCallExpression = PsiTreeUtil.getParentOfType( + methodCallExpression, + PsiMethodCallExpression.class, + true + ); } - LOG.assertTrue(parentClass != null); - expressionFromText = (PsiReferenceExpression) factory.createExpressionFromText("A.this." + member - .getName(), null); - ((PsiThisExpression) expressionFromText.getQualifierExpression()).getQualifier().replace(factory - .createClassReferenceElement(parentClass)); - } else { - expressionFromText = (PsiReferenceExpression) factory.createExpressionFromText("this." + member - .getName(), null); - } - } else { - expressionFromText = (PsiReferenceExpression) factory.createExpressionFromText("A." + member.getName(), - null); - expressionFromText.setQualifierExpression(factory.createReferenceExpression(qualifyingClass)); + PsiReferenceExpression expressionFromText; + final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); + if (qualifyingClass == null) { + PsiClass parentClass = PsiTreeUtil.getParentOfType(referenceExpression, PsiClass.class); + final PsiClass containingClass = member.getContainingClass(); + if (parentClass != null && !InheritanceUtil.isInheritorOrSelf(parentClass, containingClass, true)) { + while (parentClass != null && !InheritanceUtil.isInheritorOrSelf(parentClass, containingClass, true)) { + parentClass = PsiTreeUtil.getParentOfType(parentClass, PsiClass.class, true); + } + LOG.assertTrue(parentClass != null); + expressionFromText = (PsiReferenceExpression)factory + .createExpressionFromText("A.this." + member.getName(), null); + ((PsiThisExpression)expressionFromText.getQualifierExpression()).getQualifier() + .replace(factory.createClassReferenceElement(parentClass)); + } + else { + expressionFromText = (PsiReferenceExpression)factory + .createExpressionFromText("this." + member.getName(), null); + } + } + else { + expressionFromText = (PsiReferenceExpression)factory + .createExpressionFromText("A." + member.getName(), null); + expressionFromText.setQualifierExpression(factory.createReferenceExpression(qualifyingClass)); + } + CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(manager.getProject()); + expressionFromText = (PsiReferenceExpression)codeStyleManager.reformat(expressionFromText); + return (PsiReferenceExpression)referenceExpression.replace(expressionFromText); } - CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(manager.getProject()); - expressionFromText = (PsiReferenceExpression) codeStyleManager.reformat(expressionFromText); - return (PsiReferenceExpression) referenceExpression.replace(expressionFromText); - } - public static PsiClass getThisClass(@Nonnull PsiElement place) { - PsiElement parent = place.getContext(); - if (parent == null) { - return null; - } - PsiElement prev = null; - while (true) { - if (parent instanceof PsiClass) { - if (!(parent instanceof PsiAnonymousClass && ((PsiAnonymousClass) parent).getArgumentList() == prev)) { - return (PsiClass) parent; + public static PsiClass getThisClass(@Nonnull PsiElement place) { + PsiElement parent = place.getContext(); + if (parent == null) { + return null; + } + PsiElement prev = null; + while (true) { + if (parent instanceof PsiClass) { + if (!(parent instanceof PsiAnonymousClass && ((PsiAnonymousClass)parent).getArgumentList() == prev)) { + return (PsiClass)parent; + } + } + prev = parent; + parent = parent.getContext(); + if (parent == null) { + return null; + } } - } - prev = parent; - parent = parent.getContext(); - if (parent == null) { - return null; - } } - } - static T createQualifiedExpression(@Nonnull PsiManager manager, - PsiClass qualifierClass, - @Nonnull String qName) throws IncorrectOperationException { - PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); - if (qualifierClass != null) { - T qualifiedThis = (T) factory.createExpressionFromText("q." + qName, null); - qualifiedThis = (T) CodeStyleManager.getInstance(manager.getProject()).reformat(qualifiedThis); - PsiJavaCodeReferenceElement thisQualifier = qualifiedThis.getQualifier(); - LOG.assertTrue(thisQualifier != null); - thisQualifier.bindToElement(qualifierClass); - return qualifiedThis; - } else { - return (T) factory.createExpressionFromText(qName, null); + static T createQualifiedExpression( + @Nonnull PsiManager manager, + PsiClass qualifierClass, + @Nonnull String qName + ) throws IncorrectOperationException { + PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); + if (qualifierClass != null) { + T qualifiedThis = (T)factory.createExpressionFromText("q." + qName, null); + qualifiedThis = (T)CodeStyleManager.getInstance(manager.getProject()).reformat(qualifiedThis); + PsiJavaCodeReferenceElement thisQualifier = qualifiedThis.getQualifier(); + LOG.assertTrue(thisQualifier != null); + thisQualifier.bindToElement(qualifierClass); + return qualifiedThis; + } + else { + return (T)factory.createExpressionFromText(qName, null); + } } - } - public static PsiThisExpression createThisExpression(PsiManager manager, - PsiClass qualifierClass) throws IncorrectOperationException { - return RefactoringChangeUtil.createQualifiedExpression(manager, qualifierClass, "this"); - } + public static PsiThisExpression createThisExpression(PsiManager manager, PsiClass qualifierClass) + throws IncorrectOperationException { + return RefactoringChangeUtil.createQualifiedExpression(manager, qualifierClass, "this"); + } - public static PsiSuperExpression createSuperExpression(PsiManager manager, - PsiClass qualifierClass) throws IncorrectOperationException { - return RefactoringChangeUtil.createQualifiedExpression(manager, qualifierClass, "super"); - } + public static PsiSuperExpression createSuperExpression(PsiManager manager, PsiClass qualifierClass) + throws IncorrectOperationException { + return RefactoringChangeUtil.createQualifiedExpression(manager, qualifierClass, "super"); + } } From ac024007b56ff84536e33562b6711b9ef1afc6f0 Mon Sep 17 00:00:00 2001 From: UNV Date: Fri, 2 May 2025 03:34:39 +0300 Subject: [PATCH 2/2] Refactoring and localizing users of EP_NAME (part 2). --- .../daemon/impl/UnusedSymbolUtil.java | 65 +- .../impl/analysis/HighlightMethodUtil.java | 733 ++++++++-------- .../daemon/impl/analysis/HighlightUtil.java | 802 +++++++++--------- .../impl/analysis/HighlightVisitorImpl.java | 54 +- .../util/RefactoringChangeUtil.java | 30 +- .../BaseSmartPointerPsiNode.java | 17 +- ...ClassInitializerMayBeStaticInspection.java | 10 +- .../MethodMayBeStaticInspection.java | 68 +- .../psi/NonClasspathResolveScopeEnlarger.java | 4 +- .../ChangeSignatureProcessor.java | 60 +- .../IntroduceParameterProcessor.java | 146 ++-- .../IntroduceParameterUtil.java | 19 +- .../migration/MigrationMapSet.java | 84 +- .../MoveClassToInnerHandler.java | 2 +- .../MoveClassToInnerProcessor.java | 144 ++-- .../MoveClassesOrPackagesImpl.java | 105 +-- .../MoveClassesOrPackagesProcessor.java | 142 ++-- .../MoveClassesOrPackagesUtil.java | 137 +-- 18 files changed, 1343 insertions(+), 1279 deletions(-) diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/UnusedSymbolUtil.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/UnusedSymbolUtil.java index aa71556274..a98ba95f19 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/UnusedSymbolUtil.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/UnusedSymbolUtil.java @@ -26,13 +26,11 @@ import consulo.annotation.access.RequiredReadAction; import consulo.application.progress.ProgressIndicator; import consulo.application.progress.ProgressManager; -import consulo.application.util.function.Processor; import consulo.content.scope.SearchScope; import consulo.find.FindUsagesOptions; import consulo.java.language.impl.psi.augment.JavaEnumAugmentProvider; import consulo.language.editor.ImplicitUsageProvider; import consulo.language.editor.intention.IntentionAction; -import consulo.language.editor.intention.QuickFixAction; import consulo.language.editor.rawHighlight.HighlightInfo; import consulo.language.editor.rawHighlight.HighlightInfoType; import consulo.language.psi.PsiComment; @@ -44,10 +42,11 @@ import consulo.language.psi.search.PsiSearchHelper; import consulo.project.Project; import consulo.usage.UsageInfo; - import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; +import java.util.function.Predicate; + import static consulo.language.psi.search.PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES; public class UnusedSymbolUtil { @@ -71,10 +70,10 @@ public static boolean isImplicitRead(@Nonnull PsiVariable variable) { } public static boolean isImplicitRead(@Nonnull Project project, @Nonnull PsiVariable element, @Nullable ProgressIndicator progress) { - return project.getExtensionPoint(ImplicitUsageProvider.class).findFirstSafe(provider -> { + return project.getExtensionPoint(ImplicitUsageProvider.class).anyMatchSafe(provider -> { ProgressManager.checkCanceled(); return provider.isImplicitRead(element); - }) != null || isInjected(project, element); + }) || isInjected(project, element); } public static boolean isImplicitWrite(@Nonnull PsiVariable variable) { @@ -82,20 +81,23 @@ public static boolean isImplicitWrite(@Nonnull PsiVariable variable) { } public static boolean isImplicitWrite(@Nonnull Project project, @Nonnull PsiVariable element, @Nullable ProgressIndicator progress) { - return project.getExtensionPoint(ImplicitUsageProvider.class).findFirstSafe(provider -> { + return project.getExtensionPoint(ImplicitUsageProvider.class).anyMatchSafe(provider -> { ProgressManager.checkCanceled(); return provider.isImplicitWrite(element); - }) != null || isInjected(project, element); + }) || isInjected(project, element); } @Nullable + @RequiredReadAction public static HighlightInfo createUnusedSymbolInfo( @Nonnull PsiElement element, @Nonnull String message, - @Nonnull final HighlightInfoType highlightInfoType + @Nonnull HighlightInfoType highlightInfoType ) { - HighlightInfo info = HighlightInfo.newHighlightInfo(highlightInfoType).range(element).descriptionAndTooltip - (message).create(); + HighlightInfo info = HighlightInfo.newHighlightInfo(highlightInfoType) + .range(element) + .descriptionAndTooltip(message).create(); + if (info == null) { return null; //filtered out } @@ -103,12 +105,13 @@ public static HighlightInfo createUnusedSymbolInfo( for (UnusedDeclarationFixProvider provider : UnusedDeclarationFixProvider.EP_NAME.getExtensionList()) { IntentionAction[] fixes = provider.getQuickFixes(element); for (IntentionAction fix : fixes) { - QuickFixAction.registerQuickFixAction(info, fix); + info.registerFix(fix, null, null, null, null); } } return info; } + @RequiredReadAction public static boolean isFieldUnused( @Nonnull Project project, @Nonnull PsiFile containingFile, @@ -119,12 +122,14 @@ public static boolean isFieldUnused( if (helper.isLocallyUsed(field)) { return false; } + //noinspection SimplifiableIfStatement if (field instanceof PsiEnumConstant && isEnumValuesMethodUsed(project, containingFile, field, progress, helper)) { return false; } return weAreSureThereAreNoUsages(project, containingFile, field, progress, helper); } + @RequiredReadAction public static boolean isMethodReferenced( @Nonnull Project project, @Nonnull PsiFile containingFile, @@ -136,7 +141,7 @@ public static boolean isMethodReferenced( return true; } - boolean isPrivate = method.hasModifierProperty(PsiModifier.PRIVATE); + boolean isPrivate = method.isPrivate(); PsiClass containingClass = method.getContainingClass(); if (JavaHighlightUtil.isSerializationRelatedMethod(method, containingClass)) { return true; @@ -170,10 +175,11 @@ public static boolean isMethodReferenced( return false; } + @RequiredReadAction private static boolean weAreSureThereAreNoUsages( @Nonnull Project project, @Nonnull PsiFile containingFile, - @Nonnull final PsiMember member, + @Nonnull PsiMember member, @Nonnull ProgressIndicator progress, @Nonnull GlobalUsageHelper helper ) { @@ -183,11 +189,15 @@ private static boolean weAreSureThereAreNoUsages( return false; } - final PsiFile ignoreFile = helper.isCurrentFileAlreadyChecked() ? containingFile : null; + PsiFile ignoreFile = helper.isCurrentFileAlreadyChecked() ? containingFile : null; - boolean sure = processUsages(project, containingFile, member, progress, ignoreFile, new Processor() { - @Override - public boolean process(UsageInfo info) { + boolean sure = processUsages( + project, + containingFile, + member, + progress, + ignoreFile, + info -> { PsiFile psiFile = info.getFile(); if (psiFile == ignoreFile || psiFile == null) { return true; // ignore usages in containingFile because isLocallyUsed() method would have caught @@ -202,7 +212,7 @@ public boolean process(UsageInfo info) { log("* " + member.getName() + ": usage :" + element); return inComment; // ignore comments } - }); + ); log("* " + member.getName() + ": result:" + sure); return sure; } @@ -219,7 +229,7 @@ public static boolean processUsages( @Nonnull PsiMember member, @Nonnull ProgressIndicator progress, @Nullable PsiFile ignoreFile, - @Nonnull Processor usageInfoProcessor + @Nonnull @RequiredReadAction Predicate usageInfoProcessor ) { String name = member.getName(); if (name == null) { @@ -227,7 +237,7 @@ public static boolean processUsages( return false; } SearchScope useScope = member.getUseScope(); - PsiSearchHelper searchHelper = PsiSearchHelper.SERVICE.getInstance(project); + PsiSearchHelper searchHelper = project.getInstance(PsiSearchHelper.class); if (useScope instanceof GlobalSearchScope globalSearchScope) { // some classes may have references from within XML outside dependent modules, e.g. our actions if (member instanceof PsiClass) { @@ -294,6 +304,7 @@ else if (member instanceof PsiVariable) { return JavaFindUsagesHelper.processElementUsages(member, options, usageInfoProcessor); } + @RequiredReadAction private static boolean isEnumValuesMethodUsed( @Nonnull Project project, @Nonnull PsiFile containingFile, @@ -301,7 +312,7 @@ private static boolean isEnumValuesMethodUsed( @Nonnull ProgressIndicator progress, @Nonnull GlobalUsageHelper helper ) { - final PsiClass containingClass = member.getContainingClass(); + PsiClass containingClass = member.getContainingClass(); if (!(containingClass instanceof PsiClassImpl)) { return true; } @@ -314,8 +325,7 @@ private static boolean isEnumValuesMethodUsed( PsiMethod valuesMethod = null; for (PsiMethod psiMethod : methodsByName) { - if (psiMethod.getParameterList().getParametersCount() == 0 && psiMethod.hasModifierProperty - (PsiModifier.STATIC)) { + if (psiMethod.getParameterList().getParametersCount() == 0 && psiMethod.isStatic()) { valuesMethod = psiMethod; break; } @@ -337,12 +347,14 @@ private static boolean canBeReferencedViaWeirdNames(@Nonnull PsiMember member, @ if (member instanceof PsiField) { return false; //Java field cannot be referenced by anything but its name } + //noinspection SimplifiableIfStatement if (member instanceof PsiMethod method) { return PropertyUtil.isSimplePropertyAccessor(method); //Java accessors can be referenced by field name from Groovy } return false; } + @RequiredReadAction public static boolean isClassUsed( @Nonnull Project project, @Nonnull PsiFile containingFile, @@ -358,6 +370,7 @@ public static boolean isClassUsed( return result; } + @RequiredReadAction private static boolean isReallyUsed( @Nonnull Project project, @Nonnull PsiFile containingFile, @@ -369,9 +382,9 @@ private static boolean isReallyUsed( return true; } if (helper.isCurrentFileAlreadyChecked()) { - if (aClass.getContainingClass() != null && aClass.hasModifierProperty(PsiModifier.PRIVATE) || - aClass.getParent() instanceof PsiDeclarationStatement || - aClass instanceof PsiTypeParameter) { + if (aClass.getContainingClass() != null && aClass.isPrivate() + || aClass.getParent() instanceof PsiDeclarationStatement + || aClass instanceof PsiTypeParameter) { return false; } } diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 639e9054cf..f2f1802cfd 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -31,22 +31,25 @@ import com.intellij.java.language.psi.infos.MethodCandidateInfo; import com.intellij.java.language.psi.util.*; import com.intellij.java.language.util.VisibilityUtil; +import consulo.annotation.access.RequiredReadAction; import consulo.application.dumb.IndexNotReadyException; import consulo.document.util.TextRange; import consulo.document.util.TextRangeUtil; +import consulo.java.language.impl.localize.JavaErrorLocalize; import consulo.java.language.module.util.JavaClassNames; -import consulo.language.editor.DaemonBundle; import consulo.language.editor.inspection.LocalQuickFixOnPsiElementAsIntentionAdapter; import consulo.language.editor.intention.IntentionAction; import consulo.language.editor.intention.QuickFixAction; import consulo.language.editor.intention.QuickFixActionRegistrar; import consulo.language.editor.intention.UnresolvedReferenceQuickFixProvider; +import consulo.language.editor.localize.DaemonLocalize; import consulo.language.editor.rawHighlight.HighlightInfo; import consulo.language.editor.rawHighlight.HighlightInfoHolder; import consulo.language.editor.rawHighlight.HighlightInfoType; import consulo.language.psi.*; import consulo.language.psi.util.PsiMatcherImpl; import consulo.language.psi.util.PsiTreeUtil; +import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.ui.ex.JBColor; import consulo.ui.ex.awt.UIUtil; @@ -55,13 +58,12 @@ import consulo.util.lang.Comparing; import consulo.util.lang.ObjectUtil; import consulo.util.lang.StringUtil; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import consulo.util.lang.xml.XmlStringUtil; import consulo.virtualFileSystem.VirtualFile; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import org.intellij.lang.annotations.Language; -import org.jetbrains.annotations.NonNls; import java.text.MessageFormat; import java.util.*; @@ -70,7 +72,7 @@ * Highlight method problems * * @author cdr - * Date: Aug 14, 2002 + * @since 2002-08-14 */ public class HighlightMethodUtil { private static final Logger LOG = Logger.getInstance(HighlightMethodUtil.class); @@ -79,16 +81,19 @@ private HighlightMethodUtil() { } public static String createClashMethodMessage(PsiMethod method1, PsiMethod method2, boolean showContainingClasses) { - @NonNls String pattern = showContainingClasses ? "clash.methods.message.show.classes" : "clash.methods.message"; - return JavaErrorBundle.message( - pattern, - JavaHighlightUtil.formatMethod(method1), - JavaHighlightUtil.formatMethod(method2), - HighlightUtil.formatClass(method1.getContainingClass()), - HighlightUtil.formatClass(method2.getContainingClass()) - ); + String m1 = JavaHighlightUtil.formatMethod(method1); + String m2 = JavaHighlightUtil.formatMethod(method2); + return showContainingClasses + ? JavaErrorLocalize.clashMethodsMessageShowClasses( + m1, + m2, + HighlightUtil.formatClass(method1.getContainingClass()), + HighlightUtil.formatClass(method2.getContainingClass()) + ).get() + : JavaErrorLocalize.clashMethodsMessage(m1, m2).get(); } + @RequiredReadAction public static HighlightInfo checkMethodWeakerPrivileges( @Nonnull MethodSignatureBackedByPsiMethod methodSignature, @Nonnull List superMethodSignatures, @@ -104,7 +109,7 @@ public static HighlightInfo checkMethodWeakerPrivileges( String accessModifier = PsiUtil.getAccessModifier(accessLevel); for (MethodSignatureBackedByPsiMethod superMethodSignature : superMethodSignatures) { PsiMethod superMethod = superMethodSignature.getMethod(); - if (method.hasModifierProperty(PsiModifier.ABSTRACT) && !MethodSignatureUtil.isSuperMethod(superMethod, method)) { + if (method.isAbstract() && !MethodSignatureUtil.isSuperMethod(superMethod, method)) { continue; } if (!PsiUtil.isAccessible(containingFile.getProject(), superMethod, method, null)) { @@ -121,22 +126,17 @@ public static HighlightInfo checkMethodWeakerPrivileges( return null; } + @RequiredReadAction private static HighlightInfo isWeaker( - final PsiMethod method, - final PsiModifierList modifierList, - final String accessModifier, - final int accessLevel, - final PsiMethod superMethod, - final boolean includeRealPositionInfo + PsiMethod method, + PsiModifierList modifierList, + String accessModifier, + int accessLevel, + PsiMethod superMethod, + boolean includeRealPositionInfo ) { int superAccessLevel = PsiUtil.getAccessLevel(superMethod.getModifierList()); if (accessLevel < superAccessLevel) { - String description = JavaErrorBundle.message( - "weaker.privileges", - createClashMethodMessage(method, superMethod, true), - VisibilityUtil.toPresentableText(accessModifier), - PsiUtil.getAccessModifier(superAccessLevel) - ); TextRange textRange; if (includeRealPositionInfo) { PsiElement keyword = PsiUtil.findModifierInList(modifierList, accessModifier); @@ -151,8 +151,14 @@ private static HighlightInfo isWeaker( else { textRange = TextRange.EMPTY_RANGE; } - HighlightInfo highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(textRange) + .descriptionAndTooltip(JavaErrorLocalize.weakerPrivileges( + createClashMethodMessage(method, superMethod, true), + VisibilityUtil.toPresentableText(accessModifier), + PsiUtil.getAccessModifier(superAccessLevel) + )) + .create(); QuickFixAction.registerQuickFixAction( highlightInfo, QuickFixFactory.getInstance().createModifierListFix( @@ -167,7 +173,7 @@ private static HighlightInfo isWeaker( return null; } - + @RequiredReadAction public static HighlightInfo checkMethodIncompatibleReturnType( @Nonnull MethodSignatureBackedByPsiMethod methodSignature, @Nonnull List superMethodSignatures, @@ -176,6 +182,7 @@ public static HighlightInfo checkMethodIncompatibleReturnType( return checkMethodIncompatibleReturnType(methodSignature, superMethodSignatures, includeRealPositionInfo, null); } + @RequiredReadAction public static HighlightInfo checkMethodIncompatibleReturnType( @Nonnull MethodSignatureBackedByPsiMethod methodSignature, @Nonnull List superMethodSignatures, @@ -211,7 +218,7 @@ public static HighlightInfo checkMethodIncompatibleReturnType( method, methodSignature, returnType, - JavaErrorBundle.message("incompatible.return.type"), + JavaErrorLocalize.incompatibleReturnType(), toHighlight, PsiUtil.getLanguageLevel(aClass) ); @@ -230,25 +237,25 @@ private static HighlightInfo checkSuperMethodSignature( @Nonnull PsiMethod method, @Nonnull MethodSignatureBackedByPsiMethod methodSignature, @Nonnull PsiType returnType, - @Nonnull String detailMessage, + @Nonnull LocalizeValue detailMessage, @Nonnull TextRange range, @Nonnull LanguageLevel languageLevel ) { if (superReturnType == null) { return null; } - final PsiClass superContainingClass = superMethod.getContainingClass(); + PsiClass superContainingClass = superMethod.getContainingClass(); if (superContainingClass != null && JavaClassNames.JAVA_LANG_OBJECT.equals(superContainingClass.getQualifiedName()) - && !superMethod.hasModifierProperty(PsiModifier.PUBLIC)) { - final PsiClass containingClass = method.getContainingClass(); + && !superMethod.isPublic()) { + PsiClass containingClass = method.getContainingClass(); if (containingClass != null && containingClass.isInterface() && !superContainingClass.isInterface()) { return null; } } PsiType substitutedSuperReturnType; - final boolean isJdk15 = languageLevel.isAtLeast(LanguageLevel.JDK_1_5); + boolean isJdk15 = languageLevel.isAtLeast(LanguageLevel.JDK_1_5); if (isJdk15 && !superMethodSignature.isRaw() && superMethodSignature.equals(methodSignature)) { //see 8.4.5 PsiSubstitutor unifyingSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, superMethodSignature); @@ -261,10 +268,9 @@ private static HighlightInfo checkSuperMethodSignature( if (returnType.equals(substitutedSuperReturnType)) { return null; } - if (!(returnType instanceof PsiPrimitiveType) && substitutedSuperReturnType.getDeepComponentType() instanceof PsiClassType) { - if (isJdk15 && TypeConversionUtil.isAssignable(substitutedSuperReturnType, returnType)) { - return null; - } + if (!(returnType instanceof PsiPrimitiveType) && substitutedSuperReturnType.getDeepComponentType() instanceof PsiClassType + && isJdk15 && TypeConversionUtil.isAssignable(substitutedSuperReturnType, returnType)) { + return null; } return createIncompatibleReturnTypeMessage(method, superMethod, substitutedSuperReturnType, returnType, detailMessage, range); @@ -275,30 +281,33 @@ private static HighlightInfo createIncompatibleReturnTypeMessage( @Nonnull PsiMethod superMethod, @Nonnull PsiType substitutedSuperReturnType, @Nonnull PsiType returnType, - @Nonnull String detailMessage, + @Nonnull LocalizeValue detailMessage, @Nonnull TextRange textRange ) { String description = MessageFormat.format("{0}; {1}", createClashMethodMessage(method, superMethod, true), detailMessage); - HighlightInfo errorResult = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance() - .createMethodReturnFix(method, substitutedSuperReturnType, false)); - QuickFixAction.registerQuickFixAction( - errorResult, - QuickFixFactory.getInstance().createSuperMethodReturnFix(superMethod, returnType) - ); - final PsiClass returnClass = PsiUtil.resolveClassInClassTypeOnly(returnType); - if (returnClass != null && substitutedSuperReturnType instanceof PsiClassType) { - QuickFixAction.registerQuickFixAction( - errorResult, - QuickFixFactory.getInstance().createChangeParameterClassFix( - returnClass, - (PsiClassType)substitutedSuperReturnType - ) + HighlightInfo.Builder builder = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(textRange) + .descriptionAndTooltip(description) + .registerFix( + QuickFixFactory.getInstance().createMethodReturnFix(method, substitutedSuperReturnType, false), + null, + null, + null, + null + ) + .registerFix(QuickFixFactory.getInstance().createSuperMethodReturnFix(superMethod, returnType), null, null, null, null); + PsiClass returnClass = PsiUtil.resolveClassInClassTypeOnly(returnType); + if (returnClass != null && substitutedSuperReturnType instanceof PsiClassType classType) { + builder.registerFix( + QuickFixFactory.getInstance().createChangeParameterClassFix(returnClass, classType), + null, + null, + null, + null ); } - return errorResult; + return builder.create(); } public static HighlightInfo checkMethodOverridesFinal( @@ -318,30 +327,26 @@ public static HighlightInfo checkMethodOverridesFinal( private static HighlightInfo checkSuperMethodIsFinal(PsiMethod method, PsiMethod superMethod) { // strange things happen when super method is from Object and method from interface - if (superMethod.hasModifierProperty(PsiModifier.FINAL)) { - String description = JavaErrorBundle.message( - "final.method.override", - JavaHighlightUtil.formatMethod(method), - JavaHighlightUtil.formatMethod(superMethod), - HighlightUtil.formatClass(superMethod.getContainingClass()) - ); - TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); - HighlightInfo errorResult = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction( - errorResult, - QuickFixFactory.getInstance().createModifierListFix( + if (superMethod.isFinal()) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(HighlightNamesUtil.getMethodDeclarationTextRange(method)) + .descriptionAndTooltip(JavaErrorLocalize.finalMethodOverride( + JavaHighlightUtil.formatMethod(method), + JavaHighlightUtil.formatMethod(superMethod), + HighlightUtil.formatClass(superMethod.getContainingClass()) + )) + .registerFix(QuickFixFactory.getInstance().createModifierListFix( superMethod, PsiModifier.FINAL, false, true - ) - ); - return errorResult; + ), null, null, null, null) + .create(); } return null; } + @RequiredReadAction public static HighlightInfo checkMethodIncompatibleThrows( MethodSignatureBackedByPsiMethod methodSignature, List superMethodSignatures, @@ -384,7 +389,7 @@ public static HighlightInfo checkMethodIncompatibleThrows( int index = getExtraExceptionNum(methodSignature, superMethodSignature, checkedExceptions, superSubstitutor); if (index != -1) { if (aClass.isInterface()) { - final PsiClass superContainingClass = superMethod.getContainingClass(); + PsiClass superContainingClass = superMethod.getContainingClass(); if (superContainingClass != null && !superContainingClass.isInterface()) { continue; } @@ -393,11 +398,10 @@ public static HighlightInfo checkMethodIncompatibleThrows( } } PsiClassType exception = checkedExceptions.get(index); - String description = JavaErrorBundle.message( - "overridden.method.does.not.throw", + String description = JavaErrorLocalize.overriddenMethodDoesNotThrow( createClashMethodMessage(method, superMethod, true), JavaHighlightUtil.formatType(exception) - ); + ).get(); TextRange textRange; if (includeRealPositionInfo) { PsiElement exceptionContext = exceptionContexts.get(index); @@ -406,31 +410,26 @@ public static HighlightInfo checkMethodIncompatibleThrows( else { textRange = TextRange.EMPTY_RANGE; } - HighlightInfo errorResult = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction( - errorResult, - new LocalQuickFixOnPsiElementAsIntentionAdapter( + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(textRange) + .descriptionAndTooltip(description) + .registerFix(new LocalQuickFixOnPsiElementAsIntentionAdapter( QuickFixFactory.getInstance().createMethodThrowsFix( method, exception, false, false ) - ) - ); - QuickFixAction.registerQuickFixAction( - errorResult, - new LocalQuickFixOnPsiElementAsIntentionAdapter( + ), null, null, null, null) + .registerFix(new LocalQuickFixOnPsiElementAsIntentionAdapter( QuickFixFactory.getInstance().createMethodThrowsFix( superMethod, exception, true, true ) - ) - ); - return errorResult; + ), null, null, null, null) + .create(); } } return null; @@ -438,16 +437,16 @@ public static HighlightInfo checkMethodIncompatibleThrows( // return number of exception which was not declared in super method or -1 private static int getExtraExceptionNum( - final MethodSignature methodSignature, - final MethodSignatureBackedByPsiMethod superSignature, + MethodSignature methodSignature, + MethodSignatureBackedByPsiMethod superSignature, List checkedExceptions, PsiSubstitutor substitutorForDerivedClass ) { PsiMethod superMethod = superSignature.getMethod(); PsiSubstitutor substitutorForMethod = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, superSignature); for (int i = 0; i < checkedExceptions.size(); i++) { - final PsiClassType checkedEx = checkedExceptions.get(i); - final PsiType substituted = + PsiClassType checkedEx = checkedExceptions.get(i); + PsiType substituted = substitutorForMethod != null ? substitutorForMethod.substitute(checkedEx) : TypeConversionUtil.erasure(checkedEx); PsiType exception = substitutorForDerivedClass.substitute(substituted); if (!isMethodThrows(superMethod, substitutorForMethod, exception, substitutorForDerivedClass)) { @@ -477,6 +476,7 @@ private static boolean isMethodThrows( } @Nullable + @RequiredReadAction public static HighlightInfo checkMethodCall( @Nonnull PsiMethodCallExpression methodCall, @Nonnull PsiResolveHelper resolveHelper, @@ -496,19 +496,19 @@ public static HighlightInfo checkMethodCall( } HighlightInfo highlightInfo; - final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); - if (resolved instanceof PsiMethod && resolveResult.isValidResult()) { + PsiSubstitutor substitutor = resolveResult.getSubstitutor(); + if (resolved instanceof PsiMethod method && resolveResult.isValidResult()) { TextRange fixRange = getFixRange(methodCall); highlightInfo = HighlightUtil.checkUnhandledExceptions(methodCall, fixRange); - if (highlightInfo == null && ((PsiMethod)resolved).hasModifierProperty(PsiModifier.STATIC)) { - PsiClass containingClass = ((PsiMethod)resolved).getContainingClass(); + if (highlightInfo == null && method.isStatic()) { + PsiClass containingClass = method.getContainingClass(); if (containingClass != null && containingClass.isInterface()) { PsiReferenceExpression methodRef = methodCall.getMethodExpression(); PsiElement element = ObjectUtil.notNull(methodRef.getReferenceNameElement(), methodRef); highlightInfo = HighlightUtil.checkFeature(element, JavaFeature.STATIC_INTERFACE_CALLS, languageLevel, file); if (highlightInfo == null) { - String message = + LocalizeValue message = checkStaticInterfaceMethodCallQualifier(methodRef, resolveResult.getCurrentFileResolveScope(), containingClass); if (message != null) { highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) @@ -551,8 +551,8 @@ public static HighlightInfo checkMethodCall( else { PsiMethod resolvedMethod = null; MethodCandidateInfo candidateInfo = null; - if (resolveResult instanceof MethodCandidateInfo) { - candidateInfo = (MethodCandidateInfo)resolveResult; + if (resolveResult instanceof MethodCandidateInfo mci) { + candidateInfo = mci; resolvedMethod = candidateInfo.getElement(); } @@ -565,8 +565,8 @@ else if (candidateInfo != null && !candidateInfo.isApplicable()) { PsiElement parent = resolved.getParent(); String containerName = parent == null ? "" : HighlightMessageUtil.getSymbolName(parent, substitutor); String argTypes = buildArgTypesList(list); - String description = JavaErrorBundle.message("wrong.method.arguments", methodName, containerName, argTypes); - final Ref elementToHighlight = new Ref<>(list); + String description = JavaErrorLocalize.wrongMethodArguments(methodName, containerName, argTypes).get(); + SimpleReference elementToHighlight = SimpleReference.create(list); String toolTip; if (parent instanceof PsiClass) { toolTip = buildOneLineMismatchDescription(list, candidateInfo, elementToHighlight); @@ -611,35 +611,46 @@ else if (candidateInfo != null && !candidateInfo.isApplicable()) { } } else { - String description = JavaErrorBundle.message("method.call.expected"); highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(methodCall) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.methodCallExpected()) .create(); - if (resolved instanceof PsiClass) { + if (resolved instanceof PsiClass psiClass) { QuickFixAction.registerQuickFixAction( highlightInfo, - QuickFixFactory.getInstance().createInsertNewFix(methodCall, (PsiClass)resolved) + QuickFixFactory.getInstance().createInsertNewFix(methodCall, psiClass) ); } else { TextRange range = getFixRange(methodCall); - QuickFixAction.registerQuickFixAction(highlightInfo, range, QuickFixFactory.getInstance() - .createCreateMethodFromUsageFix(methodCall)); - QuickFixAction.registerQuickFixAction(highlightInfo, range, QuickFixFactory.getInstance() - .createCreateAbstractMethodFromUsageFix(methodCall)); - QuickFixAction.registerQuickFixAction(highlightInfo, range, QuickFixFactory.getInstance() - .createCreatePropertyFromUsageFix(methodCall)); + QuickFixAction.registerQuickFixAction( + highlightInfo, + range, + QuickFixFactory.getInstance().createCreateMethodFromUsageFix(methodCall) + ); + QuickFixAction.registerQuickFixAction( + highlightInfo, + range, + QuickFixFactory.getInstance().createCreateAbstractMethodFromUsageFix(methodCall) + ); + QuickFixAction.registerQuickFixAction( + highlightInfo, + range, + QuickFixFactory.getInstance().createCreatePropertyFromUsageFix(methodCall) + ); QuickFixAction.registerQuickFixAction( highlightInfo, range, QuickFixFactory.getInstance().createStaticImportMethodFix(methodCall) ); - if (resolved instanceof PsiVariable && languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { - PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(((PsiVariable)resolved).getType()); + if (resolved instanceof PsiVariable variable && languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { + PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(variable.getType()); if (method != null) { - QuickFixAction.registerQuickFixAction(highlightInfo, range, QuickFixFactory.getInstance() - .createInsertMethodCallFix(methodCall, method)); + QuickFixAction.registerQuickFixAction( + highlightInfo, + range, + QuickFixFactory.getInstance().createInsertMethodCallFix(methodCall, method) + ); } } } @@ -652,6 +663,7 @@ else if (candidateInfo != null && !candidateInfo.isApplicable()) { return highlightInfo; } + @RequiredReadAction private static void registerTargetTypeFixesBasedOnApplicabilityInference( @Nonnull PsiMethodCallExpression methodCall, MethodCandidateInfo resolveResult, @@ -660,17 +672,13 @@ private static void registerTargetTypeFixesBasedOnApplicabilityInference( ) { PsiElement parent = PsiUtil.skipParenthesizedExprUp(methodCall.getParent()); PsiVariable variable = null; - if (parent instanceof PsiVariable) { - variable = (PsiVariable)parent; - } - else if (parent instanceof PsiAssignmentExpression) { - PsiExpression lExpression = ((PsiAssignmentExpression)parent).getLExpression(); - if (lExpression instanceof PsiReferenceExpression) { - PsiElement resolve = ((PsiReferenceExpression)lExpression).resolve(); - if (resolve instanceof PsiVariable) { - variable = (PsiVariable)resolve; - } - } + if (parent instanceof PsiVariable var) { + variable = var; + } + else if (parent instanceof PsiAssignmentExpression assignment + && assignment.getLExpression() instanceof PsiReferenceExpression lRefExpr + && lRefExpr.resolve() instanceof PsiVariable lVar) { + variable = lVar; } if (variable != null) { @@ -691,22 +699,27 @@ else if (parent instanceof PsiAssignmentExpression) { /* see also PsiReferenceExpressionImpl.hasValidQualifier() */ @Nullable - private static String checkStaticInterfaceMethodCallQualifier(PsiReferenceExpression ref, PsiElement scope, PsiClass containingClass) { + @RequiredReadAction + private static LocalizeValue checkStaticInterfaceMethodCallQualifier( + PsiReferenceExpression ref, + PsiElement scope, + PsiClass containingClass + ) { PsiExpression qualifierExpression = ref.getQualifierExpression(); if (qualifierExpression == null && (scope instanceof PsiImportStaticStatement || PsiTreeUtil.isAncestor(containingClass, ref, true))) { return null; } - if (qualifierExpression instanceof PsiReferenceExpression) { - PsiElement resolve = ((PsiReferenceExpression)qualifierExpression).resolve(); + if (qualifierExpression instanceof PsiReferenceExpression qRefExpr) { + PsiElement resolve = qRefExpr.resolve(); if (resolve == containingClass) { return null; } - if (resolve instanceof PsiTypeParameter) { + if (resolve instanceof PsiTypeParameter typeParam) { Set classes = new HashSet<>(); - for (PsiClassType type : ((PsiTypeParameter)resolve).getExtendsListTypes()) { + for (PsiClassType type : typeParam.getExtendsListTypes()) { PsiClass aClass = type.resolve(); if (aClass != null) { classes.add(aClass); @@ -719,15 +732,16 @@ private static String checkStaticInterfaceMethodCallQualifier(PsiReferenceExpres } } - return JavaErrorBundle.message("static.interface.method.call.qualifier"); + return JavaErrorLocalize.staticInterfaceMethodCallQualifier(); } + @RequiredReadAction private static void registerMethodReturnFixAction(HighlightInfo highlightInfo, MethodCandidateInfo candidate, PsiCall methodCall) { if (methodCall.getParent() instanceof PsiReturnStatement) { - final PsiMethod containerMethod = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class, true, PsiLambdaExpression.class); + PsiMethod containerMethod = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class, true, PsiLambdaExpression.class); if (containerMethod != null) { - final PsiMethod method = candidate.getElement(); - final PsiExpression methodCallCopy = + PsiMethod method = candidate.getElement(); + PsiExpression methodCallCopy = JavaPsiFacade.getElementFactory(method.getProject()).createExpressionFromText(methodCall.getText(), methodCall); PsiType methodCallTypeByArgs = methodCallCopy.getType(); //ensure type params are not included @@ -749,27 +763,26 @@ private static void registerMethodReturnFixAction(HighlightInfo highlightInfo, M } } + @RequiredReadAction private static String buildOneLineMismatchDescription( @Nonnull PsiExpressionList list, @Nonnull MethodCandidateInfo candidateInfo, - @Nonnull Ref elementToHighlight + @Nonnull SimpleReference elementToHighlight ) { - final PsiExpression[] expressions = list.getExpressions(); - final PsiMethod resolvedMethod = candidateInfo.getElement(); - final PsiSubstitutor substitutor = candidateInfo.getSubstitutor(); - final PsiParameter[] parameters = resolvedMethod.getParameterList().getParameters(); + PsiExpression[] expressions = list.getExpressions(); + PsiMethod resolvedMethod = candidateInfo.getElement(); + PsiSubstitutor substitutor = candidateInfo.getSubstitutor(); + PsiParameter[] parameters = resolvedMethod.getParameterList().getParameters(); if (expressions.length == parameters.length && parameters.length > 1) { int idx = -1; for (int i = 0; i < expressions.length; i++) { PsiExpression expression = expressions[i]; - if (expression instanceof PsiMethodCallExpression) { - final JavaResolveResult result = ((PsiCallExpression)expression).resolveMethodGenerics(); - if (result instanceof MethodCandidateInfo - && PsiUtil.isLanguageLevel8OrHigher(list) - && ((MethodCandidateInfo)result).isToInferApplicability() - && ((MethodCandidateInfo)result).getInferenceErrorMessage() == null) { - continue; - } + if (expression instanceof PsiMethodCallExpression methodCall + && methodCall.resolveMethodGenerics() instanceof MethodCandidateInfo methodCandidateInfo + && PsiUtil.isLanguageLevel8OrHigher(list) + && methodCandidateInfo.isToInferApplicability() + && methodCandidateInfo.getInferenceErrorMessage() == null) { + continue; } if (!TypeConversionUtil.areTypesAssignmentCompatible(substitutor.substitute(parameters[i].getType()), expression)) { if (idx != -1) { @@ -783,23 +796,22 @@ private static String buildOneLineMismatchDescription( } if (idx > -1) { - final PsiExpression wrongArg = expressions[idx]; - final PsiType argType = wrongArg.getType(); + PsiExpression wrongArg = expressions[idx]; + PsiType argType = wrongArg.getType(); if (argType != null) { elementToHighlight.set(wrongArg); - final String message = JavaErrorBundle.message( - "incompatible.call.types", + LocalizeValue message = JavaErrorLocalize.incompatibleCallTypes( idx + 1, substitutor.substitute(parameters[idx].getType()).getCanonicalText(), argType.getCanonicalText() ); - return XmlStringUtil.wrapInHtml("" + XmlStringUtil.escapeString(message) + " " + XmlStringUtil.escapeString(message.get()) + " " + DaemonBundle.message( - "inspection.extended.description") + ""); + )) + "\"" + (UIUtil.isUnderDarcula() ? " color=\"7AB4C9\" " : "") + ">" + + DaemonLocalize.inspectionExtendedDescription() + ""); } } } @@ -827,11 +839,12 @@ public static boolean isDummyConstructorCall( } @Nullable + @RequiredReadAction public static HighlightInfo checkAmbiguousMethodCallIdentifier( @Nonnull PsiReferenceExpression referenceToMethod, @Nonnull JavaResolveResult[] resolveResults, @Nonnull PsiExpressionList list, - final PsiElement element, + PsiElement element, @Nonnull JavaResolveResult resolveResult, @Nonnull PsiMethodCallExpression methodCall, @Nonnull PsiResolveHelper resolveHelper, @@ -841,10 +854,9 @@ public static HighlightInfo checkAmbiguousMethodCallIdentifier( MethodCandidateInfo methodCandidate1 = null; MethodCandidateInfo methodCandidate2 = null; for (JavaResolveResult result : resolveResults) { - if (!(result instanceof MethodCandidateInfo)) { + if (!(result instanceof MethodCandidateInfo candidate)) { continue; } - MethodCandidateInfo candidate = (MethodCandidateInfo)result; if (candidate.isApplicable() && !candidate.getElement().isConstructor()) { if (methodCandidate1 == null) { methodCandidate1 = candidate; @@ -861,14 +873,14 @@ public static HighlightInfo checkAmbiguousMethodCallIdentifier( if (methodCandidate2 != null) { return null; } - String description; + LocalizeValue description; PsiElement elementToHighlight = ObjectUtil.notNull(referenceToMethod.getReferenceNameElement(), referenceToMethod); if (element != null && !resolveResult.isAccessible()) { description = HighlightUtil.buildProblemWithAccessDescription(referenceToMethod, resolveResult); } else if (element != null && !resolveResult.isStaticsScopeCorrect()) { - if (element instanceof PsiMethod && ((PsiMethod)element).hasModifierProperty(PsiModifier.STATIC)) { - PsiClass containingClass = ((PsiMethod)element).getContainingClass(); + if (element instanceof PsiMethod method && method.isStatic()) { + PsiClass containingClass = method.getContainingClass(); if (containingClass != null && containingClass.isInterface()) { HighlightInfo info = HighlightUtil.checkFeature(elementToHighlight, JavaFeature.STATIC_INTERFACE_CALLS, languageLevel, file); @@ -881,19 +893,15 @@ else if (element != null && !resolveResult.isStaticsScopeCorrect()) { containingClass ); if (description != null) { - HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(highlightInfoType) + return HighlightInfo.newHighlightInfo(highlightInfoType) .range(elementToHighlight) - .description(description) - .escapedToolTip(XmlStringUtil.escapeString(description)) - .create(); - QuickFixAction.registerQuickFixAction( - highlightInfo, - QuickFixFactory.getInstance().createAccessStaticViaInstanceFix( + .description(description.get()) + .escapedToolTip(XmlStringUtil.escapeString(description.get())) + .registerFix(QuickFixFactory.getInstance().createAccessStaticViaInstanceFix( referenceToMethod, resolveResult - ) - ); - return highlightInfo; + ), null, null, null, null) + .create(); } } } @@ -902,7 +910,7 @@ else if (element != null && !resolveResult.isStaticsScopeCorrect()) { } else { String methodName = referenceToMethod.getReferenceName() + buildArgTypesList(list); - description = JavaErrorBundle.message("cannot.resolve.method", methodName); + description = JavaErrorLocalize.cannotResolveMethod(methodName); if (candidates.length == 0) { highlightInfoType = HighlightInfoType.WRONG_REF; } @@ -911,10 +919,10 @@ else if (element != null && !resolveResult.isStaticsScopeCorrect()) { } } - String toolTip = XmlStringUtil.escapeString(description); + String toolTip = XmlStringUtil.escapeString(description.get()); HighlightInfo info = HighlightInfo.newHighlightInfo(highlightInfoType) .range(elementToHighlight) - .description(description) + .description(description.get()) .escapedToolTip(toolTip) .create(); registerMethodCallIntentions(info, methodCall, list, resolveHelper); @@ -941,11 +949,12 @@ else if (element != null && !resolveResult.isStaticsScopeCorrect()) { } @Nullable + @RequiredReadAction public static HighlightInfo checkAmbiguousMethodCallArguments( @Nonnull PsiReferenceExpression referenceToMethod, @Nonnull JavaResolveResult[] resolveResults, @Nonnull PsiExpressionList list, - final PsiElement element, + PsiElement element, @Nonnull JavaResolveResult resolveResult, @Nonnull PsiMethodCallExpression methodCall, @Nonnull PsiResolveHelper resolveHelper, @@ -954,10 +963,9 @@ public static HighlightInfo checkAmbiguousMethodCallArguments( MethodCandidateInfo methodCandidate1 = null; MethodCandidateInfo methodCandidate2 = null; for (JavaResolveResult result : resolveResults) { - if (!(result instanceof MethodCandidateInfo)) { + if (!(result instanceof MethodCandidateInfo candidate)) { continue; } - MethodCandidateInfo candidate = (MethodCandidateInfo)result; if (candidate.isApplicable() && !candidate.getElement().isConstructor()) { if (methodCandidate1 == null) { methodCandidate1 = candidate; @@ -998,11 +1006,11 @@ public static HighlightInfo checkAmbiguousMethodCallArguments( m2 += " (In " + virtualFile2.getPresentableUrl() + ")"; } } - description = JavaErrorBundle.message("ambiguous.method.call", m1, m2); + description = JavaErrorLocalize.ambiguousMethodCall(m1, m2).get(); toolTip = createAmbiguousMethodHtmlTooltip(new MethodCandidateInfo[]{ methodCandidate1, methodCandidate2 - }); + }).get(); } else { if (element != null && !resolveResult.isAccessible()) { @@ -1012,7 +1020,7 @@ public static HighlightInfo checkAmbiguousMethodCallArguments( return null; } String methodName = referenceToMethod.getReferenceName() + buildArgTypesList(list); - description = JavaErrorBundle.message("cannot.resolve.method", methodName); + description = JavaErrorLocalize.cannotResolveMethod(methodName).get(); if (candidates.length == 0) { return null; } @@ -1055,17 +1063,14 @@ private static MethodCandidateInfo[] toMethodCandidates(@Nonnull JavaResolveResu List candidateList = new ArrayList<>(resolveResults.length); for (JavaResolveResult result : resolveResults) { - if (!(result instanceof MethodCandidateInfo)) { - continue; - } - MethodCandidateInfo candidate = (MethodCandidateInfo)result; - if (candidate.isAccessible()) { + if (result instanceof MethodCandidateInfo candidate && candidate.isAccessible()) { candidateList.add(candidate); } } return candidateList.toArray(new MethodCandidateInfo[candidateList.size()]); } + @RequiredReadAction private static void registerMethodCallIntentions( @Nullable HighlightInfo highlightInfo, PsiMethodCallExpression methodCall, @@ -1073,22 +1078,12 @@ private static void registerMethodCallIntentions( PsiResolveHelper resolveHelper ) { TextRange fixRange = getFixRange(methodCall); - final PsiExpression qualifierExpression = methodCall.getMethodExpression().getQualifierExpression(); - if (qualifierExpression instanceof PsiReferenceExpression) { - final PsiElement resolve = ((PsiReferenceExpression)qualifierExpression).resolve(); - if (resolve instanceof PsiClass - && ((PsiClass)resolve).getContainingClass() != null - && !((PsiClass)resolve).hasModifierProperty(PsiModifier.STATIC)) { - QuickFixAction.registerQuickFixAction( - highlightInfo, - QuickFixFactory.getInstance().createModifierListFix( - (PsiClass)resolve, - PsiModifier.STATIC, - true, - false - ) - ); - } + if (methodCall.getMethodExpression().getQualifierExpression() instanceof PsiReferenceExpression qualifierExpr + && qualifierExpr.resolve() instanceof PsiClass psiClass && psiClass.getContainingClass() != null && !psiClass.isStatic()) { + QuickFixAction.registerQuickFixAction( + highlightInfo, + QuickFixFactory.getInstance().createModifierListFix(psiClass, PsiModifier.STATIC, true, false) + ); } QuickFixAction.registerQuickFixAction( @@ -1146,8 +1141,11 @@ private static void registerMethodCallIntentions( for (IntentionAction action : QuickFixFactory.getInstance().getVariableTypeFromCallFixes(methodCall, list)) { QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, action); } - QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QuickFixFactory.getInstance() - .createReplaceAddAllArrayToCollectionFix(methodCall)); + QuickFixAction.registerQuickFixAction( + highlightInfo, + fixRange, + QuickFixFactory.getInstance().createReplaceAddAllArrayToCollectionFix(methodCall) + ); QuickFixAction.registerQuickFixAction( highlightInfo, fixRange, @@ -1159,6 +1157,7 @@ private static void registerMethodCallIntentions( ChangeStringLiteralToCharInMethodCallFix.registerFixes(candidates, methodCall, highlightInfo); } + @RequiredReadAction private static void registerMethodAccessLevelIntentions( CandidateInfo[] methodCandidates, PsiMethodCallExpression methodCall, @@ -1179,9 +1178,9 @@ private static void registerMethodAccessLevelIntentions( } @Nonnull - private static String createAmbiguousMethodHtmlTooltip(MethodCandidateInfo[] methodCandidates) { - return JavaErrorBundle.message( - "ambiguous.method.html.tooltip", + @RequiredReadAction + private static LocalizeValue createAmbiguousMethodHtmlTooltip(MethodCandidateInfo[] methodCandidates) { + return JavaErrorLocalize.ambiguousMethodHtmlTooltip( methodCandidates[0].getElement().getParameterList().getParametersCount() + 2, createAmbiguousMethodHtmlTooltipMethodRow (methodCandidates[0]), @@ -1191,18 +1190,19 @@ private static String createAmbiguousMethodHtmlTooltip(MethodCandidateInfo[] met ); } - private static String getContainingClassName(final MethodCandidateInfo methodCandidate) { + @RequiredReadAction + private static String getContainingClassName(MethodCandidateInfo methodCandidate) { PsiMethod method = methodCandidate.getElement(); PsiClass containingClass = method.getContainingClass(); return containingClass == null ? method.getContainingFile().getName() : HighlightUtil.formatClass(containingClass, false); } @Language("HTML") - private static String createAmbiguousMethodHtmlTooltipMethodRow(final MethodCandidateInfo methodCandidate) { + private static String createAmbiguousMethodHtmlTooltipMethodRow(MethodCandidateInfo methodCandidate) { PsiMethod method = methodCandidate.getElement(); PsiParameter[] parameters = method.getParameterList().getParameters(); PsiSubstitutor substitutor = methodCandidate.getSubstitutor(); - @NonNls @Language("HTML") String ms = "" + method.getName() + ""; + @Language("HTML") String ms = "" + method.getName() + ""; for (int j = 0; j < parameters.length; j++) { PsiParameter parameter = parameters[j]; @@ -1216,6 +1216,7 @@ private static String createAmbiguousMethodHtmlTooltipMethodRow(final MethodCand return ms; } + @RequiredReadAction private static String createMismatchedArgumentsHtmlTooltip(MethodCandidateInfo info, PsiExpressionList list) { PsiMethod method = info.getElement(); PsiSubstitutor substitutor = info.getSubstitutor(); @@ -1236,7 +1237,7 @@ private static String createShortMismatchedArgumentsHtmlTooltip( PsiExpression[] expressions = list.getExpressions(); int cols = Math.max(parameters.length, expressions.length); - @Language("HTML") @NonNls String parensizedName = methodName + (parameters.length == 0 ? "( ) " : ""); + @Language("HTML") String parensizedName = methodName + (parameters.length == 0 ? "( ) " : ""); String errorMessage = info != null ? info.getParentInferenceErrorMessage(list) : null; return JavaErrorBundle.message( "argument.mismatch.html.tooltip", @@ -1280,6 +1281,7 @@ private static String trimNicely(String s) { return StringUtil.last(s, 40, true).toString(); } + @RequiredReadAction private static String createMismatchedArgumentsHtmlTooltip( PsiExpressionList list, MethodCandidateInfo info, @@ -1293,6 +1295,7 @@ private static String createMismatchedArgumentsHtmlTooltip( : createLongMismatchedArgumentsHtmlTooltip(list, info, parameters, methodName, substitutor, aClass); } + @RequiredReadAction @SuppressWarnings("StringContatenationInLoop") @Language("HTML") private static String createLongMismatchedArgumentsHtmlTooltip( @@ -1305,7 +1308,7 @@ private static String createLongMismatchedArgumentsHtmlTooltip( ) { PsiExpression[] expressions = list.getExpressions(); - @SuppressWarnings("NonConstantStringShouldBeStringBuffer") @NonNls String s = + @SuppressWarnings("NonConstantStringShouldBeStringBuffer") String s = "" + "
" + "" + methodName + "() in " + HighlightUtil.formatClass( aClass, @@ -1317,7 +1320,7 @@ private static String createLongMismatchedArgumentsHtmlTooltip( PsiParameter parameter = i < parameters.length ? parameters[i] : null; PsiExpression expression = i < expressions.length ? expressions[i] : null; boolean showShort = showShortType(i, parameters, expressions, substitutor); - @NonNls String mismatchColor = showShort ? null : UIUtil.isUnderDarcula() ? "FF6B68" : "red"; + String mismatchColor = showShort ? null : UIUtil.isUnderDarcula() ? "FF6B68" : "red"; s += " superSignatures = methodSignature.getSuperSignatures(); + HierarchicalMethodSignature methodSignature = PsiSuperMethodImplUtil.getHierarchicalMethodSignature(method); + List superSignatures = methodSignature.getSuperSignatures(); if (superSignatures.isEmpty()) { return null; } - boolean isStatic = method.hasModifierProperty(PsiModifier.STATIC); + boolean isStatic = method.isStatic(); for (HierarchicalMethodSignature signature : superSignatures) { - final PsiMethod superMethod = signature.getMethod(); - final PsiClass superClass = superMethod.getContainingClass(); + PsiMethod superMethod = signature.getMethod(); + PsiClass superClass = superMethod.getContainingClass(); if (superClass == null) { continue; } - final HighlightInfo highlightInfo = + HighlightInfo highlightInfo = checkStaticMethodOverride(aClass, method, isStatic, superClass, superMethod, containingFile); if (highlightInfo != null) { return highlightInfo; @@ -1727,6 +1731,7 @@ public static HighlightInfo checkStaticMethodOverride(@Nonnull PsiMethod method, return null; } + @RequiredReadAction private static HighlightInfo checkStaticMethodOverride( PsiClass aClass, PsiMethod method, @@ -1750,21 +1755,18 @@ private static HighlightInfo checkStaticMethodOverride( } boolean isSuperMethodStatic = superModifierList.hasModifierProperty(PsiModifier.STATIC); if (isMethodStatic != isSuperMethodStatic) { - TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); - @NonNls final String messageKey = isMethodStatic - ? "static.method.cannot.override.instance.method" - : "instance.method.cannot.override.static.method"; - - String description = JavaErrorBundle.message( - messageKey, - JavaHighlightUtil.formatMethod(method), - HighlightUtil.formatClass(aClass), - JavaHighlightUtil.formatMethod(superMethod), - HighlightUtil.formatClass(superClass) - ); - - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + String m1 = JavaHighlightUtil.formatMethod(method); + String m2 = JavaHighlightUtil.formatMethod(superMethod); + String c1 = HighlightUtil.formatClass(aClass); + String c2 = HighlightUtil.formatClass(superClass); + LocalizeValue description = isMethodStatic + ? JavaErrorLocalize.staticMethodCannotOverrideInstanceMethod(m1, c1, m2, c2) + : JavaErrorLocalize.instanceMethodCannotOverrideStaticMethod(m1, c1, m2, c2); + + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(HighlightNamesUtil.getMethodDeclarationTextRange(method)) + .descriptionAndTooltip(description) + .create(); if (!isSuperMethodStatic || HighlightUtil.getIncompatibleModifier(PsiModifier.STATIC, modifierList) == null) { QuickFixAction.registerQuickFixAction( info, @@ -1816,7 +1818,7 @@ private static HighlightInfo checkInterfaceInheritedMethodsReturnTypes( if (superMethodSignatures.size() < 2) { return null; } - final MethodSignatureBackedByPsiMethod[] returnTypeSubstitutable = {superMethodSignatures.get(0)}; + MethodSignatureBackedByPsiMethod[] returnTypeSubstitutable = {superMethodSignatures.get(0)}; for (int i = 1; i < superMethodSignatures.size(); i++) { PsiMethod currentMethod = returnTypeSubstitutable[0].getMethod(); PsiType currentType = returnTypeSubstitutable[0].getSubstitutor().substitute(currentMethod.getReturnType()); @@ -1837,7 +1839,7 @@ private static HighlightInfo checkInterfaceInheritedMethodsReturnTypes( } PsiType otherReturnType = otherSuperReturnType; PsiType curType = currentType; - final HighlightInfo info = + HighlightInfo info = LambdaUtil.performWithSubstitutedParameterBounds(otherSuperMethod.getTypeParameters(), otherSubstitutor, () -> { if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5)) { @@ -1860,7 +1862,7 @@ private static HighlightInfo checkInterfaceInheritedMethodsReturnTypes( currentMethod, curType, otherReturnType, - JavaErrorBundle.message("unrelated.overriding.methods.return.types"), + JavaErrorLocalize.unrelatedOverridingMethodsReturnTypes(), TextRange.EMPTY_RANGE ); }); @@ -1871,6 +1873,7 @@ private static HighlightInfo checkInterfaceInheritedMethodsReturnTypes( return null; } + @RequiredReadAction public static HighlightInfo checkOverrideEquivalentInheritedMethods( PsiClass aClass, PsiFile containingFile, @@ -1878,7 +1881,7 @@ public static HighlightInfo checkOverrideEquivalentInheritedMethods( ) { String description = null; boolean appendImplementMethodFix = true; - final Collection visibleSignatures = aClass.getVisibleSignatures(); + Collection visibleSignatures = aClass.getVisibleSignatures(); PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(aClass.getProject()).getResolveHelper(); Ultimate: for (HierarchicalMethodSignature signature : visibleSignatures) { @@ -1888,8 +1891,8 @@ public static HighlightInfo checkOverrideEquivalentInheritedMethods( } List superSignatures = signature.getSuperSignatures(); - boolean allAbstracts = method.hasModifierProperty(PsiModifier.ABSTRACT); - final PsiClass containingClass = method.getContainingClass(); + boolean allAbstracts = method.isAbstract(); + PsiClass containingClass = method.getContainingClass(); if (aClass.equals(containingClass)) { continue; //to be checked at method level } @@ -1910,17 +1913,15 @@ public static HighlightInfo checkOverrideEquivalentInheritedMethods( description = highlightInfo.getDescription(); } - if (method.hasModifierProperty(PsiModifier.STATIC)) { + if (method.isStatic()) { for (HierarchicalMethodSignature superSignature : superSignatures) { PsiMethod superMethod = superSignature.getMethod(); - if (!superMethod.hasModifierProperty(PsiModifier.STATIC)) { - description = JavaErrorBundle.message( - "static.method.cannot.override.instance.method", - JavaHighlightUtil.formatMethod(method), + if (!superMethod.isStatic()) { + description = JavaErrorLocalize.staticMethodCannotOverrideInstanceMethod(JavaHighlightUtil.formatMethod(method), HighlightUtil.formatClass(containingClass), JavaHighlightUtil.formatMethod(superMethod), HighlightUtil.formatClass(superMethod.getContainingClass()) - ); + ).get(); appendImplementMethodFix = false; break Ultimate; } @@ -1950,7 +1951,7 @@ public static HighlightInfo checkOverrideEquivalentInheritedMethods( if (description != null) { // show error info at the class level TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - final HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(textRange) .descriptionAndTooltip(description) .create(); @@ -1998,45 +1999,47 @@ public static HighlightInfo checkConstructorHandleSuperClassExceptions(PsiMethod return highlightInfo; } - public static HighlightInfo checkRecursiveConstructorInvocation(@Nonnull PsiMethod method) { - if (HighlightControlFlowUtil.isRecursivelyCalledConstructor(method)) { - TextRange textRange = HighlightNamesUtil.getMethodDeclarationTextRange(method); - String description = JavaErrorBundle.message("recursive.constructor.invocation"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + if (!HighlightControlFlowUtil.isRecursivelyCalledConstructor(method)) { + return null; } - return null; + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(HighlightNamesUtil.getMethodDeclarationTextRange(method)) + .descriptionAndTooltip(JavaErrorLocalize.recursiveConstructorInvocation()) + .create(); } @Nonnull + @RequiredReadAction public static TextRange getFixRange(@Nonnull PsiElement element) { TextRange range = element.getTextRange(); int start = range.getStartOffset(); int end = range.getEndOffset(); PsiElement nextSibling = element.getNextSibling(); - if (nextSibling instanceof PsiJavaToken && ((PsiJavaToken)nextSibling).getTokenType() == JavaTokenType.SEMICOLON) { + if (nextSibling instanceof PsiJavaToken javaToken && javaToken.getTokenType() == JavaTokenType.SEMICOLON) { return new TextRange(start, end + 1); } return range; } + @RequiredReadAction public static void checkNewExpression( @Nonnull PsiNewExpression expression, PsiType type, @Nonnull HighlightInfoHolder holder, @Nonnull JavaSdkVersion javaSdkVersion ) { - if (!(type instanceof PsiClassType)) { + if (!(type instanceof PsiClassType classType)) { return; } - PsiClassType.ClassResolveResult typeResult = ((PsiClassType)type).resolveGenerics(); + PsiClassType.ClassResolveResult typeResult = classType.resolveGenerics(); PsiClass aClass = typeResult.getElement(); if (aClass == null) { return; } - if (aClass instanceof PsiAnonymousClass) { - type = ((PsiAnonymousClass)aClass).getBaseClassType(); + if (aClass instanceof PsiAnonymousClass anonymousClass) { + type = anonymousClass.getBaseClassType(); typeResult = ((PsiClassType)type).resolveGenerics(); aClass = typeResult.getElement(); if (aClass == null) { @@ -2048,6 +2051,7 @@ public static void checkNewExpression( checkConstructorCall(typeResult, expression, type, classReference, holder, javaSdkVersion); } + @RequiredReadAction public static void checkConstructorCall( @Nonnull PsiClassType.ClassResolveResult typeResolveResult, @Nonnull PsiConstructorCall constructorCall, @@ -2064,19 +2068,19 @@ public static void checkConstructorCall( if (aClass == null) { return; } - final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(holder.getProject()).getResolveHelper(); + PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(holder.getProject()).getResolveHelper(); PsiClass accessObjectClass = null; - if (constructorCall instanceof PsiNewExpression) { - PsiExpression qualifier = ((PsiNewExpression)constructorCall).getQualifier(); + if (constructorCall instanceof PsiNewExpression newExpr) { + PsiExpression qualifier = newExpr.getQualifier(); if (qualifier != null) { accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass(qualifier).getElement(); } } if (classReference != null && !resolveHelper.isAccessible(aClass, constructorCall, accessObjectClass)) { - String description = HighlightUtil.buildProblemWithAccessDescription(classReference, typeResolveResult); - PsiElement element = classReference.getReferenceNameElement(); - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(classReference.getReferenceNameElement()) + .descriptionAndTooltip(HighlightUtil.buildProblemWithAccessDescription(classReference, typeResolveResult)) + .create(); HighlightUtil.registerAccessQuickFixAction(aClass, classReference, info, null); holder.add(info); return; @@ -2087,7 +2091,6 @@ public static void checkConstructorCall( if (list.getExpressions().length != 0) { String constructorName = aClass.getName(); String argTypes = buildArgTypesList(list); - String description = JavaErrorBundle.message("wrong.constructor.arguments", constructorName + "()", argTypes); String tooltip = createMismatchedArgumentsHtmlTooltip( list, null, @@ -2098,7 +2101,7 @@ public static void checkConstructorCall( ); HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(list) - .description(description) + .description(JavaErrorLocalize.wrongConstructorArguments(constructorName + "()", argTypes).get()) .escapedToolTip(tooltip) .navigationShift(+1) .create(); @@ -2113,12 +2116,12 @@ public static void checkConstructorCall( holder.add(info); return; } - if (classReference != null && aClass.hasModifierProperty(PsiModifier.PROTECTED) + if (classReference != null && aClass.isProtected() && callingProtectedConstructorFromDerivedClass(constructorCall, aClass)) { holder.add(buildAccessProblem(classReference, typeResolveResult, aClass)); } - else if (aClass.isInterface() && constructorCall instanceof PsiNewExpression) { - final PsiReferenceParameterList typeArgumentList = ((PsiNewExpression)constructorCall).getTypeArgumentList(); + else if (aClass.isInterface() && constructorCall instanceof PsiNewExpression newExpr) { + PsiReferenceParameterList typeArgumentList = newExpr.getTypeArgumentList(); if (typeArgumentList.getTypeArguments().length > 0) { holder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(typeArgumentList) @@ -2129,8 +2132,8 @@ else if (aClass.isInterface() && constructorCall instanceof PsiNewExpression) { } else { PsiElement place = list; - if (constructorCall instanceof PsiNewExpression) { - final PsiAnonymousClass anonymousClass = ((PsiNewExpression)constructorCall).getAnonymousClass(); + if (constructorCall instanceof PsiNewExpression newExpr) { + PsiAnonymousClass anonymousClass = newExpr.getAnonymousClass(); if (anonymousClass != null) { place = anonymousClass; } @@ -2146,11 +2149,11 @@ else if (aClass.isInterface() && constructorCall instanceof PsiNewExpression) { boolean applicable = true; try { - final PsiDiamondType diamondType = - constructorCall instanceof PsiNewExpression ? PsiDiamondType.getDiamondType((PsiNewExpression)constructorCall) : null; - final JavaResolveResult staticFactory = diamondType != null ? diamondType.getStaticFactory() : null; - applicable = staticFactory instanceof MethodCandidateInfo - ? ((MethodCandidateInfo)staticFactory).isApplicable() + PsiDiamondType diamondType = + constructorCall instanceof PsiNewExpression newExpr ? PsiDiamondType.getDiamondType(newExpr) : null; + JavaResolveResult staticFactory = diamondType != null ? diamondType.getStaticFactory() : null; + applicable = staticFactory instanceof MethodCandidateInfo info + ? info.isApplicable() : result != null && result.isApplicable(); } catch (IndexNotReadyException e) { @@ -2161,10 +2164,9 @@ else if (aClass.isInterface() && constructorCall instanceof PsiNewExpression) { if (constructor == null) { String name = aClass.getName(); name += buildArgTypesList(list); - String description = JavaErrorBundle.message("cannot.resolve.constructor", name); HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(list) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.cannotResolveConstructor(name)) .navigationShift(+1) .create(); if (info != null) { @@ -2183,27 +2185,25 @@ else if (aClass.isInterface() && constructorCall instanceof PsiNewExpression) { } } else if (classReference != null && (!result.isAccessible() - || constructor.hasModifierProperty(PsiModifier.PROTECTED) - && callingProtectedConstructorFromDerivedClass(constructorCall, aClass))) { + || constructor.isProtected() && callingProtectedConstructorFromDerivedClass(constructorCall, aClass))) { holder.add(buildAccessProblem(classReference, result, constructor)); } else if (!applicable) { String constructorName = HighlightMessageUtil.getSymbolName(constructor, result.getSubstitutor()); String containerName = HighlightMessageUtil.getSymbolName(constructor.getContainingClass(), result.getSubstitutor()); String argTypes = buildArgTypesList(list); - String description = JavaErrorBundle.message("wrong.method.arguments", constructorName, containerName, argTypes); String toolTip = createMismatchedArgumentsHtmlTooltip(result, list); HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(infoElement) - .description(description) + .description(JavaErrorLocalize.wrongMethodArguments(constructorName, containerName, argTypes).get()) .escapedToolTip(toolTip) .navigationShift(+1) .create(); if (info != null) { JavaResolveResult[] methodCandidates = results; - if (constructorCall instanceof PsiNewExpression) { - methodCandidates = resolveHelper.getReferencedMethodCandidates((PsiCallExpression)constructorCall, true); + if (constructorCall instanceof PsiNewExpression newExpr) { + methodCandidates = resolveHelper.getReferencedMethodCandidates(newExpr, true); } registerFixesOnInvalidConstructorCall( constructorCall, @@ -2219,11 +2219,10 @@ else if (!applicable) { holder.add(info); } } - else if (constructorCall instanceof PsiNewExpression) { - PsiReferenceParameterList typeArgumentList = ((PsiNewExpression)constructorCall).getTypeArgumentList(); + else if (constructorCall instanceof PsiNewExpression newExpr) { HighlightInfo info = GenericsHighlightUtil.checkReferenceTypeArgumentList( constructor, - typeArgumentList, + newExpr.getTypeArgumentList(), result.getSubstitutor(), false, javaSdkVersion @@ -2244,20 +2243,21 @@ else if (constructorCall instanceof PsiNewExpression) { * then where the last formal parameter type of the invocation type of the method is Fn[], * it is a compile-time error if the type which is the erasure of Fn is not accessible at the point of invocation. */ + @RequiredReadAction private static HighlightInfo checkVarargParameterErasureToBeAccessible(MethodCandidateInfo info, PsiCall place) { - final PsiMethod method = info.getElement(); + PsiMethod method = info.getElement(); if (info.isVarargs() || method.isVarArgs() && !PsiUtil.isLanguageLevel8OrHigher(place)) { - final PsiParameter[] parameters = method.getParameterList().getParameters(); - final PsiType componentType = ((PsiEllipsisType)parameters[parameters.length - 1].getType()).getComponentType(); - final PsiType substitutedTypeErasure = TypeConversionUtil.erasure(info.getSubstitutor().substitute(componentType)); - final PsiClass targetClass = PsiUtil.resolveClassInClassTypeOnly(substitutedTypeErasure); + PsiParameter[] parameters = method.getParameterList().getParameters(); + PsiType componentType = ((PsiEllipsisType)parameters[parameters.length - 1].getType()).getComponentType(); + PsiType substitutedTypeErasure = TypeConversionUtil.erasure(info.getSubstitutor().substitute(componentType)); + PsiClass targetClass = PsiUtil.resolveClassInClassTypeOnly(substitutedTypeErasure); if (targetClass != null && !PsiUtil.isAccessible(targetClass, place, null)) { - final PsiExpressionList argumentList = place.getArgumentList(); + PsiExpressionList argumentList = place.getArgumentList(); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .descriptionAndTooltip( + .descriptionAndTooltip(LocalizeValue.localizeTODO( "Formal varargs element type " + PsiFormatUtil.formatClass(targetClass, PsiFormatUtilBase.SHOW_FQ_NAME) + " is inaccessible here" - ) + )) .range(argumentList != null ? argumentList : place) .create(); } @@ -2265,6 +2265,7 @@ private static HighlightInfo checkVarargParameterErasureToBeAccessible(MethodCan return null; } + @RequiredReadAction private static void registerFixesOnInvalidConstructorCall( PsiConstructorCall constructorCall, PsiJavaCodeReferenceElement classReference, @@ -2273,10 +2274,13 @@ private static void registerFixesOnInvalidConstructorCall( PsiMethod[] constructors, JavaResolveResult[] results, PsiElement infoElement, - @Nonnull final HighlightInfo info + @Nonnull HighlightInfo info ) { - QuickFixAction.registerQuickFixAction(info, constructorCall.getTextRange(), QuickFixFactory.getInstance() - .createCreateConstructorFromCallFix(constructorCall)); + QuickFixAction.registerQuickFixAction( + info, + constructorCall.getTextRange(), + QuickFixFactory.getInstance().createCreateConstructorFromCallFix(constructorCall) + ); if (classReference != null) { ConstructorParametersFixer.registerFixActions(classReference, constructorCall, info, getFixRange(infoElement)); ChangeTypeArgumentsFix.registerIntentions(results, list, info, aClass); @@ -2285,20 +2289,23 @@ private static void registerFixesOnInvalidConstructorCall( registerChangeMethodSignatureFromUsageIntentions(results, list, info, null); PermuteArgumentsFix.registerFix(info, constructorCall, toMethodCandidates(results), getFixRange(list)); registerChangeParameterClassFix(constructorCall, list, info); - QuickFixAction.registerQuickFixAction(info, getFixRange(list), QuickFixFactory.getInstance() - .createSurroundWithArrayFix(constructorCall, null)); + QuickFixAction.registerQuickFixAction( + info, + getFixRange(list), + QuickFixFactory.getInstance().createSurroundWithArrayFix(constructorCall, null) + ); ChangeStringLiteralToCharInMethodCallFix.registerFixes(constructors, constructorCall, info); } + @RequiredReadAction private static HighlightInfo buildAccessProblem( @Nonnull PsiJavaCodeReferenceElement classReference, JavaResolveResult result, PsiMember elementToFix ) { - String description = HighlightUtil.buildProblemWithAccessDescription(classReference, result); HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(classReference) - .descriptionAndTooltip(description) + .descriptionAndTooltip(HighlightUtil.buildProblemWithAccessDescription(classReference, result)) .navigationShift(+1) .create(); if (result.isStaticsScopeCorrect()) { @@ -2312,7 +2319,7 @@ private static boolean callingProtectedConstructorFromDerivedClass(PsiConstructo return false; } // indirect instantiation via anonymous class is ok - if (place instanceof PsiNewExpression && ((PsiNewExpression)place).getAnonymousClass() != null) { + if (place instanceof PsiNewExpression newExpr && newExpr.getAnonymousClass() != null) { return false; } PsiElement curElement = place; @@ -2351,22 +2358,22 @@ private static void registerChangeParameterClassFix( @Nonnull PsiExpressionList list, HighlightInfo highlightInfo ) { - final JavaResolveResult result = methodCall.resolveMethodGenerics(); + JavaResolveResult result = methodCall.resolveMethodGenerics(); PsiMethod method = (PsiMethod)result.getElement(); - final PsiSubstitutor substitutor = result.getSubstitutor(); + PsiSubstitutor substitutor = result.getSubstitutor(); PsiExpression[] expressions = list.getExpressions(); if (method == null) { return; } - final PsiParameter[] parameters = method.getParameterList().getParameters(); + PsiParameter[] parameters = method.getParameterList().getParameters(); if (parameters.length != expressions.length) { return; } for (int i = 0; i < expressions.length; i++) { - final PsiExpression expression = expressions[i]; - final PsiParameter parameter = parameters[i]; - final PsiType expressionType = expression.getType(); - final PsiType parameterType = substitutor.substitute(parameter.getType()); + PsiExpression expression = expressions[i]; + PsiParameter parameter = parameters[i]; + PsiType expressionType = expression.getType(); + PsiType parameterType = substitutor.substitute(parameter.getType()); if (expressionType == null || expressionType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(expressionType) @@ -2383,19 +2390,15 @@ private static void registerChangeParameterClassFix( } PsiClass parameterClass = PsiUtil.resolveClassInType(parameterType); PsiClass expressionClass = PsiUtil.resolveClassInType(expressionType); - if (parameterClass == null || expressionClass == null) { - continue; - } - if (expressionClass instanceof PsiAnonymousClass) { - continue; - } - if (parameterClass.isInheritor(expressionClass, true)) { + if (parameterClass == null + || expressionClass == null + || expressionClass instanceof PsiAnonymousClass + || parameterClass.isInheritor(expressionClass, true)) { continue; } QuickFixAction.registerQuickFixAction( highlightInfo, - QuickFixFactory.getInstance() - .createChangeParameterClassFix(expressionClass, (PsiClassType)parameterType) + QuickFixFactory.getInstance().createChangeParameterClassFix(expressionClass, (PsiClassType)parameterType) ); } } diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightUtil.java index aaa9600dd3..a024cb0228 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -65,6 +65,7 @@ import consulo.language.psi.util.PsiMatcherImpl; import consulo.language.psi.util.PsiTreeUtil; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.module.Module; import consulo.module.content.FilePropertyPusher; @@ -244,9 +245,9 @@ private static String getIncompatibleModifier( if (incompatibles == null) { return null; } - final PsiElement parent = modifierList.getParent(); - final boolean level8OrHigher = PsiUtil.isLanguageLevel8OrHigher(modifierList); - final boolean level9OrHigher = PsiUtil.isLanguageLevel9OrHigher(modifierList); + PsiElement parent = modifierList.getParent(); + boolean level8OrHigher = PsiUtil.isLanguageLevel8OrHigher(modifierList); + boolean level9OrHigher = PsiUtil.isLanguageLevel9OrHigher(modifierList); for (@PsiModifier.ModifierConstant String incompatible : incompatibles) { if (level8OrHigher) { if (modifier.equals(PsiModifier.STATIC) && incompatible.equals(PsiModifier.ABSTRACT)) { @@ -259,7 +260,7 @@ private static String getIncompatibleModifier( } if (modifier.equals(PsiModifier.STATIC) && incompatible.equals(PsiModifier.FINAL)) { - final PsiClass containingClass = ((PsiMethod)parent).getContainingClass(); + PsiClass containingClass = ((PsiMethod)parent).getContainingClass(); if (containingClass == null || !containingClass.isInterface()) { continue; } @@ -284,7 +285,7 @@ public static void registerAccessQuickFixAction( @Nonnull PsiMember refElement, @Nonnull PsiJavaCodeReferenceElement place, @Nullable HighlightInfo errorResult, - final PsiElement fileResolveScope + PsiElement fileResolveScope ) { if (errorResult == null) { return; @@ -414,6 +415,7 @@ public static HighlightInfo checkInstanceOfApplicable(@Nonnull PsiInstanceOfExpr * - No two listed types may be subtypes of different parameterization of the same generic interface. */ @Nullable + @RequiredReadAction public static HighlightInfo checkIntersectionInTypeCast( @Nonnull PsiTypeCastExpression expression, @Nonnull LanguageLevel languageLevel, @@ -426,18 +428,18 @@ public static HighlightInfo checkIntersectionInTypeCast( return info; } - final PsiTypeElement[] conjuncts = PsiTreeUtil.getChildrenOfType(castTypeElement, PsiTypeElement.class); + PsiTypeElement[] conjuncts = PsiTreeUtil.getChildrenOfType(castTypeElement, PsiTypeElement.class); if (conjuncts != null) { - final Set erasures = new HashSet<>(conjuncts.length); + Set erasures = new HashSet<>(conjuncts.length); erasures.add(TypeConversionUtil.erasure(conjuncts[0].getType())); - final List conjList = new ArrayList<>(Arrays.asList(conjuncts)); + List conjList = new ArrayList<>(Arrays.asList(conjuncts)); for (int i = 1; i < conjuncts.length; i++) { - final PsiTypeElement conjunct = conjuncts[i]; - final PsiType conjType = conjunct.getType(); + PsiTypeElement conjunct = conjuncts[i]; + PsiType conjType = conjunct.getType(); if (conjType instanceof PsiClassType) { - final PsiClass aClass = ((PsiClassType)conjType).resolve(); + PsiClass aClass = ((PsiClassType)conjType).resolve(); if (aClass != null && !aClass.isInterface()) { - final HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(conjunct) .descriptionAndTooltip(JavaErrorBundle.message("interface.expected")) .create(); @@ -456,19 +458,18 @@ public static HighlightInfo checkIntersectionInTypeCast( .create(); } if (!erasures.add(TypeConversionUtil.erasure(conjType))) { - final HighlightInfo highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(conjunct) - .descriptionAndTooltip("Repeated interface") - .create(); + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(conjunct) + .descriptionAndTooltip("Repeated interface") + .create(); QuickFixAction.registerQuickFixAction(highlightInfo, new DeleteRepeatedInterfaceFix(conjunct, conjList), null); return highlightInfo; } } - final List typeList = ContainerUtil.map(conjList, PsiTypeElement::getType); - final Ref differentArgumentsMessage = new Ref<>(); - final PsiClass sameGenericParameterization = InferenceSession.findParameterizationOfTheSameGenericClass(typeList, pair -> + List typeList = ContainerUtil.map(conjList, PsiTypeElement::getType); + Ref differentArgumentsMessage = new Ref<>(); + PsiClass sameGenericParameterization = InferenceSession.findParameterizationOfTheSameGenericClass(typeList, pair -> { if (!TypesDistinctProver.provablyDistinct(pair.first, pair.second)) { return true; @@ -477,7 +478,7 @@ public static HighlightInfo checkIntersectionInTypeCast( return false; }); if (sameGenericParameterization != null) { - final String message = + String message = formatClass(sameGenericParameterization) + " cannot be inherited with different arguments: " + differentArgumentsMessage.get(); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) @@ -499,7 +500,7 @@ private static boolean isIntersection(PsiTypeElement castTypeElement, PsiType ca @Nullable public static HighlightInfo checkInconvertibleTypeCast(@Nonnull PsiTypeCastExpression expression) { - final PsiTypeElement castTypeElement = expression.getCastType(); + PsiTypeElement castTypeElement = expression.getCastType(); if (castTypeElement == null) { return null; } @@ -549,8 +550,8 @@ else if (PsiUtil.isIncrementDecrementOperation(expression)) { return errorResult; } - @Nullable + @RequiredReadAction public static HighlightInfo checkAssignmentOperatorApplicable(@Nonnull PsiAssignmentExpression assignment) { PsiJavaToken operationSign = assignment.getOperationSign(); IElementType eqOpSign = operationSign.getTokenType(); @@ -558,29 +559,30 @@ public static HighlightInfo checkAssignmentOperatorApplicable(@Nonnull PsiAssign if (opSign == null) { return null; } - final PsiType lType = assignment.getLExpression().getType(); - final PsiExpression rExpression = assignment.getRExpression(); + PsiType lType = assignment.getLExpression().getType(); + PsiExpression rExpression = assignment.getRExpression(); if (rExpression == null) { return null; } - final PsiType rType = rExpression.getType(); - HighlightInfo errorResult = null; + PsiType rType = rExpression.getType(); if (!TypeConversionUtil.isBinaryOperatorApplicable(opSign, lType, rType, true)) { String operatorText = operationSign.getText().substring(0, operationSign.getText().length() - 1); - String message = JavaErrorBundle.message( - "binary.operator.not.applicable", + LocalizeValue message = JavaErrorLocalize.binaryOperatorNotApplicable( operatorText, JavaHighlightUtil.formatType(lType), JavaHighlightUtil.formatType(rType) ); - errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(assignment).descriptionAndTooltip(message).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(assignment) + .descriptionAndTooltip(message) + .create(); } - return errorResult; + return null; } - @Nullable + @RequiredReadAction public static HighlightInfo checkAssignmentCompatibleTypes(@Nonnull PsiAssignmentExpression assignment) { PsiExpression lExpr = assignment.getLExpression(); PsiExpression rExpr = assignment.getRExpression(); @@ -593,15 +595,15 @@ public static HighlightInfo checkAssignmentCompatibleTypes(@Nonnull PsiAssignmen return null; } - final IElementType sign = assignment.getOperationTokenType(); + IElementType sign = assignment.getOperationTokenType(); HighlightInfo highlightInfo; if (JavaTokenType.EQ.equals(sign)) { highlightInfo = checkAssignability(lType, rType, rExpr, assignment); } else { // 15.26.2. Compound Assignment Operators - final IElementType opSign = TypeConversionUtil.convertEQtoOperation(sign); - final PsiType type = TypeConversionUtil.calcTypeForBinaryExpression(lType, rType, opSign, true); + IElementType opSign = TypeConversionUtil.convertEQtoOperation(sign); + PsiType type = TypeConversionUtil.calcTypeForBinaryExpression(lType, rType, opSign, true); if (type == null || lType == null || TypeConversionUtil.areTypesConvertible(type, lType)) { return null; } @@ -621,44 +623,43 @@ public static HighlightInfo checkAssignmentCompatibleTypes(@Nonnull PsiAssignmen return highlightInfo; } + @RequiredReadAction private static void registerChangeVariableTypeFixes( @Nonnull PsiExpression expression, @Nonnull PsiType type, - @Nullable final PsiExpression lExpr, + @Nullable PsiExpression lExpr, @Nullable HighlightInfo highlightInfo ) { - if (highlightInfo == null || !(expression instanceof PsiReferenceExpression)) { - return; - } - - final PsiElement element = ((PsiReferenceExpression)expression).resolve(); - if (!(element instanceof PsiVariable)) { + if (highlightInfo == null || !(expression instanceof PsiReferenceExpression refExpr) + || !(refExpr.resolve() instanceof PsiVariable variable)) { return; } - registerChangeVariableTypeFixes((PsiVariable)element, type, lExpr, highlightInfo); + registerChangeVariableTypeFixes(variable, type, lExpr, highlightInfo); - if (lExpr instanceof PsiMethodCallExpression && lExpr.getParent() instanceof PsiAssignmentExpression) { - final PsiElement parent = lExpr.getParent(); - if (parent.getParent() instanceof PsiStatement) { - final PsiMethod method = ((PsiMethodCallExpression)lExpr).resolveMethod(); - if (method != null && PsiType.VOID.equals(method.getReturnType())) { - QuickFixAction.registerQuickFixAction( - highlightInfo, - new ReplaceAssignmentFromVoidWithStatementIntentionAction(parent, lExpr) - ); - } + if (lExpr instanceof PsiMethodCallExpression methodCall + && methodCall.getParent() instanceof PsiAssignmentExpression assignment + && assignment.getParent() instanceof PsiStatement) { + PsiMethod method = methodCall.resolveMethod(); + if (method != null && PsiType.VOID.equals(method.getReturnType())) { + highlightInfo.registerFix( + new ReplaceAssignmentFromVoidWithStatementIntentionAction(assignment, lExpr), + null, + null, + null, + null + ); } } } private static boolean isCastIntentionApplicable(@Nonnull PsiExpression expression, @Nullable PsiType toType) { while (expression instanceof PsiTypeCastExpression || expression instanceof PsiParenthesizedExpression) { - if (expression instanceof PsiTypeCastExpression) { - expression = ((PsiTypeCastExpression)expression).getOperand(); + if (expression instanceof PsiTypeCastExpression typeCast) { + expression = typeCast.getOperand(); } - if (expression instanceof PsiParenthesizedExpression) { - expression = ((PsiParenthesizedExpression)expression).getExpression(); + if (expression instanceof PsiParenthesizedExpression parenthesized) { + expression = parenthesized.getExpression(); } } if (expression == null) { @@ -670,6 +671,7 @@ private static boolean isCastIntentionApplicable(@Nonnull PsiExpression expressi @Nullable + @RequiredReadAction public static HighlightInfo checkVariableInitializerType(@Nonnull PsiVariable variable) { PsiExpression initializer = variable.getInitializer(); // array initializer checked in checkArrayInitializerApplicable @@ -690,6 +692,7 @@ public static HighlightInfo checkVariableInitializerType(@Nonnull PsiVariable va } @Nullable + @RequiredReadAction public static HighlightInfo checkAssignability( @Nullable PsiType lType, @Nullable PsiType rType, @@ -744,8 +747,8 @@ else if (TypeConversionUtil.areTypesAssignmentCompatible(lType, expression)) { return highlightInfo; } - @Nullable + @RequiredReadAction public static HighlightInfo checkReturnStatementType(@Nonnull PsiReturnStatement statement) { PsiMethod method = null; PsiLambdaExpression lambda = null; @@ -770,15 +773,15 @@ public static HighlightInfo checkReturnStatementType(@Nonnull PsiReturnStatement if (parent instanceof PsiCodeFragment) { return null; } - String description; HighlightInfo errorResult = null; if (method == null && lambda != null) { //todo check return statements type inside lambda } else if (method == null && !(parent instanceof ServerPageFile)) { - description = JavaErrorBundle.message("return.outside.method"); - errorResult = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(description).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(statement) + .descriptionAndTooltip(JavaErrorLocalize.returnOutsideMethod()) + .create(); } else { PsiType returnType = method != null ? method.getReturnType() : null/*JSP page returns void*/; @@ -787,12 +790,10 @@ else if (method == null && !(parent instanceof ServerPageFile)) { if (returnValue != null) { PsiType valueType = RefactoringChangeUtil.getTypeByExpression(returnValue); if (isMethodVoid) { - description = JavaErrorBundle.message("return.from.void.method"); - errorResult = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(statement) - .descriptionAndTooltip(description) - .create(); + errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(statement) + .descriptionAndTooltip(JavaErrorLocalize.returnFromVoidMethod()) + .create(); if (valueType != null) { QuickFixAction.registerQuickFixAction( errorResult, @@ -811,10 +812,10 @@ else if (method == null && !(parent instanceof ServerPageFile)) { ); } registerChangeParameterClassFix(returnType, valueType, errorResult); - if (returnType instanceof PsiArrayType) { - final PsiType erasedValueType = TypeConversionUtil.erasure(valueType); + if (returnType instanceof PsiArrayType arrayType) { + PsiType erasedValueType = TypeConversionUtil.erasure(valueType); if (erasedValueType != null - && TypeConversionUtil.isAssignable(((PsiArrayType)returnType).getComponentType(), erasedValueType)) { + && TypeConversionUtil.isAssignable(arrayType.getComponentType(), erasedValueType)) { QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance() .createSurroundWithArrayFix(null, returnValue)); } @@ -823,19 +824,13 @@ else if (method == null && !(parent instanceof ServerPageFile)) { } } } - else { - if (!isMethodVoid) { - description = JavaErrorBundle.message("missing.return.value"); - errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(statement) - .descriptionAndTooltip(description) - .navigationShift(PsiKeyword.RETURN.length()) - .create(); - QuickFixAction.registerQuickFixAction( - errorResult, - QuickFixFactory.getInstance().createMethodReturnFix(method, PsiType.VOID, true) - ); - } + else if (!isMethodVoid) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(statement) + .descriptionAndTooltip(JavaErrorLocalize.missingReturnValue()) + .navigationShift(PsiKeyword.RETURN.length()) + .registerFix(QuickFixFactory.getInstance().createMethodReturnFix(method, PsiType.VOID, true), null, null, null, null) + .create(); } } return errorResult; @@ -864,19 +859,16 @@ private static void registerCollectionToArrayFixAction( } @Nonnull - public static String getUnhandledExceptionsDescriptor(@Nonnull final Collection unhandled) { + public static String getUnhandledExceptionsDescriptor(@Nonnull Collection unhandled) { return getUnhandledExceptionsDescriptor(unhandled, null); } @Nonnull - private static String getUnhandledExceptionsDescriptor( - @Nonnull final Collection unhandled, - @Nullable final String source - ) { - final String exceptions = formatTypes(unhandled); + private static String getUnhandledExceptionsDescriptor(@Nonnull Collection unhandled, @Nullable String source) { + String exceptions = formatTypes(unhandled); return source != null - ? JavaErrorBundle.message("unhandled.close.exceptions", exceptions, unhandled.size(), source) - : JavaErrorBundle.message("unhandled.exceptions", exceptions, unhandled.size()); + ? JavaErrorLocalize.unhandledCloseExceptions(exceptions, unhandled.size(), source).get() + : JavaErrorLocalize.unhandledExceptions(exceptions, unhandled.size()).get(); } @Nonnull @@ -947,13 +939,13 @@ private static String formatField(@Nonnull PsiField field) { } @Nullable - public static HighlightInfo checkUnhandledExceptions(@Nonnull final PsiElement element, @Nullable TextRange textRange) { - final List unhandledExceptions = ExceptionUtil.getUnhandledExceptions(element); + public static HighlightInfo checkUnhandledExceptions(@Nonnull PsiElement element, @Nullable TextRange textRange) { + List unhandledExceptions = ExceptionUtil.getUnhandledExceptions(element); if (unhandledExceptions.isEmpty()) { return null; } - final HighlightInfoType highlightType = getUnhandledExceptionHighlightType(element); + HighlightInfoType highlightType = getUnhandledExceptionHighlightType(element); if (highlightType == null) { return null; } @@ -961,7 +953,7 @@ public static HighlightInfo checkUnhandledExceptions(@Nonnull final PsiElement e if (textRange == null) { textRange = element.getTextRange(); } - final String description = getUnhandledExceptionsDescriptor(unhandledExceptions); + String description = getUnhandledExceptionsDescriptor(unhandledExceptions); HighlightInfo errorResult = HighlightInfo.newHighlightInfo(highlightType).range(textRange).descriptionAndTooltip(description).create(); registerUnhandledExceptionFixes(element, errorResult, unhandledExceptions); @@ -1547,10 +1539,9 @@ public static HighlightInfo checkMustBeBoolean(@Nonnull PsiExpression expr, PsiT } if (!TypeConversionUtil.isBooleanType(type)) { - final HighlightInfo info = createIncompatibleTypeHighlightInfo(PsiType.BOOLEAN, type, expr.getTextRange(), 0); - if (expr instanceof PsiMethodCallExpression) { - final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)expr; - final PsiMethod method = methodCall.resolveMethod(); + HighlightInfo info = createIncompatibleTypeHighlightInfo(PsiType.BOOLEAN, type, expr.getTextRange(), 0); + if (expr instanceof PsiMethodCallExpression methodCall) { + PsiMethod method = methodCall.resolveMethod(); if (method != null && PsiType.VOID.equals(method.getReturnType())) { QuickFixAction.registerQuickFixAction( info, @@ -1572,15 +1563,15 @@ else if (expr instanceof PsiAssignmentExpression && ((PsiAssignmentExpression)ex @Nonnull - public static Set collectUnhandledExceptions(@Nonnull final PsiTryStatement statement) { - final Set thrownTypes = new HashSet<>(); + public static Set collectUnhandledExceptions(@Nonnull PsiTryStatement statement) { + Set thrownTypes = new HashSet<>(); - final PsiCodeBlock tryBlock = statement.getTryBlock(); + PsiCodeBlock tryBlock = statement.getTryBlock(); if (tryBlock != null) { thrownTypes.addAll(ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock)); } - final PsiResourceList resources = statement.getResourceList(); + PsiResourceList resources = statement.getResourceList(); if (resources != null) { thrownTypes.addAll(ExceptionUtil.collectUnhandledExceptions(resources, resources)); } @@ -1589,18 +1580,16 @@ public static Set collectUnhandledExceptions(@Nonnull final PsiTry } @Nonnull - public static List checkExceptionThrownInTry( - @Nonnull final PsiParameter parameter, - @Nonnull final Set thrownTypes - ) { - final PsiElement declarationScope = parameter.getDeclarationScope(); + @RequiredReadAction + public static List checkExceptionThrownInTry(@Nonnull PsiParameter parameter, @Nonnull Set thrownTypes) { + PsiElement declarationScope = parameter.getDeclarationScope(); if (!(declarationScope instanceof PsiCatchSection)) { return Collections.emptyList(); } - final PsiType caughtType = parameter.getType(); - if (caughtType instanceof PsiClassType) { - HighlightInfo info = checkSimpleCatchParameter(parameter, thrownTypes, (PsiClassType)caughtType); + PsiType caughtType = parameter.getType(); + if (caughtType instanceof PsiClassType classType) { + HighlightInfo info = checkSimpleCatchParameter(parameter, thrownTypes, classType); return info == null ? Collections.emptyList() : Collections.singletonList(info); } if (caughtType instanceof PsiDisjunctionType) { @@ -1611,10 +1600,11 @@ public static List checkExceptionThrownInTry( } @Nullable + @RequiredReadAction private static HighlightInfo checkSimpleCatchParameter( - @Nonnull final PsiParameter parameter, - @Nonnull final Collection thrownTypes, - @Nonnull final PsiClassType caughtType + @Nonnull PsiParameter parameter, + @Nonnull Collection thrownTypes, + @Nonnull PsiClassType caughtType ) { if (ExceptionUtil.isUncheckedExceptionOrSuperclass(caughtType)) { return null; @@ -1626,23 +1616,24 @@ private static HighlightInfo checkSimpleCatchParameter( } } - final String description = JavaErrorBundle.message("exception.never.thrown.try", JavaHighlightUtil.formatType(caughtType)); - final HighlightInfo errorResult = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parameter).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createDeleteCatchFix(parameter)); - return errorResult; + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(parameter) + .descriptionAndTooltip(JavaErrorLocalize.exceptionNeverThrownTry(JavaHighlightUtil.formatType(caughtType))) + .registerFix(QuickFixFactory.getInstance().createDeleteCatchFix(parameter), null, null, null, null) + .create(); } @Nonnull + @RequiredReadAction private static List checkMultiCatchParameter( - @Nonnull final PsiParameter parameter, - @Nonnull final Collection thrownTypes + @Nonnull PsiParameter parameter, + @Nonnull Collection thrownTypes ) { - final List typeElements = PsiUtil.getParameterTypeElements(parameter); - final List highlights = new ArrayList<>(typeElements.size()); + List typeElements = PsiUtil.getParameterTypeElements(parameter); + List highlights = new ArrayList<>(typeElements.size()); - for (final PsiTypeElement typeElement : typeElements) { - final PsiType catchType = typeElement.getType(); + for (PsiTypeElement typeElement : typeElements) { + PsiType catchType = typeElement.getType(); if (catchType instanceof PsiClassType && ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)catchType)) { continue; } @@ -1655,10 +1646,11 @@ private static List checkMultiCatchParameter( } } if (!used) { - final String description = JavaErrorBundle.message("exception.never.thrown.try", JavaHighlightUtil.formatType(catchType)); - final HighlightInfo highlight = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(highlight, QuickFixFactory.getInstance().createDeleteMultiCatchFix(typeElement)); + HighlightInfo highlight = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeElement) + .descriptionAndTooltip(JavaErrorLocalize.exceptionNeverThrownTry(JavaHighlightUtil.formatType(catchType))) + .registerFix(QuickFixFactory.getInstance().createDeleteMultiCatchFix(typeElement), null, null, null, null) + .create(); highlights.add(highlight); } } @@ -1673,29 +1665,29 @@ public static Collection checkWithImprovedCatchAnalysis( @Nonnull Collection thrownInTryStatement, @Nonnull PsiFile containingFile ) { - final PsiElement scope = parameter.getDeclarationScope(); + PsiElement scope = parameter.getDeclarationScope(); if (!(scope instanceof PsiCatchSection)) { return Collections.emptyList(); } - final PsiCatchSection catchSection = (PsiCatchSection)scope; - final PsiCatchSection[] allCatchSections = catchSection.getTryStatement().getCatchSections(); - final int idx = ArrayUtil.find(allCatchSections, catchSection); + PsiCatchSection catchSection = (PsiCatchSection)scope; + PsiCatchSection[] allCatchSections = catchSection.getTryStatement().getCatchSections(); + int idx = ArrayUtil.find(allCatchSections, catchSection); if (idx <= 0) { return Collections.emptyList(); } - final Collection thrownTypes = new HashSet<>(thrownInTryStatement); - final PsiManager manager = containingFile.getManager(); - final GlobalSearchScope parameterResolveScope = parameter.getResolveScope(); + Collection thrownTypes = new HashSet<>(thrownInTryStatement); + PsiManager manager = containingFile.getManager(); + GlobalSearchScope parameterResolveScope = parameter.getResolveScope(); thrownTypes.add(PsiType.getJavaLangError(manager, parameterResolveScope)); thrownTypes.add(PsiType.getJavaLangRuntimeException(manager, parameterResolveScope)); - final Collection result = ContainerUtil.newArrayList(); + Collection result = ContainerUtil.newArrayList(); - final List parameterTypeElements = PsiUtil.getParameterTypeElements(parameter); - final boolean isMultiCatch = parameterTypeElements.size() > 1; + List parameterTypeElements = PsiUtil.getParameterTypeElements(parameter); + boolean isMultiCatch = parameterTypeElements.size() > 1; for (PsiTypeElement catchTypeElement : parameterTypeElements) { - final PsiType catchType = catchTypeElement.getType(); + PsiType catchType = catchTypeElement.getType(); if (ExceptionUtil.isGeneralExceptionType(catchType)) { continue; } @@ -1705,16 +1697,16 @@ public static Collection checkWithImprovedCatchAnalysis( if (caught.isEmpty()) { continue; } - final Collection caughtCopy = new HashSet<>(caught); + Collection caughtCopy = new HashSet<>(caught); // exclude all which are caught by previous catch sections for (int i = 0; i < idx; i++) { - final PsiParameter prevCatchParameter = allCatchSections[i].getParameter(); + PsiParameter prevCatchParameter = allCatchSections[i].getParameter(); if (prevCatchParameter == null) { continue; } for (PsiTypeElement prevCatchTypeElement : PsiUtil.getParameterTypeElements(prevCatchParameter)) { - final PsiType prevCatchType = prevCatchTypeElement.getType(); + PsiType prevCatchType = prevCatchTypeElement.getType(); caught.removeIf(prevCatchType::isAssignableFrom); if (caught.isEmpty()) { break; @@ -1724,9 +1716,11 @@ public static Collection checkWithImprovedCatchAnalysis( // check & warn if (caught.isEmpty()) { - final String message = JavaErrorBundle.message("exception.already.caught.warn", formatTypes(caughtCopy), caughtCopy.size()); - final HighlightInfo highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING).range(catchSection).descriptionAndTooltip(message).create(); + String message = JavaErrorBundle.message("exception.already.caught.warn", formatTypes(caughtCopy), caughtCopy.size()); + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING) + .range(catchSection) + .descriptionAndTooltip(message) + .create(); if (isMultiCatch) { QuickFixAction.registerQuickFixAction( highlightInfo, @@ -1743,13 +1737,12 @@ public static Collection checkWithImprovedCatchAnalysis( return result; } - @Nullable public static HighlightInfo checkNotAStatement(@Nonnull PsiStatement statement) { if (!PsiUtil.isStatement(statement) && !PsiUtilCore.hasErrorElementChild(statement)) { boolean isDeclarationNotAllowed = false; if (statement instanceof PsiDeclarationStatement) { - final PsiElement parent = statement.getParent(); + PsiElement parent = statement.getParent(); isDeclarationNotAllowed = parent instanceof PsiIfStatement || parent instanceof PsiLoopStatement; } @@ -1983,10 +1976,10 @@ public static HighlightInfo checkThisOrSuperExpressionInIllegalContext( @Nonnull LanguageLevel languageLevel ) { if (expr instanceof PsiSuperExpression) { - final PsiElement parent = expr.getParent(); + PsiElement parent = expr.getParent(); if (!(parent instanceof PsiReferenceExpression)) { // like in 'Object o = super;' - final int o = expr.getTextRange().getEndOffset(); + int o = expr.getTextRange().getEndOffset(); String description = JavaErrorBundle.message("dot.expected.after.super.or.this"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(o, o + 1).descriptionAndTooltip(description).create(); } @@ -2017,13 +2010,15 @@ public static HighlightInfo checkThisOrSuperExpressionInIllegalContext( } if (expr instanceof PsiSuperExpression) { - final PsiElement resolved = ((PsiReferenceExpression)expr.getParent()).resolve(); + PsiElement resolved = ((PsiReferenceExpression)expr.getParent()).resolve(); //15.11.2 //The form T.super.Identifier refers to the field named Identifier of the lexically enclosing instance corresponding to T, //but with that instance viewed as an instance of the superclass of T. if (resolved instanceof PsiField) { - String description = JavaErrorBundle.message("is.not.an.enclosing.class", formatClass(aClass)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expr).descriptionAndTooltip(description).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expr) + .descriptionAndTooltip(JavaErrorLocalize.isNotAnEnclosingClass(formatClass(aClass))) + .create(); } } } @@ -2033,10 +2028,10 @@ public static HighlightInfo checkThisOrSuperExpressionInIllegalContext( //If TypeName denotes an interface, I, then let T be the type declaration immediately enclosing the method reference expression. //It is a compile-time error if I is not a direct superinterface of T, //or if there exists some other direct superclass or direct superinterface of T, J, such that J is a subtype of I. - final PsiClass classT = PsiTreeUtil.getParentOfType(expr, PsiClass.class); + PsiClass classT = PsiTreeUtil.getParentOfType(expr, PsiClass.class); if (classT != null) { - final PsiElement parent = expr.getParent(); - final PsiElement resolved = parent instanceof PsiReferenceExpression ? ((PsiReferenceExpression)parent).resolve() : null; + PsiElement parent = expr.getParent(); + PsiElement resolved = parent instanceof PsiReferenceExpression ? ((PsiReferenceExpression)parent).resolve() : null; PsiClass containingClass = ObjectUtil.notNull(resolved instanceof PsiMethod ? ((PsiMethod)resolved).getContainingClass() : null, aClass); @@ -2073,7 +2068,7 @@ else if (resolved instanceof PsiMethod } if (expr instanceof PsiThisExpression) { - final PsiMethod psiMethod = PsiTreeUtil.getParentOfType(expr, PsiMethod.class); + PsiMethod psiMethod = PsiTreeUtil.getParentOfType(expr, PsiMethod.class); if (psiMethod == null || psiMethod.getContainingClass() != aClass && !isInsideDefaultMethod(psiMethod, aClass)) { if (aClass.isInterface()) { return thisNotFoundInInterfaceInfo(expr); @@ -2084,7 +2079,7 @@ else if (resolved instanceof PsiMethod expr, true )) { - final PsiClass parentClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class, true); + PsiClass parentClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class, true); if (parentClass != null && parentClass.isInterface()) { return thisNotFoundInInterfaceInfo(expr); } @@ -2100,7 +2095,7 @@ public static HighlightInfo checkUnqualifiedSuperInDefaultMethod( PsiExpression qualifier ) { if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && qualifier instanceof PsiSuperExpression) { - final PsiMethod method = PsiTreeUtil.getParentOfType(expr, PsiMethod.class); + PsiMethod method = PsiTreeUtil.getParentOfType(expr, PsiMethod.class); if (method != null && method.hasModifierProperty(PsiModifier.DEFAULT) && ((PsiSuperExpression)qualifier).getQualifier() == null) { String description = JavaErrorBundle.message("unqualified.super.disallowed"); HighlightInfo info = @@ -2135,20 +2130,20 @@ private static boolean resolvesToImmediateSuperInterface( if (!(expr instanceof PsiSuperExpression) || qualifier == null || !languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { return false; } - final PsiType superType = expr.getType(); + PsiType superType = expr.getType(); if (!(superType instanceof PsiClassType)) { return false; } - final PsiClass superClass = ((PsiClassType)superType).resolve(); + PsiClass superClass = ((PsiClassType)superType).resolve(); return superClass != null && aClass.equals(superClass) && PsiUtil.getEnclosingStaticElement(expr, PsiTreeUtil.getParentOfType(expr, PsiClass.class)) == null; } @Nonnull - public static String buildProblemWithStaticDescription(@Nonnull PsiElement refElement) { + public static LocalizeValue buildProblemWithStaticDescription(@Nonnull PsiElement refElement) { String type = FindUsagesProvider.forLanguage(JavaLanguage.INSTANCE).getType(refElement); String name = HighlightMessageUtil.getSymbolName(refElement, PsiSubstitutor.EMPTY); - return JavaErrorBundle.message("non.static.symbol.referenced.from.static.context", type, name); + return JavaErrorLocalize.nonStaticSymbolReferencedFromStaticContext(type, name); } public static void registerStaticProblemQuickFixAction( @@ -2184,15 +2179,16 @@ public static void registerStaticProblemQuickFixAction( } } + @RequiredReadAction private static boolean isInstanceReference(@Nonnull PsiJavaCodeReferenceElement place) { PsiElement qualifier = place.getQualifier(); if (qualifier == null) { return true; } - if (!(qualifier instanceof PsiJavaCodeReferenceElement)) { + if (!(qualifier instanceof PsiJavaCodeReferenceElement codeReferenceElement)) { return false; } - PsiElement q = ((PsiReference)qualifier).resolve(); + PsiElement q = codeReferenceElement.resolve(); if (q instanceof PsiClass) { return false; } @@ -2204,15 +2200,15 @@ private static boolean isInstanceReference(@Nonnull PsiJavaCodeReferenceElement } @Nonnull - public static String buildProblemWithAccessDescription(@Nonnull final PsiElement reference, @Nonnull final JavaResolveResult result) { + public static LocalizeValue buildProblemWithAccessDescription(@Nonnull PsiElement reference, @Nonnull JavaResolveResult result) { return buildProblemWithAccessDescription(reference, result, ObjectUtil.notNull(result.getElement())); } @Nonnull - private static String buildProblemWithAccessDescription( - @Nonnull final PsiElement reference, - @Nonnull final JavaResolveResult result, - @Nonnull final PsiElement resolved + private static LocalizeValue buildProblemWithAccessDescription( + @Nonnull PsiElement reference, + @Nonnull JavaResolveResult result, + @Nonnull PsiElement resolved ) { assert resolved instanceof PsiModifierListOwner : resolved; PsiModifierListOwner refElement = (PsiModifierListOwner)resolved; @@ -2220,11 +2216,11 @@ private static String buildProblemWithAccessDescription( if (refElement.hasModifierProperty(PsiModifier.PRIVATE)) { String containerName = getContainerName(refElement, result.getSubstitutor()); - return JavaErrorBundle.message("private.symbol", symbolName, containerName); + return JavaErrorLocalize.privateSymbol(symbolName, containerName); } else if (refElement.hasModifierProperty(PsiModifier.PROTECTED)) { String containerName = getContainerName(refElement, result.getSubstitutor()); - return JavaErrorBundle.message("protected.symbol", symbolName, containerName); + return JavaErrorLocalize.protectedSymbol(symbolName, containerName); } else { PsiClass packageLocalClass = getPackageLocalClassInTheMiddle(reference); @@ -2234,18 +2230,18 @@ else if (refElement.hasModifierProperty(PsiModifier.PROTECTED)) { } if (refElement.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) || packageLocalClass != null) { String containerName = getContainerName(refElement, result.getSubstitutor()); - return JavaErrorBundle.message("package.local.symbol", symbolName, containerName); + return JavaErrorLocalize.packageLocalSymbol(symbolName, containerName); } else { String containerName = getContainerName(refElement, result.getSubstitutor()); - return JavaErrorBundle.message("visibility.access.problem", symbolName, containerName); + return JavaErrorLocalize.visibilityAccessProblem(symbolName, containerName); } } } private static PsiElement getContainer(PsiModifierListOwner refElement) { for (ContainerProvider provider : ContainerProvider.EP_NAME.getExtensions()) { - final PsiElement container = provider.getContainer(refElement); + PsiElement container = provider.getContainer(refElement); if (container != null) { return container; } @@ -2259,19 +2255,17 @@ private static String getContainerName(PsiModifierListOwner refElement, final Ps } @Nullable + @RequiredReadAction public static HighlightInfo checkValidArrayAccessExpression(@Nonnull PsiArrayAccessExpression arrayAccessExpression) { final PsiExpression arrayExpression = arrayAccessExpression.getArrayExpression(); final PsiType arrayExpressionType = arrayExpression.getType(); if (arrayExpressionType != null && !(arrayExpressionType instanceof PsiArrayType)) { - final String description = JavaErrorBundle.message("array.type.expected", JavaHighlightUtil.formatType(arrayExpressionType)); - final HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(arrayExpression).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction( - info, - QuickFixFactory.getInstance().createReplaceWithListAccessFix(arrayAccessExpression) - ); - return info; + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(arrayExpression) + .descriptionAndTooltip(JavaErrorLocalize.arrayTypeExpected(JavaHighlightUtil.formatType(arrayExpressionType))) + .registerFix(QuickFixFactory.getInstance().createReplaceWithListAccessFix(arrayAccessExpression), null, null, null, null) + .create(); } final PsiExpression indexExpression = arrayAccessExpression.getIndexExpression(); @@ -2307,6 +2301,7 @@ public static HighlightInfo checkTryResourceIsAutoCloseable(@Nonnull PsiResource } @Nullable + @RequiredReadAction public static HighlightInfo checkResourceVariableIsFinal(@Nonnull PsiResourceExpression resource) { PsiExpression expression = resource.getExpression(); @@ -2314,15 +2309,13 @@ public static HighlightInfo checkResourceVariableIsFinal(@Nonnull PsiResourceExp return null; } - if (expression instanceof PsiReferenceExpression) { - PsiElement target = ((PsiReferenceExpression)expression).resolve(); + if (expression instanceof PsiReferenceExpression refExpr) { + PsiElement target = refExpr.resolve(); if (target == null) { return null; } - if (target instanceof PsiVariable) { - PsiVariable variable = (PsiVariable)target; - + if (target instanceof PsiVariable variable) { PsiModifierList modifierList = variable.getModifierList(); if (modifierList != null && modifierList.hasModifierProperty(PsiModifier.FINAL)) { return null; @@ -2357,7 +2350,7 @@ public static Collection checkArrayInitializer(final PsiExpressio boolean arrayTypeFixChecked = false; VariableArrayTypeFix fix = null; - final Collection result = ContainerUtil.newArrayList(); + final Collection result = new ArrayList<>(); final PsiExpression[] initializers = arrayInitializer.getInitializers(); for (PsiExpression expression : initializers) { final HighlightInfo info = checkArrayInitializerCompatibleTypes(expression, componentType); @@ -2378,6 +2371,7 @@ public static Collection checkArrayInitializer(final PsiExpressio } @Nullable + @RequiredReadAction private static HighlightInfo checkArrayInitializerCompatibleTypes(@Nonnull PsiExpression initializer, final PsiType componentType) { PsiType initializerType = initializer.getType(); if (initializerType == null) { @@ -2389,6 +2383,7 @@ private static HighlightInfo checkArrayInitializerCompatibleTypes(@Nonnull PsiEx } @Nullable + @RequiredReadAction public static HighlightInfo checkExpressionRequired( @Nonnull PsiReferenceExpression expression, @Nonnull JavaResolveResult resultForIncompleteCode @@ -2408,9 +2403,10 @@ public static HighlightInfo checkExpressionRequired( return null; } - String description = JavaErrorBundle.message("expression.expected"); - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description).create(); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.expressionExpected()) + .create(); if (info != null) { UnresolvedReferenceQuickFixProvider.registerReferenceFixes(expression, QuickFixActionRegistrar.create(info)); } @@ -2418,11 +2414,12 @@ public static HighlightInfo checkExpressionRequired( } @Nullable + @RequiredReadAction public static HighlightInfo checkArrayInitializerApplicable(@Nonnull PsiArrayInitializerExpression expression) { - /* - JLS 10.6 Array Initializers - An array initializer may be specified in a declaration, or as part of an array creation expression - */ + /* + * JLS 10.6 Array Initializers + * An array initializer may be specified in a declaration, or as part of an array creation expression + */ PsiElement parent = expression.getParent(); if (parent instanceof PsiVariable) { PsiVariable variable = (PsiVariable)parent; @@ -2434,26 +2431,32 @@ else if (parent instanceof PsiNewExpression || parent instanceof PsiArrayInitial return null; } - String description = JavaErrorBundle.message("array.initializer.not.allowed"); - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description).create(); + String description = JavaErrorLocalize.arrayInitializerNotAllowed().get(); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(description) + .create(); QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createAddNewArrayExpressionFix(expression)); return info; } @Nullable + @RequiredReadAction public static HighlightInfo checkCaseStatement(@Nonnull PsiSwitchLabelStatementBase statement) { PsiSwitchBlock switchBlock = statement.getEnclosingSwitchBlock(); if (switchBlock == null) { - String description = JavaErrorBundle.message("case.statement.outside.switch"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(description).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(statement) + .descriptionAndTooltip(JavaErrorLocalize.caseStatementOutsideSwitch()) + .create(); } return null; } @Nonnull + @RequiredReadAction public static Collection checkSwitchLabelValues(@Nonnull PsiSwitchBlock switchBlock) { PsiCodeBlock body = switchBlock.getBody(); if (body == null) { @@ -2491,29 +2494,29 @@ public static Collection checkSwitchLabelValues(@Nonnull PsiSwitc } Object value = null; - if (expr instanceof PsiReferenceExpression) { - PsiElement element = ((PsiReferenceExpression)expr).resolve(); - if (element instanceof PsiEnumConstant) { - value = ((PsiEnumConstant)element).getName(); - if (((PsiReferenceExpression)expr).getQualifier() != null) { - String message = JavaErrorBundle.message("qualified.enum.constant.in.switch"); - results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(expr) - .descriptionAndTooltip(message) - .create()); - continue; - } + if (expr instanceof PsiReferenceExpression refExpr + && refExpr.resolve() instanceof PsiEnumConstant enumConst) { + value = enumConst.getName(); + if (refExpr.getQualifier() != null) { + results.add( + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(refExpr) + .descriptionAndTooltip(JavaErrorLocalize.qualifiedEnumConstantInSwitch()) + .create() + ); + continue; } } if (value == null) { value = ConstantExpressionUtil.computeCastTo(expr, selectorType); } if (value == null) { - String description = JavaErrorBundle.message("constant.expression.required"); - results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(expr) - .descriptionAndTooltip(description) - .create()); + results.add( + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expr) + .descriptionAndTooltip(JavaErrorLocalize.constantExpressionRequired()) + .create() + ); continue; } @@ -2526,15 +2529,16 @@ public static Collection checkSwitchLabelValues(@Nonnull PsiSwitc for (Map.Entry> entry : values.entrySet()) { if (entry.getValue().size() > 1) { Object value = entry.getKey(); - String description = - value == defaultValue - ? JavaErrorBundle.message("duplicate.default.switch.label") - : JavaErrorBundle.message("duplicate.switch.label", value); + LocalizeValue description = value == defaultValue + ? JavaErrorLocalize.duplicateDefaultSwitchLabel() + : JavaErrorLocalize.duplicateSwitchLabel(value); for (PsiElement element : entry.getValue()) { - results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(element) - .descriptionAndTooltip(description) - .create()); + results.add( + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(element) + .descriptionAndTooltip(description) + .create() + ); } } } @@ -2543,8 +2547,8 @@ public static Collection checkSwitchLabelValues(@Nonnull PsiSwitc Set missingConstants = new HashSet<>(); boolean exhaustive = hasDefaultCase; if (!exhaustive) { - if (!values.isEmpty() && selectorType instanceof PsiClassType) { - PsiClass type = ((PsiClassType)selectorType).resolve(); + if (!values.isEmpty() && selectorType instanceof PsiClassType classType) { + PsiClass type = classType.resolve(); if (type != null && type.isEnum()) { for (PsiField field : type.getFields()) { if (field instanceof PsiEnumConstant && !values.containsKey(field.getName())) { @@ -2557,12 +2561,16 @@ public static Collection checkSwitchLabelValues(@Nonnull PsiSwitc } if (!exhaustive) { PsiElement range = ObjectUtil.notNull(selectorExpression, switchBlock); - String message = JavaErrorBundle.message(values.isEmpty() ? "switch.expr.empty" : "switch.expr.incomplete"); + String message = values.isEmpty() + ? JavaErrorBundle.message("switch.expr.empty") + : JavaErrorBundle.message("switch.expr.incomplete"); HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip(message).create(); if (!missingConstants.isEmpty()) { - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance() - .createAddMissingEnumBranchesFix(switchBlock, missingConstants)); + QuickFixAction.registerQuickFixAction( + info, + QuickFixFactory.getInstance().createAddMissingEnumBranchesFix(switchBlock, missingConstants) + ); } QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createAddSwitchDefaultFix(switchBlock, null)); results.add(info); @@ -2577,6 +2585,7 @@ public static Collection checkSwitchLabelValues(@Nonnull PsiSwitc * see JLS 8.3.2.3 */ @Nullable + @RequiredReadAction public static HighlightInfo checkIllegalForwardReferenceToField( @Nonnull PsiReferenceExpression expression, @Nonnull PsiField referencedField @@ -2585,10 +2594,16 @@ public static HighlightInfo checkIllegalForwardReferenceToField( if (isIllegalForwardReference == null) { return null; } - String description = JavaErrorBundle.message(isIllegalForwardReference ? "illegal.forward.reference" : "illegal.self.reference"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description).create(); + String description = isIllegalForwardReference + ? JavaErrorBundle.message("illegal.forward.reference") + : JavaErrorBundle.message("illegal.self.reference"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(description) + .create(); } + @RequiredReadAction public static Boolean isIllegalForwardReferenceToField( @Nonnull PsiReferenceExpression expression, @Nonnull PsiField referencedField, @@ -2614,10 +2629,10 @@ public static Boolean isIllegalForwardReferenceToField( return null; } // instance initializers may access static fields - boolean isStaticClassInitializer = classInitializer != null && classInitializer.hasModifierProperty(PsiModifier.STATIC); - boolean isStaticInitField = initField != null && initField.hasModifierProperty(PsiModifier.STATIC); + boolean isStaticClassInitializer = classInitializer != null && classInitializer.isStatic(); + boolean isStaticInitField = initField != null && initField.isStatic(); boolean inStaticContext = isStaticInitField || isStaticClassInitializer; - if (!inStaticContext && referencedField.hasModifierProperty(PsiModifier.STATIC)) { + if (!inStaticContext && referencedField.isStatic()) { return null; } if (PsiUtil.isOnAssignmentLeftHand(expression) && !PsiUtil.isAccessedForReading(expression)) { @@ -2636,12 +2651,11 @@ public static Boolean isIllegalForwardReferenceToField( public static PsiField findEnclosingFieldInitializer(@Nullable PsiElement element) { while (element != null) { PsiElement parent = element.getParent(); - if (parent instanceof PsiField) { - PsiField field = (PsiField)parent; + if (parent instanceof PsiField field) { if (element == field.getInitializer()) { return field; } - if (field instanceof PsiEnumConstant && element == ((PsiEnumConstant)field).getArgumentList()) { + if (field instanceof PsiEnumConstant enumConst && element == enumConst.getArgumentList()) { return field; } } @@ -2656,8 +2670,8 @@ public static PsiField findEnclosingFieldInitializer(@Nullable PsiElement elemen @Nullable private static PsiClassInitializer findParentClassInitializer(@Nullable PsiElement element) { while (element != null) { - if (element instanceof PsiClassInitializer) { - return (PsiClassInitializer)element; + if (element instanceof PsiClassInitializer classInitializer) { + return classInitializer; } if (element instanceof PsiClass || element instanceof PsiMethod) { return null; @@ -2667,8 +2681,8 @@ private static PsiClassInitializer findParentClassInitializer(@Nullable PsiEleme return null; } - @Nullable + @RequiredReadAction public static HighlightInfo checkIllegalType(@Nullable PsiTypeElement typeElement) { if (typeElement == null || typeElement.getParent() instanceof PsiTypeElement) { return null; @@ -2684,9 +2698,10 @@ public static HighlightInfo checkIllegalType(@Nullable PsiTypeElement typeElemen PsiClass aClass = PsiUtil.resolveClassInType(componentType); if (aClass == null) { String canonicalText = type.getCanonicalText(); - String description = JavaErrorBundle.message("unknown.class", canonicalText); - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create(); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeElement) + .descriptionAndTooltip(JavaErrorLocalize.unknownClass(canonicalText)) + .create(); PsiJavaCodeReferenceElement referenceElement = typeElement.getInnermostComponentReferenceElement(); if (referenceElement != null && info != null) { @@ -2700,6 +2715,7 @@ public static HighlightInfo checkIllegalType(@Nullable PsiTypeElement typeElemen } @Nullable + @RequiredReadAction public static HighlightInfo checkIllegalVoidType(@Nonnull PsiKeyword type) { if (!PsiKeyword.VOID.equals(type.getText())) { return null; @@ -2721,8 +2737,8 @@ public static HighlightInfo checkIllegalVoidType(@Nonnull PsiKeyword type) { return null; } } - else if (typeOwner instanceof PsiClassObjectAccessExpression) { - if (TypeConversionUtil.isVoidType(((PsiClassObjectAccessExpression)typeOwner).getOperand().getType())) { + else if (typeOwner instanceof PsiClassObjectAccessExpression classObjectAccessExpression) { + if (TypeConversionUtil.isVoidType(classObjectAccessExpression.getOperand().getType())) { return null; } } @@ -2733,35 +2749,37 @@ else if (typeOwner instanceof JavaCodeFragment) { } } - String description = JavaErrorBundle.message("illegal.type.void"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(type).descriptionAndTooltip(description).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(type) + .descriptionAndTooltip(JavaErrorLocalize.illegalTypeVoid()) + .create(); } @Nullable + @RequiredReadAction public static HighlightInfo checkMemberReferencedBeforeConstructorCalled( @Nonnull PsiElement expression, PsiElement resolved, @Nonnull PsiFile containingFile ) { PsiClass referencedClass; - @NonNls String resolvedName; + String resolvedName; PsiType type; - if (expression instanceof PsiJavaCodeReferenceElement) { + if (expression instanceof PsiJavaCodeReferenceElement javaCodeRef) { // redirected ctr - if (PsiKeyword.THIS.equals(((PsiJavaCodeReferenceElement)expression).getReferenceName()) && resolved instanceof PsiMethod && ((PsiMethod)resolved) - .isConstructor()) { + if (PsiKeyword.THIS.equals(javaCodeRef.getReferenceName()) && resolved instanceof PsiMethod method && method.isConstructor()) { return null; } - PsiElement qualifier = ((PsiJavaCodeReferenceElement)expression).getQualifier(); - type = qualifier instanceof PsiExpression ? ((PsiExpression)qualifier).getType() : null; + PsiElement qualifier = javaCodeRef.getQualifier(); + type = qualifier instanceof PsiExpression qExpr ? qExpr.getType() : null; referencedClass = PsiUtil.resolveClassInType(type); - boolean isSuperCall = RefactoringChangeUtil.isSuperMethodCall(expression.getParent()); + boolean isSuperCall = RefactoringChangeUtil.isSuperMethodCall(javaCodeRef.getParent()); if (resolved == null && isSuperCall) { - if (qualifier instanceof PsiReferenceExpression) { - resolved = ((PsiReferenceExpression)qualifier).resolve(); + if (qualifier instanceof PsiReferenceExpression qRefExpr) { + resolved = qRefExpr.resolve(); expression = qualifier; - type = ((PsiReferenceExpression)qualifier).getType(); + type = qRefExpr.getType(); referencedClass = PsiUtil.resolveClassInType(type); } else if (qualifier == null) { @@ -2770,13 +2788,12 @@ else if (qualifier == null) { referencedClass = ((PsiMethod)resolved).getContainingClass(); } } - else if (qualifier instanceof PsiThisExpression) { - referencedClass = PsiUtil.resolveClassInType(((PsiThisExpression)qualifier).getType()); + else if (qualifier instanceof PsiThisExpression thisExpr) { + referencedClass = PsiUtil.resolveClassInType(thisExpr.getType()); } } - if (resolved instanceof PsiField) { - PsiField referencedField = (PsiField)resolved; - if (referencedField.hasModifierProperty(PsiModifier.STATIC)) { + if (resolved instanceof PsiField referencedField) { + if (referencedField.isStatic()) { return null; } resolvedName = PsiFormatUtil.formatVariable( @@ -2786,9 +2803,8 @@ else if (qualifier instanceof PsiThisExpression) { ); referencedClass = referencedField.getContainingClass(); } - else if (resolved instanceof PsiMethod) { - PsiMethod method = (PsiMethod)resolved; - if (method.hasModifierProperty(PsiModifier.STATIC)) { + else if (resolved instanceof PsiMethod method) { + if (method.isStatic()) { return null; } PsiElement nameElement = @@ -2800,11 +2816,8 @@ else if (resolved instanceof PsiMethod) { } if (qualifier == null) { PsiClass superClass = referencedClass.getSuperClass(); - if (superClass != null && PsiUtil.isInnerClass(superClass) && InheritanceUtil.isInheritorOrSelf( - referencedClass, - superClass.getContainingClass(), - true - )) { + if (superClass != null && PsiUtil.isInnerClass(superClass) + && InheritanceUtil.isInheritorOrSelf(referencedClass, superClass.getContainingClass(), true)) { // by default super() is considered this. - qualified resolvedName = PsiKeyword.THIS; } @@ -2831,9 +2844,8 @@ else if (PsiKeyword.THIS.equals(name)) { } } } - else if (resolved instanceof PsiClass) { - PsiClass aClass = (PsiClass)resolved; - if (aClass.hasModifierProperty(PsiModifier.STATIC)) { + else if (resolved instanceof PsiClass aClass) { + if (aClass.isStatic()) { return null; } referencedClass = aClass.getContainingClass(); @@ -2868,6 +2880,7 @@ else if (expression instanceof PsiThisExpression) { } @Nullable + @RequiredReadAction private static HighlightInfo checkReferenceToOurInstanceInsideThisOrSuper( @Nonnull final PsiElement expression, @Nonnull PsiClass referencedClass, @@ -2919,13 +2932,13 @@ private static HighlightInfo checkReferenceToOurInstanceInsideThisOrSuper( } final HighlightInfo highlightInfo = createMemberReferencedError(resolvedName, expression.getTextRange()); - if (expression instanceof PsiReferenceExpression && PsiUtil.isInnerClass(aClass)) { - final String referenceName = ((PsiReferenceExpression)expression).getReferenceName(); + if (expression instanceof PsiReferenceExpression refExpr && PsiUtil.isInnerClass(aClass)) { + final String referenceName = refExpr.getReferenceName(); final PsiClass containingClass = aClass.getContainingClass(); LOG.assertTrue(containingClass != null); final PsiField fieldInContainingClass = containingClass.findFieldByName(referenceName, true); - if (fieldInContainingClass != null && ((PsiReferenceExpression)expression).getQualifierExpression() == null) { - QuickFixAction.registerQuickFixAction(highlightInfo, new QualifyWithThisFix(containingClass, expression)); + if (fieldInContainingClass != null && refExpr.getQualifierExpression() == null) { + QuickFixAction.registerQuickFixAction(highlightInfo, new QualifyWithThisFix(containingClass, refExpr)); } } @@ -2933,11 +2946,10 @@ private static HighlightInfo checkReferenceToOurInstanceInsideThisOrSuper( } if (element instanceof PsiReferenceExpression) { - final PsiElement resolve; - if (element instanceof PsiReferenceExpressionImpl) { - PsiReferenceExpressionImpl referenceExpression = (PsiReferenceExpressionImpl)element; + PsiElement resolve; + if (element instanceof PsiReferenceExpressionImpl refExpr) { JavaResolveResult[] results = JavaResolveUtil.resolveWithContainingFile( - referenceExpression, + refExpr, PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE, true, false, @@ -2948,22 +2960,24 @@ private static HighlightInfo checkReferenceToOurInstanceInsideThisOrSuper( else { resolve = ((PsiReferenceExpression)element).resolve(); } - if (resolve instanceof PsiField && ((PsiField)resolve).hasModifierProperty(PsiModifier.STATIC)) { + if (resolve instanceof PsiField field && field.isStatic()) { return null; } } element = element.getParent(); - if (element instanceof PsiClass && InheritanceUtil.isInheritorOrSelf((PsiClass)element, referencedClass, true)) { + if (element instanceof PsiClass psiClass && InheritanceUtil.isInheritorOrSelf(psiClass, referencedClass, true)) { return null; } } return null; } - private static HighlightInfo createMemberReferencedError(@NonNls final String resolvedName, @Nonnull TextRange textRange) { - String description = JavaErrorBundle.message("member.referenced.before.constructor.called", resolvedName); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + private static HighlightInfo createMemberReferencedError(String resolvedName, @Nonnull TextRange textRange) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(textRange) + .descriptionAndTooltip(JavaErrorLocalize.memberReferencedBeforeConstructorCalled(resolvedName)) + .create(); } @Nullable @@ -3019,39 +3033,42 @@ private static boolean isSuperCalledInConstructor(@Nonnull final PsiMethod const return element != null; } + @RequiredReadAction private static boolean thisOrSuperReference(@Nullable PsiExpression qualifierExpression, PsiClass aClass) { if (qualifierExpression == null) { return true; } PsiJavaCodeReferenceElement qualifier; - if (qualifierExpression instanceof PsiThisExpression) { - qualifier = ((PsiThisExpression)qualifierExpression).getQualifier(); + if (qualifierExpression instanceof PsiThisExpression thisExpr) { + qualifier = thisExpr.getQualifier(); } - else if (qualifierExpression instanceof PsiSuperExpression) { - qualifier = ((PsiSuperExpression)qualifierExpression).getQualifier(); + else if (qualifierExpression instanceof PsiSuperExpression superExpr) { + qualifier = superExpr.getQualifier(); } else { return false; } + //noinspection SimplifiableIfStatement if (qualifier == null) { return true; } - PsiElement resolved = qualifier.resolve(); - return resolved instanceof PsiClass && InheritanceUtil.isInheritorOrSelf(aClass, (PsiClass)resolved, true); + return qualifier.resolve() instanceof PsiClass psiClass && InheritanceUtil.isInheritorOrSelf(aClass, psiClass, true); } - @Nullable + @RequiredReadAction public static HighlightInfo checkLabelWithoutStatement(@Nonnull PsiLabeledStatement statement) { if (statement.getStatement() == null) { - String description = JavaErrorBundle.message("label.without.statement"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(description).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(statement) + .descriptionAndTooltip(JavaErrorLocalize.labelWithoutStatement()) + .create(); } return null; } - @Nullable + @RequiredReadAction public static HighlightInfo checkLabelAlreadyInUse(@Nonnull PsiLabeledStatement statement) { PsiIdentifier identifier = statement.getLabelIdentifier(); String text = identifier.getText(); @@ -3060,12 +3077,11 @@ public static HighlightInfo checkLabelAlreadyInUse(@Nonnull PsiLabeledStatement if (element instanceof PsiMethod || element instanceof PsiClass) { break; } - if (element instanceof PsiLabeledStatement && element != statement - && Comparing.equal(((PsiLabeledStatement)element).getLabelIdentifier().getText(), text)) { - String description = JavaErrorBundle.message("duplicate.label", text); + if (element instanceof PsiLabeledStatement labeledStmt && element != statement + && Objects.equals(labeledStmt.getLabelIdentifier().getText(), text)) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(identifier) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.duplicateLabel(text)) .create(); } element = element.getParent(); @@ -3073,8 +3089,8 @@ public static HighlightInfo checkLabelAlreadyInUse(@Nonnull PsiLabeledStatement return null; } - @Nullable + @RequiredReadAction public static HighlightInfo checkUnclosedComment(@Nonnull PsiComment comment) { if (!(comment instanceof PsiDocComment) && comment.getTokenType() != JavaTokenType.C_STYLE_COMMENT) { return null; @@ -3082,20 +3098,22 @@ public static HighlightInfo checkUnclosedComment(@Nonnull PsiComment comment) { if (!comment.getText().endsWith("*/")) { int start = comment.getTextRange().getEndOffset() - 1; int end = start + 1; - String description = JavaErrorBundle.message("unclosed.comment"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(start, end).descriptionAndTooltip(description).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(start, end) + .descriptionAndTooltip(JavaErrorLocalize.unclosedComment()) + .create(); } return null; } - @Nonnull + @RequiredReadAction public static Collection checkCatchTypeIsDisjoint(@Nonnull final PsiParameter parameter) { if (!(parameter.getType() instanceof PsiDisjunctionType)) { return Collections.emptyList(); } - final Collection result = ContainerUtil.newArrayList(); + final Collection result = new ArrayList<>(); final List typeElements = PsiUtil.getParameterTypeElements(parameter); for (int i = 0, size = typeElements.size(); i < size; i++) { final PsiClass class1 = PsiUtil.resolveClassInClassTypeOnly(typeElements.get(i).getType()); @@ -3110,13 +3128,14 @@ public static Collection checkCatchTypeIsDisjoint(@Nonnull final final boolean sub = InheritanceUtil.isInheritorOrSelf(class1, class2, true); final boolean sup = InheritanceUtil.isInheritorOrSelf(class2, class1, true); if (sub || sup) { - final String name1 = PsiFormatUtil.formatClass(class1, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_FQ_NAME); - final String name2 = PsiFormatUtil.formatClass(class2, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_FQ_NAME); - final String message = JavaErrorBundle.message("exception.must.be.disjoint", sub ? name1 : name2, sub ? name2 : name1); - final PsiTypeElement element = typeElements.get(sub ? i : j); - final HighlightInfo highlight = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(message).create(); - QuickFixAction.registerQuickFixAction(highlight, QuickFixFactory.getInstance().createDeleteMultiCatchFix(element)); + String name1 = PsiFormatUtil.formatClass(class1, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_FQ_NAME); + String name2 = PsiFormatUtil.formatClass(class2, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_FQ_NAME); + PsiTypeElement element = typeElements.get(sub ? i : j); + HighlightInfo highlight = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(element) + .descriptionAndTooltip(JavaErrorLocalize.exceptionMustBeDisjoint(sub ? name1 : name2, sub ? name2 : name1).get()) + .registerFix(QuickFixFactory.getInstance().createDeleteMultiCatchFix(element), null, null, null, null) + .create(); result.add(highlight); break; } @@ -3126,8 +3145,8 @@ public static Collection checkCatchTypeIsDisjoint(@Nonnull final return result; } - @Nonnull + @RequiredReadAction public static Collection checkExceptionAlreadyCaught(@Nonnull final PsiParameter parameter) { final PsiElement scope = parameter.getDeclarationScope(); if (!(scope instanceof PsiCatchSection)) { @@ -3143,7 +3162,7 @@ public static Collection checkExceptionAlreadyCaught(@Nonnull fin final List typeElements = PsiUtil.getParameterTypeElements(parameter); final boolean isInMultiCatch = typeElements.size() > 1; - final Collection result = ContainerUtil.newArrayList(); + final Collection result = new ArrayList<>(); for (PsiTypeElement typeElement : typeElements) { final PsiClass catchClass = PsiUtil.resolveClassInClassTypeOnly(typeElement.getType()); @@ -3155,16 +3174,15 @@ public static Collection checkExceptionAlreadyCaught(@Nonnull fin final PsiCatchSection upperCatchSection = allCatchSections[i]; final PsiType upperCatchType = upperCatchSection.getCatchType(); - final boolean highlight = upperCatchType instanceof PsiDisjunctionType - ? checkMultipleTypes(catchClass, ((PsiDisjunctionType)upperCatchType).getDisjunctions()) + final boolean highlight = upperCatchType instanceof PsiDisjunctionType disjunctionType + ? checkMultipleTypes(catchClass, disjunctionType.getDisjunctions()) : checkSingleType(catchClass, upperCatchType); if (highlight) { final String className = PsiFormatUtil.formatClass(catchClass, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_FQ_NAME); - final String description = JavaErrorBundle.message("exception.already.caught", className); final HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(typeElement) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.exceptionAlreadyCaught(className)) .create(); result.add(highlightInfo); @@ -3200,33 +3218,35 @@ private static boolean checkSingleType(final PsiClass catchClass, final PsiType return upperCatchClass != null && InheritanceUtil.isInheritorOrSelf(catchClass, upperCatchClass, true); } - @Nullable + @RequiredReadAction public static HighlightInfo checkTernaryOperatorConditionIsBoolean(@Nonnull PsiExpression expression, PsiType type) { - if (expression.getParent() instanceof PsiConditionalExpression && ((PsiConditionalExpression)expression.getParent()).getCondition() == expression && !TypeConversionUtil - .isBooleanType(type)) { + if (expression.getParent() instanceof PsiConditionalExpression condExpr && condExpr.getCondition() == expression + && !TypeConversionUtil.isBooleanType(type)) { return createIncompatibleTypeHighlightInfo(PsiType.BOOLEAN, type, expression.getTextRange(), 0); } return null; } - @Nullable + @RequiredReadAction public static HighlightInfo checkStatementPrependedWithCaseInsideSwitch(@Nonnull PsiSwitchStatement statement) { PsiCodeBlock body = statement.getBody(); if (body != null) { PsiElement first = PsiTreeUtil.skipSiblingsForward(body.getLBrace(), PsiWhiteSpace.class, PsiComment.class); if (first != null && !(first instanceof PsiSwitchLabelStatement) && !PsiUtil.isJavaToken(first, JavaTokenType.RBRACE)) { - String description = JavaErrorBundle.message("statement.must.be.prepended.with.case.label"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(first).descriptionAndTooltip(description).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(first) + .descriptionAndTooltip(JavaErrorLocalize.statementMustBePrependedWithCaseLabel()) + .create(); } } return null; } - @Nullable + @RequiredReadAction public static HighlightInfo checkAssertOperatorTypes(@Nonnull PsiExpression expression, @Nullable PsiType type) { if (type == null) { return null; @@ -3238,22 +3258,25 @@ public static HighlightInfo checkAssertOperatorTypes(@Nonnull PsiExpression expr if (expression == assertStatement.getAssertCondition() && !TypeConversionUtil.isBooleanType(type)) { // addTypeCast quickfix is not applicable here since no type can be cast to boolean HighlightInfo highlightInfo = createIncompatibleTypeHighlightInfo(PsiType.BOOLEAN, type, expression.getTextRange(), 0); - if (expression instanceof PsiAssignmentExpression && ((PsiAssignmentExpression)expression).getOperationTokenType() == JavaTokenType.EQ) { + if (expression instanceof PsiAssignmentExpression assignment && assignment.getOperationTokenType() == JavaTokenType.EQ) { QuickFixAction.registerQuickFixAction( highlightInfo, - QuickFixFactory.getInstance().createAssignmentToComparisonFix((PsiAssignmentExpression)expression) + QuickFixFactory.getInstance().createAssignmentToComparisonFix(assignment) ); } return highlightInfo; } if (expression == assertStatement.getAssertDescription() && TypeConversionUtil.isVoidType(type)) { - String description = JavaErrorBundle.message("void.type.is.not.allowed"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.voidTypeIsNotAllowed()) + .create(); } return null; } @Nullable + @RequiredReadAction public static HighlightInfo checkSynchronizedExpressionType( @Nonnull PsiExpression expression, @Nullable PsiType type, @@ -3262,37 +3285,33 @@ public static HighlightInfo checkSynchronizedExpressionType( if (type == null) { return null; } - if (expression.getParent() instanceof PsiSynchronizedStatement) { - PsiSynchronizedStatement synchronizedStatement = (PsiSynchronizedStatement)expression.getParent(); - if (expression == synchronizedStatement.getLockExpression() && (type instanceof PsiPrimitiveType - || TypeConversionUtil.isNullType(type))) { - PsiClassType objectType = PsiType.getJavaLangObject(containingFile.getManager(), expression.getResolveScope()); - return createIncompatibleTypeHighlightInfo(objectType, type, expression.getTextRange(), 0); - } + if (expression.getParent() instanceof PsiSynchronizedStatement syncStmt + && expression == syncStmt.getLockExpression() && (type instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(type))) { + PsiClassType objectType = PsiType.getJavaLangObject(containingFile.getManager(), expression.getResolveScope()); + return createIncompatibleTypeHighlightInfo(objectType, type, expression.getTextRange(), 0); } return null; } - @Nullable + @RequiredReadAction public static HighlightInfo checkConditionalExpressionBranchTypesMatch(@Nonnull final PsiExpression expression, PsiType type) { PsiElement parent = expression.getParent(); - if (!(parent instanceof PsiConditionalExpression)) { + if (!(parent instanceof PsiConditionalExpression conditionalExpr)) { return null; } - PsiConditionalExpression conditionalExpression = (PsiConditionalExpression)parent; // check else branches only - if (conditionalExpression.getElseExpression() != expression) { + if (conditionalExpr.getElseExpression() != expression) { return null; } - final PsiExpression thenExpression = conditionalExpression.getThenExpression(); + final PsiExpression thenExpression = conditionalExpr.getThenExpression(); assert thenExpression != null; PsiType thenType = thenExpression.getType(); if (thenType == null || type == null) { return null; } - if (conditionalExpression.getType() == null) { - if (PsiUtil.isLanguageLevel8OrHigher(conditionalExpression) && PsiPolyExpressionUtil.isPolyExpression(conditionalExpression)) { + if (conditionalExpr.getType() == null) { + if (PsiUtil.isLanguageLevel8OrHigher(conditionalExpr) && PsiPolyExpressionUtil.isPolyExpression(conditionalExpr)) { return null; } // cannot derive type of conditional expression @@ -3313,8 +3332,8 @@ public static HighlightInfo createIncompatibleTypeHighlightInfo( PsiType rType1 = rType; PsiTypeParameter[] lTypeParams = PsiTypeParameter.EMPTY_ARRAY; PsiSubstitutor lTypeSubstitutor = PsiSubstitutor.EMPTY; - if (lType1 instanceof PsiClassType) { - PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)lType1).resolveGenerics(); + if (lType1 instanceof PsiClassType classType) { + PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics(); lTypeSubstitutor = resolveResult.getSubstitutor(); PsiClass psiClass = resolveResult.getElement(); if (psiClass instanceof PsiAnonymousClass) { @@ -3362,26 +3381,22 @@ public static HighlightInfo createIncompatibleTypeHighlightInfo( PsiType rRawType = rType1 instanceof PsiClassType ? ((PsiClassType)rType1).rawType() : rType1; boolean assignable = lRawType == null || rRawType == null || TypeConversionUtil.isAssignable(lRawType, rRawType); - String toolTip = JavaErrorBundle.message( - "incompatible.types.html.tooltip", - redIfNotMatch(lRawType, assignable), + LocalizeValue toolTip = JavaErrorLocalize.incompatibleTypesHtmlTooltip(redIfNotMatch(lRawType, assignable), requiredRow, redIfNotMatch(rRawType, assignable), foundRow ); - String description = - JavaErrorBundle.message("incompatible.types", JavaHighlightUtil.formatType(lType1), JavaHighlightUtil.formatType(rType1)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(textRange) - .description(description) - .escapedToolTip(toolTip) + .description(JavaErrorLocalize.incompatibleTypes(JavaHighlightUtil.formatType(lType1), JavaHighlightUtil.formatType(rType1)).get()) + .escapedToolTip(toolTip.get()) .navigationShift(navigationShift) .create(); } @Nullable + @RequiredReadAction public static HighlightInfo checkSingleImportClassConflict( @Nonnull PsiImportStatement statement, @Nonnull Map> importedClasses, @@ -3391,21 +3406,21 @@ public static HighlightInfo checkSingleImportClassConflict( return null; } PsiElement element = statement.resolve(); - if (element instanceof PsiClass) { - String name = ((PsiClass)element).getName(); + if (element instanceof PsiClass psiClass) { + String name = psiClass.getName(); Pair imported = importedClasses.get(name); PsiClass importedClass = imported == null ? null : imported.getSecond(); if (importedClass != null && !containingFile.getManager().areElementsEquivalent(importedClass, element)) { - String description = JavaErrorBundle.message("single.import.class.conflict", formatClass(importedClass)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(description).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(statement) + .descriptionAndTooltip(JavaErrorLocalize.singleImportClassConflict(formatClass(importedClass)).get()) + .create(); } importedClasses.put(name, Pair.create(null, (PsiClass)element)); } return null; } - - @NonNls private static String redIfNotMatch(PsiType type, boolean matches) { if (matches) { return getFQName(type, false); @@ -3421,8 +3436,8 @@ private static String getFQName(@Nullable PsiType type, boolean longName) { return XmlStringUtil.escapeString(longName ? type.getInternalCanonicalText() : type.getPresentableText()); } - @Nullable + @RequiredReadAction public static HighlightInfo checkMustBeThrowable(@Nullable PsiType type, @Nonnull PsiElement context, boolean addCastIntention) { if (type == null) { return null; @@ -3431,13 +3446,12 @@ public static HighlightInfo checkMustBeThrowable(@Nullable PsiType type, @Nonnul PsiClassType throwable = factory.createTypeByFQClassName("java.lang.Throwable", context.getResolveScope()); if (!TypeConversionUtil.isAssignable(throwable, type)) { HighlightInfo highlightInfo = createIncompatibleTypeHighlightInfo(throwable, type, context.getTextRange(), 0); - if (addCastIntention && TypeConversionUtil.areTypesConvertible(type, throwable)) { - if (context instanceof PsiExpression) { - QuickFixAction.registerQuickFixAction( - highlightInfo, - QuickFixFactory.getInstance().createAddTypeCastFix(throwable, (PsiExpression)context) - ); - } + if (addCastIntention && TypeConversionUtil.areTypesConvertible(type, throwable) + && context instanceof PsiExpression contextErpr) { + QuickFixAction.registerQuickFixAction( + highlightInfo, + QuickFixFactory.getInstance().createAddTypeCastFix(throwable, contextErpr) + ); } final PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(type); @@ -3452,8 +3466,8 @@ public static HighlightInfo checkMustBeThrowable(@Nullable PsiType type, @Nonnul return null; } - @Nullable + @RequiredReadAction private static HighlightInfo checkMustBeThrowable(@Nullable PsiClass aClass, @Nonnull PsiElement context) { if (aClass == null) { return null; @@ -3462,8 +3476,8 @@ private static HighlightInfo checkMustBeThrowable(@Nullable PsiClass aClass, @No return checkMustBeThrowable(type, context, false); } - @Nullable + @RequiredReadAction public static HighlightInfo checkLabelDefined(@Nullable PsiIdentifier labelIdentifier, @Nullable PsiStatement exitedStatement) { if (labelIdentifier == null) { return null; @@ -3473,14 +3487,16 @@ public static HighlightInfo checkLabelDefined(@Nullable PsiIdentifier labelIdent return null; } if (exitedStatement == null) { - String message = JavaErrorBundle.message("unresolved.label", label); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(labelIdentifier).descriptionAndTooltip(message).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(labelIdentifier) + .descriptionAndTooltip(JavaErrorLocalize.unresolvedLabel(label)) + .create(); } return null; } - @Nullable + @RequiredReadAction public static HighlightInfo checkReference( @Nonnull PsiJavaCodeReferenceElement ref, @Nonnull JavaResolveResult result, @@ -3504,10 +3520,9 @@ public static HighlightInfo checkReference( PsiReferenceExpression referenceToMethod = ((PsiMethodCallExpression)granny).getMethodExpression(); PsiExpression qualifierExpression = referenceToMethod.getQualifierExpression(); if (qualifierExpression == ref && resolved != null && !(resolved instanceof PsiClass) && !(resolved instanceof PsiVariable)) { - String message = JavaErrorBundle.message("qualifier.must.be.expression"); return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF) .range(qualifierExpression) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorBundle.message("qualifier.must.be.expression")) .create(); } } @@ -3524,14 +3539,14 @@ else if (refParent instanceof PsiMethodCallExpression) { } JavaResolveResult[] results = ref.multiResolve(true); - String description; + LocalizeValue description; if (results.length > 1) { String t1 = format(ObjectUtil.notNull(results[0].getElement())); String t2 = format(ObjectUtil.notNull(results[1].getElement())); - description = JavaErrorBundle.message("ambiguous.reference", refName.getText(), t1, t2); + description = JavaErrorLocalize.ambiguousReference(refName.getText(), t1, t2); } else { - description = JavaErrorBundle.message("cannot.resolve.symbol", refName.getText()); + description = JavaErrorLocalize.cannotResolveSymbol(refName.getText()); } HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF) @@ -3544,9 +3559,10 @@ else if (refParent instanceof PsiMethodCallExpression) { if (!result.isValidResult() && !PsiUtil.isInsideJavadocComment(ref)) { if (!result.isAccessible()) { - String message = buildProblemWithAccessDescription(ref, result, resolved); - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(refName).descriptionAndTooltip(message).create(); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF) + .range(refName) + .descriptionAndTooltip(buildProblemWithAccessDescription(ref, result, resolved)) + .create(); if (result.isStaticsScopeCorrect()) { registerAccessQuickFixAction((PsiMember)resolved, ref, info, result.getCurrentFileResolveScope()); if (ref instanceof PsiReferenceExpression) { @@ -3563,9 +3579,10 @@ else if (refParent instanceof PsiMethodCallExpression) { } if (!result.isStaticsScopeCorrect()) { - String description = buildProblemWithStaticDescription(resolved); - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(refName).descriptionAndTooltip(description).create(); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF) + .range(refName) + .descriptionAndTooltip(buildProblemWithStaticDescription(resolved)) + .create(); registerStaticProblemQuickFixAction(resolved, info, ref); if (ref instanceof PsiReferenceExpression) { QuickFixAction.registerQuickFixAction( @@ -3583,8 +3600,10 @@ else if (refParent instanceof PsiMethodCallExpression) { if (resolved instanceof PsiClass && ((PsiClass)resolved).getContainingClass() == null && PsiTreeUtil.getParentOfType(ref, PsiImportStatementBase.class) != null && PsiUtil.isFromDefaultPackage((PsiClass)resolved)) { - String description = JavaErrorBundle.message("cannot.resolve.symbol", refName.getText()); - return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(refName).descriptionAndTooltip(description).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF) + .range(refName) + .descriptionAndTooltip(JavaErrorLocalize.cannotResolveSymbol(refName.getText())) + .create(); } return null; @@ -3613,6 +3632,7 @@ private static PsiElement getOuterReferenceParent(PsiJavaCodeReferenceElement re } @Nullable + @RequiredReadAction public static HighlightInfo checkPackageAndClassConflict(@Nonnull PsiJavaCodeReferenceElement ref, @Nonnull PsiFile containingFile) { if (ref.isQualified() && getOuterReferenceParent(ref) instanceof PsiPackageStatement) { VirtualFile file = containingFile.getVirtualFile(); @@ -3622,8 +3642,10 @@ public static HighlightInfo checkPackageAndClassConflict(@Nonnull PsiJavaCodeRef GlobalSearchScope scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, false); PsiClass aClass = JavaPsiFacade.getInstance(ref.getProject()).findClass(ref.getCanonicalText(), scope); if (aClass != null) { - String message = JavaErrorBundle.message("package.clashes.with.class", ref.getText()); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(ref).descriptionAndTooltip(message).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(ref) + .descriptionAndTooltip(JavaErrorLocalize.packageClashesWithClass(ref.getText())) + .create(); } } } diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 407ce1e73b..3a7d14cf61 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -34,12 +34,14 @@ import com.intellij.java.language.psi.javadoc.PsiDocComment; import com.intellij.java.language.psi.javadoc.PsiDocTagValue; import com.intellij.java.language.psi.util.*; +import consulo.annotation.access.RequiredReadAction; import consulo.application.dumb.IndexNotReadyException; import consulo.application.progress.ProgressIndicator; import consulo.application.progress.ProgressManager; import consulo.colorScheme.TextAttributesScheme; import consulo.document.Document; import consulo.document.util.TextRange; +import consulo.java.language.impl.localize.JavaErrorLocalize; import consulo.java.language.module.util.JavaClassNames; import consulo.language.editor.DaemonCodeAnalyzer; import consulo.language.editor.Pass; @@ -1645,7 +1647,8 @@ public void visitReferenceExpression(PsiReferenceExpression expression) { } @Override - public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { + @RequiredReadAction + public void visitMethodReferenceExpression(@Nonnull PsiMethodReferenceExpression expression) { myHolder.add(checkFeature(expression, JavaFeature.METHOD_REFERENCES)); final PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent()); if (parent instanceof PsiExpressionStatement) { @@ -1666,18 +1669,19 @@ public void visitMethodReferenceExpression(PsiMethodReferenceExpression expressi } final PsiElement method = result.getElement(); if (method != null && !result.isAccessible()) { - final String accessProblem = HighlightUtil.buildProblemWithAccessDescription(expression, result); - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(accessProblem).create(); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(HighlightUtil.buildProblemWithAccessDescription(expression, result)) + .create(); HighlightUtil.registerAccessQuickFixAction((PsiMember)method, expression, info, result.getCurrentFileResolveScope()); myHolder.add(info); } else { final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); - if (method instanceof PsiMethod && !expression.isConstructor()) { + if (method instanceof PsiMethod method1 && !expression.isConstructor()) { PsiElement methodNameElement = expression.getReferenceNameElement(); if (methodNameElement != null) { - myHolder.add(HighlightNamesUtil.highlightMethodName((PsiMethod)method, methodNameElement, false, colorsScheme)); + myHolder.add(HighlightNamesUtil.highlightMethodName(method1, methodNameElement, false, colorsScheme)); } } myHolder.add(HighlightNamesUtil.highlightClassNameInQualifier(expression, colorsScheme)); @@ -1728,9 +1732,8 @@ public void visitMethodReferenceExpression(PsiMethodReferenceExpression expressi if (errorMessage != null) { final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(errorMessage).create(); - if (method instanceof PsiMethod && !((PsiMethod)method).isConstructor() && !((PsiMethod)method).hasModifierProperty( - PsiModifier.ABSTRACT)) { - final boolean shouldHave = !((PsiMethod)method).hasModifierProperty(PsiModifier.STATIC); + if (method instanceof PsiMethod method1 && !method1.isConstructor() && !method1.isAbstract()) { + final boolean shouldHave = !method1.isStatic(); final LocalQuickFixAndIntentionActionOnPsiElement fixStaticModifier = QuickFixFactory.getInstance().createModifierListFix( (PsiModifierListOwner)method, @@ -1745,8 +1748,8 @@ public void visitMethodReferenceExpression(PsiMethodReferenceExpression expressi if (!myHolder.hasErrorResults()) { PsiElement qualifier = expression.getQualifier(); - if (qualifier instanceof PsiTypeElement) { - final PsiType psiType = ((PsiTypeElement)qualifier).getType(); + if (qualifier instanceof PsiTypeElement typeElem) { + final PsiType psiType = typeElem.getType(); final HighlightInfo genericArrayCreationInfo = GenericsHighlightUtil.checkGenericArrayCreation(qualifier, psiType); if (genericArrayCreationInfo != null) { myHolder.add(genericArrayCreationInfo); @@ -1782,35 +1785,34 @@ public void visitMethodReferenceExpression(PsiMethodReferenceExpression expressi } if (!myHolder.hasErrorResults()) { - if (results.length == 0 || results[0] instanceof MethodCandidateInfo && !((MethodCandidateInfo)results[0]).isApplicable() && functionalInterfaceType != null) { + if (results.length == 0 + || results[0] instanceof MethodCandidateInfo candidate && !candidate.isApplicable() && functionalInterfaceType != null) { String description = null; if (results.length == 1) { description = ((MethodCandidateInfo)results[0]).getInferenceErrorMessage(); } if (expression.isConstructor()) { - final PsiClass containingClass = PsiMethodReferenceUtil.getQualifierResolveResult(expression).getContainingClass(); + PsiClass containingClass = PsiMethodReferenceUtil.getQualifierResolveResult(expression).getContainingClass(); if (containingClass != null) { - if (!myHolder.add(HighlightClassUtil.checkInstantiationOfAbstractClass( - containingClass, - expression - )) && !myHolder.add(GenericsHighlightUtil.checkEnumInstantiation( - expression, - containingClass - )) && containingClass.isPhysical() && description == null) { - description = JavaErrorBundle.message("cannot.resolve.constructor", containingClass.getName()); + if (!myHolder.add(HighlightClassUtil.checkInstantiationOfAbstractClass(containingClass, expression)) + && !myHolder.add(GenericsHighlightUtil.checkEnumInstantiation(expression, containingClass)) + && containingClass.isPhysical() && description == null) { + description = JavaErrorLocalize.cannotResolveConstructor(containingClass.getName()).get(); } } } else if (description == null) { - description = JavaErrorBundle.message("cannot.resolve.method", expression.getReferenceName()); + description = JavaErrorLocalize.cannotResolveMethod(expression.getReferenceName()).get(); } if (description != null) { PsiElement referenceNameElement = notNull(expression.getReferenceNameElement(), expression); HighlightInfoType type = results.length == 0 ? HighlightInfoType.WRONG_REF : HighlightInfoType.ERROR; - HighlightInfo highlightInfo = - HighlightInfo.newHighlightInfo(type).descriptionAndTooltip(description).range(referenceNameElement).create(); + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(type) + .descriptionAndTooltip(description) + .range(referenceNameElement) + .create(); myHolder.add(highlightInfo); TextRange fixRange = HighlightMethodUtil.getFixRange(referenceNameElement); QuickFixAction.registerQuickFixAction( @@ -1826,15 +1828,15 @@ else if (description == null) { // 15.13 | 15.27 // It is a compile-time error if any class or interface mentioned by either U or the function type of U // is not accessible from the class or interface in which the method reference expression appears. + @RequiredReadAction private void checkFunctionalInterfaceTypeAccessible(@Nonnull PsiFunctionalExpression expression, PsiType functionalInterfaceType) { PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); final PsiClass psiClass = resolveResult.getElement(); if (psiClass != null) { if (!PsiUtil.isAccessible(myFile.getProject(), psiClass, expression, null)) { - String text = HighlightUtil.buildProblemWithAccessDescription(expression, resolveResult); myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(text) + .descriptionAndTooltip(HighlightUtil.buildProblemWithAccessDescription(expression, resolveResult)) .create()); } else { diff --git a/java-language-impl/src/main/java/com/intellij/java/language/impl/refactoring/util/RefactoringChangeUtil.java b/java-language-impl/src/main/java/com/intellij/java/language/impl/refactoring/util/RefactoringChangeUtil.java index 6eb0654282..0e63141eca 100644 --- a/java-language-impl/src/main/java/com/intellij/java/language/impl/refactoring/util/RefactoringChangeUtil.java +++ b/java-language-impl/src/main/java/com/intellij/java/language/impl/refactoring/util/RefactoringChangeUtil.java @@ -18,6 +18,7 @@ import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.util.InheritanceUtil; import com.intellij.java.language.psi.util.PsiUtil; +import consulo.annotation.access.RequiredWriteAction; import consulo.language.codeStyle.CodeStyleManager; import consulo.language.psi.PsiElement; import consulo.language.psi.PsiManager; @@ -33,11 +34,7 @@ public class RefactoringChangeUtil { @Nullable private static String getMethodExpressionName(@Nullable PsiElement element) { - if (!(element instanceof PsiMethodCallExpression)) { - return null; - } - PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)element).getMethodExpression(); - return methodExpression.getReferenceName(); + return element instanceof PsiMethodCallExpression methodCall ? methodCall.getMethodExpression().getReferenceName() : null; } public static boolean isSuperOrThisMethodCall(@Nullable PsiElement element) { @@ -64,14 +61,13 @@ public static PsiType getTypeByExpression(PsiExpression expr) { } } - if (expr instanceof PsiReferenceExpression && PsiUtil.isOnAssignmentLeftHand(expr)) { - return getTypeByExpression(((PsiAssignmentExpression)expr.getParent()).getRExpression()); + if (expr instanceof PsiReferenceExpression refExpr && PsiUtil.isOnAssignmentLeftHand(expr)) { + return getTypeByExpression(((PsiAssignmentExpression)refExpr.getParent()).getRExpression()); } return null; } - PsiClass refClass = PsiUtil.resolveClassInType(type); - if (refClass instanceof PsiAnonymousClass) { - type = ((PsiAnonymousClass)refClass).getBaseClassType(); + if (PsiUtil.resolveClassInType(type) instanceof PsiAnonymousClass anonymousClass) { + type = anonymousClass.getBaseClassType(); } return GenericsUtil.getVariableTypeByExpressionType(type); @@ -80,7 +76,7 @@ public static PsiType getTypeByExpression(PsiExpression expr) { public static PsiReferenceExpression qualifyReference( @Nonnull PsiReferenceExpression referenceExpression, @Nonnull PsiMember member, - @Nullable final PsiClass qualifyingClass + @Nullable PsiClass qualifyingClass ) throws IncorrectOperationException { PsiManager manager = referenceExpression.getManager(); PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType( @@ -99,17 +95,17 @@ public static PsiReferenceExpression qualifyReference( ); } PsiReferenceExpression expressionFromText; - final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); + PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); if (qualifyingClass == null) { PsiClass parentClass = PsiTreeUtil.getParentOfType(referenceExpression, PsiClass.class); - final PsiClass containingClass = member.getContainingClass(); + PsiClass containingClass = member.getContainingClass(); if (parentClass != null && !InheritanceUtil.isInheritorOrSelf(parentClass, containingClass, true)) { while (parentClass != null && !InheritanceUtil.isInheritorOrSelf(parentClass, containingClass, true)) { parentClass = PsiTreeUtil.getParentOfType(parentClass, PsiClass.class, true); } LOG.assertTrue(parentClass != null); - expressionFromText = (PsiReferenceExpression)factory - .createExpressionFromText("A.this." + member.getName(), null); + expressionFromText = (PsiReferenceExpression) + factory.createExpressionFromText("A.this." + member.getName(), null); ((PsiThisExpression)expressionFromText.getQualifierExpression()).getQualifier() .replace(factory.createClassReferenceElement(parentClass)); } @@ -148,6 +144,8 @@ public static PsiClass getThisClass(@Nonnull PsiElement place) { } } + @RequiredWriteAction + @SuppressWarnings("unchecked") static T createQualifiedExpression( @Nonnull PsiManager manager, PsiClass qualifierClass, @@ -167,11 +165,13 @@ static T createQualifiedExpression( } } + @RequiredWriteAction public static PsiThisExpression createThisExpression(PsiManager manager, PsiClass qualifierClass) throws IncorrectOperationException { return RefactoringChangeUtil.createQualifiedExpression(manager, qualifierClass, "this"); } + @RequiredWriteAction public static PsiSuperExpression createSuperExpression(PsiManager manager, PsiClass qualifierClass) throws IncorrectOperationException { return RefactoringChangeUtil.createQualifiedExpression(manager, qualifierClass, "super"); diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/favoritesTreeView/smartPointerPsiNodes/BaseSmartPointerPsiNode.java b/plugin/src/main/java/com/intellij/java/impl/ide/favoritesTreeView/smartPointerPsiNodes/BaseSmartPointerPsiNode.java index 449e17e0ce..435c0c48c7 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/favoritesTreeView/smartPointerPsiNodes/BaseSmartPointerPsiNode.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/favoritesTreeView/smartPointerPsiNodes/BaseSmartPointerPsiNode.java @@ -16,6 +16,7 @@ package com.intellij.java.impl.ide.favoritesTreeView.smartPointerPsiNodes; import com.intellij.java.language.psi.PsiDocCommentOwner; +import consulo.annotation.access.RequiredReadAction; import consulo.codeEditor.CodeInsightColors; import consulo.component.util.Iconable; import consulo.language.icon.IconDescriptorUpdaters; @@ -41,8 +42,9 @@ protected BaseSmartPointerPsiNode(Project project, Type value, ViewSettings view super(project, value, viewSettings); } - @Override @Nonnull + @Override + @RequiredReadAction public final Collection getChildren() { PsiElement value = getPsiElement(); if (value == null) { @@ -56,11 +58,12 @@ public final Collection getChildren() { protected abstract Collection getChildrenImpl(); protected boolean isMarkReadOnly() { - final Object parentValue = getParentValue(); + Object parentValue = getParentValue(); return parentValue instanceof PsiDirectory || parentValue instanceof PackageElement; } @Override + @RequiredReadAction public PsiElement getTargetElement() { VirtualFile file = getVirtualFileForValue(); if (file == null) { @@ -84,10 +87,10 @@ private VirtualFile getVirtualFileForValue() { protected abstract void updateImpl(PresentationData data); - @Override + @RequiredReadAction public void update(PresentationData data) { - final PsiElement value = getPsiElement(); + PsiElement value = getPsiElement(); if (value == null || !value.isValid()) { setValue(null); } @@ -115,10 +118,8 @@ public void update(PresentationData data) { } private boolean isDeprecated() { - final PsiElement element = getPsiElement(); - return element instanceof PsiDocCommentOwner - && element.isValid() - && ((PsiDocCommentOwner)element).isDeprecated(); + PsiElement element = getPsiElement(); + return element instanceof PsiDocCommentOwner docCommentOwner && element.isValid() && docCommentOwner.isDeprecated(); } @Override diff --git a/plugin/src/main/java/com/intellij/java/impl/ig/performance/ClassInitializerMayBeStaticInspection.java b/plugin/src/main/java/com/intellij/java/impl/ig/performance/ClassInitializerMayBeStaticInspection.java index 653f50d8ee..48b1238bfa 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ig/performance/ClassInitializerMayBeStaticInspection.java +++ b/plugin/src/main/java/com/intellij/java/impl/ig/performance/ClassInitializerMayBeStaticInspection.java @@ -68,11 +68,11 @@ public BaseInspectionVisitor buildVisitor() { private static class ClassInitializerCanBeStaticVisitor extends BaseInspectionVisitor { @Override public void visitClassInitializer(PsiClassInitializer initializer) { - if (initializer.hasModifierProperty(PsiModifier.STATIC)) { + if (initializer.isStatic()) { return; } - final PsiClass containingClass = ClassUtils.getContainingClass(initializer); + PsiClass containingClass = ClassUtils.getContainingClass(initializer); if (containingClass == null) { return; } @@ -81,12 +81,12 @@ public void visitClassInitializer(PsiClassInitializer initializer) { return; } } - final PsiElement scope = containingClass.getScope(); - if (!(scope instanceof PsiJavaFile) && !containingClass.hasModifierProperty(PsiModifier.STATIC)) { + PsiElement scope = containingClass.getScope(); + if (!(scope instanceof PsiJavaFile) && !containingClass.isStatic()) { return; } - final MethodReferenceVisitor visitor = new MethodReferenceVisitor(initializer); + MethodReferenceVisitor visitor = new MethodReferenceVisitor(initializer); initializer.accept(visitor); if (!visitor.areReferencesStaticallyAccessible()) { return; diff --git a/plugin/src/main/java/com/intellij/java/impl/ig/performance/MethodMayBeStaticInspection.java b/plugin/src/main/java/com/intellij/java/impl/ig/performance/MethodMayBeStaticInspection.java index 3786e9a5e9..ac86346c13 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ig/performance/MethodMayBeStaticInspection.java +++ b/plugin/src/main/java/com/intellij/java/impl/ig/performance/MethodMayBeStaticInspection.java @@ -24,8 +24,8 @@ import com.siyeh.ig.psiutils.ClassUtils; import com.siyeh.ig.psiutils.MethodUtils; import com.siyeh.localize.InspectionGadgetsLocalize; +import consulo.annotation.access.RequiredReadAction; import consulo.annotation.component.ExtensionImpl; -import consulo.application.util.function.Processor; import consulo.application.util.query.Query; import consulo.deadCodeNotWorking.impl.MultipleCheckboxOptionsPanel; import consulo.java.analysis.codeInspection.CantBeStaticCondition; @@ -33,9 +33,9 @@ import consulo.java.language.module.util.JavaClassNames; import consulo.language.psi.PsiElement; import jakarta.annotation.Nonnull; -import org.jetbrains.annotations.NonNls; import javax.swing.*; +import java.util.function.Predicate; @ExtensionImpl public class MethodMayBeStaticInspection extends BaseInspection { @@ -67,7 +67,7 @@ protected InspectionGadgetsFix buildFix(Object... infos) { @Override public JComponent createOptionsPanel() { - final MultipleCheckboxOptionsPanel optionsPanel = new MultipleCheckboxOptionsPanel(this); + MultipleCheckboxOptionsPanel optionsPanel = new MultipleCheckboxOptionsPanel(this); optionsPanel.addCheckbox(InspectionGadgetsLocalize.methodMayBeStaticOnlyOption().get(), "m_onlyPrivateOrFinal"); optionsPanel.addCheckbox(InspectionGadgetsLocalize.methodMayBeStaticEmptyOption().get(), "m_ignoreEmptyMethods"); return optionsPanel; @@ -79,12 +79,11 @@ public BaseInspectionVisitor buildVisitor() { } private class MethodCanBeStaticVisitor extends BaseInspectionVisitor { - @Override public void visitMethod(@Nonnull PsiMethod method) { super.visitMethod(method); - if (method.hasModifierProperty(PsiModifier.STATIC) || - method.hasModifierProperty(PsiModifier.ABSTRACT) || + if (method.isStatic() || + method.isAbstract() || method.hasModifierProperty(PsiModifier.SYNCHRONIZED) || method.hasModifierProperty(PsiModifier.NATIVE)) { return; @@ -95,7 +94,7 @@ public void visitMethod(@Nonnull PsiMethod method) { if (m_ignoreEmptyMethods && MethodUtils.isEmpty(method)) { return; } - final PsiClass containingClass = ClassUtils.getContainingClass(method); + PsiClass containingClass = ClassUtils.getContainingClass(method); if (containingClass == null) { return; } @@ -104,11 +103,11 @@ public void visitMethod(@Nonnull PsiMethod method) { return; } } - final PsiElement scope = containingClass.getScope(); - if (!(scope instanceof PsiJavaFile) && !containingClass.hasModifierProperty(PsiModifier.STATIC)) { + PsiElement scope = containingClass.getScope(); + if (!(scope instanceof PsiJavaFile) && !containingClass.isStatic()) { return; } - if (m_onlyPrivateOrFinal && !method.hasModifierProperty(PsiModifier.FINAL) && !method.hasModifierProperty(PsiModifier.PRIVATE)) { + if (m_onlyPrivateOrFinal && !method.isFinal() && !method.isPrivate()) { return; } if (isExcluded(method) || MethodUtils.hasSuper(method) || MethodUtils.isOverridden(method)) { @@ -117,7 +116,7 @@ public void visitMethod(@Nonnull PsiMethod method) { if (implementsSurprisingInterface(method)) { return; } - final MethodReferenceVisitor visitor = new MethodReferenceVisitor(method); + MethodReferenceVisitor visitor = new MethodReferenceVisitor(method); method.accept(visitor); if (!visitor.areReferencesStaticallyAccessible()) { return; @@ -125,34 +124,35 @@ public void visitMethod(@Nonnull PsiMethod method) { registerMethodError(method); } - private boolean implementsSurprisingInterface(final PsiMethod method) { - final PsiClass containingClass = method.getContainingClass(); + private boolean implementsSurprisingInterface(PsiMethod method) { + PsiClass containingClass = method.getContainingClass(); if (containingClass == null) { return false; } - final Query search = ClassInheritorsSearch.search(containingClass, method.getUseScope(), true, true, false); - final boolean[] result = new boolean[1]; - search.forEach(new Processor() { + Query search = ClassInheritorsSearch.search(containingClass, method.getUseScope(), true, true, false); + boolean[] result = new boolean[1]; + search.forEach(new Predicate<>() { int count = 0; @Override - public boolean process(PsiClass subClass) { + @RequiredReadAction + public boolean test(PsiClass subClass) { if (++count > 5) { result[0] = true; return false; } - final PsiReferenceList list = subClass.getImplementsList(); + PsiReferenceList list = subClass.getImplementsList(); if (list == null) { return true; } - final PsiJavaCodeReferenceElement[] referenceElements = list.getReferenceElements(); + PsiJavaCodeReferenceElement[] referenceElements = list.getReferenceElements(); for (PsiJavaCodeReferenceElement referenceElement : referenceElements) { - final PsiElement target = referenceElement.resolve(); + PsiElement target = referenceElement.resolve(); if (!(target instanceof PsiClass)) { result[0] = true; return false; } - final PsiClass aClass = (PsiClass)target; + PsiClass aClass = (PsiClass)target; if (!aClass.isInterface()) { result[0] = true; return false; @@ -169,54 +169,54 @@ public boolean process(PsiClass subClass) { } private boolean isExcluded(PsiMethod method) { - @NonNls final String name = method.getName(); + String name = method.getName(); if ("writeObject".equals(name)) { - if (!method.hasModifierProperty(PsiModifier.PRIVATE)) { + if (!method.isPrivate()) { return false; } if (!MethodUtils.hasInThrows(method, "java.io.IOException")) { return false; } - final PsiType returnType = method.getReturnType(); + PsiType returnType = method.getReturnType(); if (!PsiType.VOID.equals(returnType)) { return false; } - final PsiParameterList parameterList = method.getParameterList(); + PsiParameterList parameterList = method.getParameterList(); if (parameterList.getParametersCount() != 1) { return false; } - final PsiParameter parameter = parameterList.getParameters()[0]; - final PsiType type = parameter.getType(); + PsiParameter parameter = parameterList.getParameters()[0]; + PsiType type = parameter.getType(); return type.equalsToText("java.io.ObjectOutputStream"); } if ("readObject".equals(name)) { - if (!method.hasModifierProperty(PsiModifier.PRIVATE)) { + if (!method.isPrivate()) { return false; } if (!MethodUtils.hasInThrows(method, "java.io.IOException", "java.lang.ClassNotFoundException")) { return false; } - final PsiType returnType = method.getReturnType(); + PsiType returnType = method.getReturnType(); if (!PsiType.VOID.equals(returnType)) { return false; } - final PsiParameterList parameterList = method.getParameterList(); + PsiParameterList parameterList = method.getParameterList(); if (parameterList.getParametersCount() != 1) { return false; } - final PsiParameter parameter = parameterList.getParameters()[0]; - final PsiType type = parameter.getType(); + PsiParameter parameter = parameterList.getParameters()[0]; + PsiType type = parameter.getType(); return type.equalsToText("java.io.ObjectInputStream"); } if ("writeReplace".equals(name) || "readResolve".equals(name)) { if (!MethodUtils.hasInThrows(method, "java.io.ObjectStreamException")) { return false; } - final PsiType returnType = method.getReturnType(); + PsiType returnType = method.getReturnType(); if (returnType == null || !returnType.equalsToText(JavaClassNames.JAVA_LANG_OBJECT)) { return false; } - final PsiParameterList parameterList = method.getParameterList(); + PsiParameterList parameterList = method.getParameterList(); return parameterList.getParametersCount() == 0; } return false; diff --git a/plugin/src/main/java/com/intellij/java/impl/psi/NonClasspathResolveScopeEnlarger.java b/plugin/src/main/java/com/intellij/java/impl/psi/NonClasspathResolveScopeEnlarger.java index 2582c169d3..80483277c4 100644 --- a/plugin/src/main/java/com/intellij/java/impl/psi/NonClasspathResolveScopeEnlarger.java +++ b/plugin/src/main/java/com/intellij/java/impl/psi/NonClasspathResolveScopeEnlarger.java @@ -32,8 +32,8 @@ public SearchScope getAdditionalResolveScope(@Nonnull VirtualFile file, Project FileType fileType = file.getFileType(); if (fileType == JavaFileType.INSTANCE || fileType == JavaClassFileType.INSTANCE) { for (PsiElementFinder finder : PsiElementFinder.EP_NAME.getExtensionList(project)) { - if (finder instanceof NonClasspathClassFinder) { - final List roots = ((NonClasspathClassFinder)finder).getClassRoots(); + if (finder instanceof NonClasspathClassFinder nonClasspathClassFinder) { + List roots = nonClasspathClassFinder.getClassRoots(); for (VirtualFile root : roots) { if (VfsUtilCore.isAncestor(root, file, true)) { return NonClasspathDirectoriesScope.compose(roots); diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/ChangeSignatureProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/ChangeSignatureProcessor.java index c07e0bebb4..6fed78ecc6 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/ChangeSignatureProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/changeSignature/ChangeSignatureProcessor.java @@ -43,7 +43,6 @@ import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.util.collection.MultiMap; -import consulo.util.lang.ref.Ref; import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -56,7 +55,7 @@ public class ChangeSignatureProcessor extends ChangeSignatureProcessorBase { public ChangeSignatureProcessor( Project project, PsiMethod method, - final boolean generateDelegate, + boolean generateDelegate, @PsiModifier.ModifierConstant String newVisibility, String newName, PsiType newType, @@ -79,7 +78,7 @@ public ChangeSignatureProcessor( public ChangeSignatureProcessor( Project project, PsiMethod method, - final boolean generateDelegate, + boolean generateDelegate, @PsiModifier.ModifierConstant String newVisibility, String newName, PsiType newType, @@ -128,7 +127,7 @@ public ChangeSignatureProcessor( ); } - public ChangeSignatureProcessor(Project project, final JavaChangeInfo changeInfo) { + public ChangeSignatureProcessor(Project project, JavaChangeInfo changeInfo) { super(project, changeInfo); LOG.assertTrue(myChangeInfo.getMethod().isValid()); } @@ -194,7 +193,7 @@ protected boolean preprocessUsages(@Nonnull SimpleReference refUsag } MultiMap conflictDescriptions = new MultiMap<>(); for (ChangeSignatureUsageProcessor usageProcessor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) { - final MultiMap conflicts = usageProcessor.findConflicts(myChangeInfo, refUsages); + MultiMap conflicts = usageProcessor.findConflicts(myChangeInfo, refUsages); for (PsiElement key : conflicts.keySet()) { Collection collection = conflictDescriptions.get(key); if (collection.size() == 0) { @@ -205,7 +204,7 @@ protected boolean preprocessUsages(@Nonnull SimpleReference refUsag } } - final UsageInfo[] usagesIn = refUsages.get(); + UsageInfo[] usagesIn = refUsages.get(); RenameUtil.addConflictDescriptions(usagesIn, conflictDescriptions); Set usagesSet = new HashSet<>(Arrays.asList(usagesIn)); RenameUtil.removeConflictUsages(usagesSet); @@ -240,7 +239,7 @@ private void askToRemoveCovariantOverriders(Set usages) { List covariantOverriderInfos = new ArrayList<>(); for (UsageInfo usageInfo : usages) { if (usageInfo instanceof OverriderUsageInfo) { - final OverriderUsageInfo info = (OverriderUsageInfo)usageInfo; + OverriderUsageInfo info = (OverriderUsageInfo)usageInfo; PsiMethod overrider = info.getElement(); PsiMethod baseMethod = info.getBaseMethod(); PsiSubstitutor substitutor = calculateSubstitutor(overrider, baseMethod); @@ -252,7 +251,7 @@ private void askToRemoveCovariantOverriders(Set usages) { LOG.error(e); return; } - final PsiType overriderType = overrider.getReturnType(); + PsiType overriderType = overrider.getReturnType(); if (overriderType != null && type.isAssignableFrom(overriderType)) { covariantOverriderInfos.add(usageInfo); } @@ -272,7 +271,7 @@ private void askToRemoveCovariantOverriders(Set usages) { } } - protected void preprocessCovariantOverriders(final List covariantOverriderInfos) { + protected void preprocessCovariantOverriders(List covariantOverriderInfos) { } @RequiredUIAccess @@ -285,7 +284,7 @@ protected boolean isProcessCovariantOverriders() { ) == DialogWrapper.OK_EXIT_CODE; } - public static void makeEmptyBody(final PsiElementFactory factory, final PsiMethod delegate) throws IncorrectOperationException { + public static void makeEmptyBody(PsiElementFactory factory, PsiMethod delegate) throws IncorrectOperationException { PsiCodeBlock body = delegate.getBody(); if (body != null) { body.replace(factory.createCodeBlock()); @@ -297,34 +296,29 @@ public static void makeEmptyBody(final PsiElementFactory factory, final PsiMetho } @Nullable - public static PsiCallExpression addDelegatingCallTemplate( - final PsiMethod delegate, - final String newName - ) throws IncorrectOperationException { + public static PsiCallExpression addDelegatingCallTemplate(PsiMethod delegate, String newName) throws IncorrectOperationException { Project project = delegate.getProject(); PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory(); PsiCodeBlock body = delegate.getBody(); assert body != null; - final PsiCallExpression callExpression; + PsiCallExpression callExpression; if (delegate.isConstructor()) { PsiElement callStatement = factory.createStatementFromText("this();", null); callStatement = CodeStyleManager.getInstance(project).reformat(callStatement); callStatement = body.add(callStatement); callExpression = (PsiCallExpression)((PsiExpressionStatement)callStatement).getExpression(); } + else if (PsiType.VOID.equals(delegate.getReturnType())) { + PsiElement callStatement = factory.createStatementFromText(newName + "();", null); + callStatement = CodeStyleManager.getInstance(project).reformat(callStatement); + callStatement = body.add(callStatement); + callExpression = (PsiCallExpression)((PsiExpressionStatement)callStatement).getExpression(); + } else { - if (PsiType.VOID.equals(delegate.getReturnType())) { - PsiElement callStatement = factory.createStatementFromText(newName + "();", null); - callStatement = CodeStyleManager.getInstance(project).reformat(callStatement); - callStatement = body.add(callStatement); - callExpression = (PsiCallExpression)((PsiExpressionStatement)callStatement).getExpression(); - } - else { - PsiElement callStatement = factory.createStatementFromText("return " + newName + "();", null); - callStatement = CodeStyleManager.getInstance(project).reformat(callStatement); - callStatement = body.add(callStatement); - callExpression = (PsiCallExpression)((PsiReturnStatement)callStatement).getReturnValue(); - } + PsiElement callStatement = factory.createStatementFromText("return " + newName + "();", null); + callStatement = CodeStyleManager.getInstance(project).reformat(callStatement); + callStatement = body.add(callStatement); + callExpression = (PsiCallExpression)((PsiReturnStatement)callStatement).getReturnValue(); } return callExpression; } @@ -335,14 +329,14 @@ public static PsiSubstitutor calculateSubstitutor(PsiMethod derivedMethod, PsiMe substitutor = PsiSubstitutor.EMPTY; } else { - final PsiClass baseClass = baseMethod.getContainingClass(); - final PsiClass derivedClass = derivedMethod.getContainingClass(); + PsiClass baseClass = baseMethod.getContainingClass(); + PsiClass derivedClass = derivedMethod.getContainingClass(); if (baseClass != null && derivedClass != null && InheritanceUtil.isInheritorOrSelf(derivedClass, baseClass, true)) { - final PsiSubstitutor superClassSubstitutor = + PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, derivedClass, PsiSubstitutor.EMPTY); - final MethodSignature superMethodSignature = baseMethod.getSignature(superClassSubstitutor); - final MethodSignature methodSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY); - final PsiSubstitutor superMethodSubstitutor = + MethodSignature superMethodSignature = baseMethod.getSignature(superClassSubstitutor); + MethodSignature methodSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY); + PsiSubstitutor superMethodSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, superMethodSignature); substitutor = superMethodSubstitutor != null ? superMethodSubstitutor : superClassSubstitutor; } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceParameter/IntroduceParameterProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceParameter/IntroduceParameterProcessor.java index 3019911084..c57f963228 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceParameter/IntroduceParameterProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceParameter/IntroduceParameterProcessor.java @@ -40,6 +40,8 @@ import com.intellij.java.language.impl.codeInsight.ChangeContextUtil; import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.util.PropertyUtil; +import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; import consulo.language.editor.refactoring.BaseRefactoringProcessor; import consulo.language.editor.refactoring.localize.RefactoringLocalize; import consulo.language.editor.refactoring.ui.RefactoringUIUtil; @@ -54,13 +56,14 @@ import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.UsageInfo; import consulo.usage.UsageViewDescriptor; import consulo.usage.UsageViewUtil; import consulo.util.collection.MultiMap; import consulo.util.collection.primitive.ints.IntList; import consulo.util.lang.Pair; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -131,11 +134,13 @@ public IntroduceParameterProcessor( } @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { + @Override + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { return new IntroduceParameterViewDescriptor(myMethodToSearchFor); } @Nonnull + @Override public PsiType getForcedType() { return myForcedType; } @@ -144,6 +149,7 @@ public void setForcedType(PsiType forcedType) { myForcedType = forcedType; } + @Override public int getReplaceFieldsWithGetters() { return myReplaceFieldsWithGetters; } @@ -153,8 +159,10 @@ public void setReplaceFieldsWithGetters(int replaceFieldsWithGetters) { } @Nonnull + @Override + @RequiredReadAction protected UsageInfo[] findUsages() { - ArrayList result = new ArrayList(); + ArrayList result = new ArrayList<>(); PsiMethod[] overridingMethods = OverridingMethodsSearch.search(myMethodToSearchFor, true).toArray(PsiMethod.EMPTY_ARRAY); @@ -196,12 +204,12 @@ else if (!IntroduceParameterUtil.insideMethodToBeReplaced(ref, myMethodToReplace } } - final UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]); + UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]); return UsageViewUtil.removeDuplicatedUsages(usageInfos); } protected PsiElement[] getOccurrences() { - final OccurrenceManager occurrenceManager; + OccurrenceManager occurrenceManager; if (myLocalVariable == null) { occurrenceManager = new ExpressionOccurrenceManager(myExpressionToSearch, myMethodToReplaceIn, null); } @@ -216,30 +224,34 @@ public boolean hasConflicts() { } private static class ReferencedElementsCollector extends JavaRecursiveElementWalkingVisitor { - private final Set myResult = new HashSet(); + private final Set myResult = new HashSet<>(); @Override + @RequiredReadAction public void visitReferenceExpression(PsiReferenceExpression expression) { visitReferenceElement(expression); } @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { + @RequiredReadAction + public void visitReferenceElement(@Nonnull PsiJavaCodeReferenceElement reference) { super.visitReferenceElement(reference); - final PsiElement element = reference.resolve(); + PsiElement element = reference.resolve(); if (element != null) { myResult.add(element); } } } - protected boolean preprocessUsages(Ref refUsages) { + @Override + @RequiredUIAccess + protected boolean preprocessUsages(SimpleReference refUsages) { UsageInfo[] usagesIn = refUsages.get(); - MultiMap conflicts = new MultiMap(); + MultiMap conflicts = new MultiMap<>(); AnySameNameVariables anySameNameVariables = new AnySameNameVariables(); myMethodToReplaceIn.accept(anySameNameVariables); - final Pair conflictPair = anySameNameVariables.getConflict(); + Pair conflictPair = anySameNameVariables.getConflict(); if (conflictPair != null) { conflicts.putValue(conflictPair.first, conflictPair.second); } @@ -248,8 +260,8 @@ protected boolean preprocessUsages(Ref refUsages) { detectAccessibilityConflicts(usagesIn, conflicts); } - if (myParameterInitializer != null && !myMethodToReplaceIn.hasModifierProperty(PsiModifier.PRIVATE)) { - final AnySupers anySupers = new AnySupers(); + if (myParameterInitializer != null && !myMethodToReplaceIn.isPrivate()) { + AnySupers anySupers = new AnySupers(); myParameterInitializer.accept(anySupers); if (anySupers.isResult()) { for (UsageInfo usageInfo : usagesIn) { @@ -276,32 +288,33 @@ protected boolean preprocessUsages(Ref refUsages) { return showConflicts(conflicts, usagesIn); } - private void detectAccessibilityConflicts(final UsageInfo[] usageArray, MultiMap conflicts) { + private void detectAccessibilityConflicts(UsageInfo[] usageArray, MultiMap conflicts) { if (myParameterInitializer != null) { - final ReferencedElementsCollector collector = new ReferencedElementsCollector(); + ReferencedElementsCollector collector = new ReferencedElementsCollector(); myParameterInitializer.accept(collector); - final Set result = collector.myResult; + Set result = collector.myResult; if (!result.isEmpty()) { - for (final UsageInfo usageInfo : usageArray) { + for (UsageInfo usageInfo : usageArray) { if (usageInfo instanceof ExternalUsageInfo && IntroduceParameterUtil.isMethodUsage(usageInfo)) { - final PsiElement place = usageInfo.getElement(); + PsiElement place = usageInfo.getElement(); for (PsiElement element : result) { - if (element instanceof PsiField && myReplaceFieldsWithGetters != IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE) { //check getter access instead - final PsiClass psiClass = ((PsiField)element).getContainingClass(); + if (element instanceof PsiField field + && myReplaceFieldsWithGetters != IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE) { + //check getter access instead + PsiClass psiClass = field.getContainingClass(); LOG.assertTrue(psiClass != null); - final PsiMethod method = - psiClass.findMethodBySignature(PropertyUtil.generateGetterPrototype((PsiField)element), true); + PsiMethod method = + psiClass.findMethodBySignature(PropertyUtil.generateGetterPrototype(field), true); if (method != null) { element = method; } } - if (element instanceof PsiMember && - !JavaPsiFacade.getInstance(myProject).getResolveHelper().isAccessible((PsiMember)element, place, null)) { - LocalizeValue message = - RefactoringLocalize.zeroIsNotAccessibleFrom1ValueForIntroducedParameterInThatMethodCallWillBeIncorrect( - RefactoringUIUtil.getDescription(element, true), - RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(place), true) - ); + if (element instanceof PsiMember member + && !JavaPsiFacade.getInstance(myProject).getResolveHelper().isAccessible(member, place, null)) { + LocalizeValue message = RefactoringLocalize.zeroIsNotAccessibleFrom1ValueForIntroducedParameterInThatMethodCallWillBeIncorrect( + RefactoringUIUtil.getDescription(element, true), + RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(place), true) + ); conflicts.putValue(element, message.get()); } } @@ -315,7 +328,7 @@ public static class AnySupers extends JavaRecursiveElementWalkingVisitor { private boolean myResult = false; @Override - public void visitSuperExpression(PsiSuperExpression expression) { + public void visitSuperExpression(@Nonnull PsiSuperExpression expression) { myResult = true; } @@ -337,7 +350,8 @@ public Pair getConflict() { } @Override - public void visitVariable(PsiVariable variable) { + @RequiredReadAction + public void visitVariable(@Nonnull PsiVariable variable) { if (variable == myLocalVariable) { return; } @@ -363,7 +377,9 @@ public void visitElement(PsiElement element) { } } - protected void performRefactoring(UsageInfo[] usages) { + @Override + @RequiredWriteAction + protected void performRefactoring(@Nonnull UsageInfo[] usages) { try { PsiElementFactory factory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory(); PsiType initializerType = getInitializerType(myForcedType, myParameterInitializer, myLocalVariable); @@ -374,9 +390,9 @@ protected void performRefactoring(UsageInfo[] usages) { LOG.assertTrue(myLocalVariable != null); myParameterInitializer = factory.createExpressionFromText(myLocalVariable.getName(), myLocalVariable); } - else if (myParameterInitializer instanceof PsiArrayInitializerExpression) { - final PsiExpression newExprArrayInitializer = RefactoringUtil.createNewExpressionFromArrayInitializer( - (PsiArrayInitializerExpression)myParameterInitializer, + else if (myParameterInitializer instanceof PsiArrayInitializerExpression arrayInitializerExpr) { + PsiExpression newExprArrayInitializer = RefactoringUtil.createNewExpressionFromArrayInitializer( + arrayInitializerExpr, initializerType ); myParameterInitializer = (PsiExpression)myParameterInitializer.replace(newExprArrayInitializer); @@ -391,9 +407,9 @@ else if (myParameterInitializer instanceof PsiArrayInitializerExpression) { if (myGenerateDelegate) { generateDelegate(myMethodToReplaceIn); if (myMethodToReplaceIn != myMethodToSearchFor) { - final PsiMethod method = generateDelegate(myMethodToSearchFor); + PsiMethod method = generateDelegate(myMethodToSearchFor); if (method.getContainingClass().isInterface()) { - final PsiCodeBlock block = method.getBody(); + PsiCodeBlock block = method.getBody(); if (block != null) { block.delete(); } @@ -404,8 +420,7 @@ else if (myParameterInitializer instanceof PsiArrayInitializerExpression) { // Changing signature of initial method // (signature of myMethodToReplaceIn will be either changed now or have already been changed) LOG.assertTrue(initializerType.isValid()); - final FieldConflictsResolver fieldConflictsResolver = - new FieldConflictsResolver(myParameterName, myMethodToReplaceIn.getBody()); + FieldConflictsResolver fieldConflictsResolver = new FieldConflictsResolver(myParameterName, myMethodToReplaceIn.getBody()); IntroduceParameterUtil.changeMethodSignatureAndResolveFieldConflicts(new UsageInfo(myMethodToReplaceIn), usages, this); if (myMethodToSearchFor != myMethodToReplaceIn) { IntroduceParameterUtil.changeMethodSignatureAndResolveFieldConflicts(new UsageInfo(myMethodToSearchFor), usages, this); @@ -415,14 +430,12 @@ else if (myParameterInitializer instanceof PsiArrayInitializerExpression) { // Replacing expression occurrences for (UsageInfo usage : usages) { if (usage instanceof ChangedMethodCallInfo) { - PsiElement element = usage.getElement(); - - processChangedMethodCall(element); + processChangedMethodCall(usage.getElement()); } else if (usage instanceof InternalUsageInfo) { PsiElement element = usage.getElement(); - if (element instanceof PsiExpression) { - element = RefactoringUtil.outermostParenthesizedExpression((PsiExpression)element); + if (element instanceof PsiExpression expression) { + element = RefactoringUtil.outermostParenthesizedExpression(expression); } if (element != null) { if (element.getParent() instanceof PsiExpressionStatement) { @@ -447,16 +460,16 @@ else if (usage instanceof InternalUsageInfo) { } } - private PsiMethod generateDelegate(final PsiMethod methodToReplaceIn) throws IncorrectOperationException { - final PsiMethod delegate = (PsiMethod)methodToReplaceIn.copy(); - final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory(); + private PsiMethod generateDelegate(PsiMethod methodToReplaceIn) throws IncorrectOperationException { + PsiMethod delegate = (PsiMethod)methodToReplaceIn.copy(); + PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory(); ChangeSignatureProcessor.makeEmptyBody(elementFactory, delegate); - final PsiCallExpression callExpression = ChangeSignatureProcessor.addDelegatingCallTemplate(delegate, delegate.getName()); - final PsiExpressionList argumentList = callExpression.getArgumentList(); + PsiCallExpression callExpression = ChangeSignatureProcessor.addDelegatingCallTemplate(delegate, delegate.getName()); + PsiExpressionList argumentList = callExpression.getArgumentList(); assert argumentList != null; - final PsiParameter[] psiParameters = methodToReplaceIn.getParameterList().getParameters(); + PsiParameter[] psiParameters = methodToReplaceIn.getParameterList().getParameters(); - final PsiParameter anchorParameter = getAnchorParameter(methodToReplaceIn); + PsiParameter anchorParameter = getAnchorParameter(methodToReplaceIn); if (psiParameters.length == 0) { argumentList.add(myParameterInitializer); } @@ -467,7 +480,7 @@ private PsiMethod generateDelegate(final PsiMethod methodToReplaceIn) throws Inc for (int i = 0; i < psiParameters.length; i++) { PsiParameter psiParameter = psiParameters[i]; if (!myParametersToRemove.contains(i)) { - final PsiExpression expression = elementFactory.createExpressionFromText(psiParameter.getName(), delegate); + PsiExpression expression = elementFactory.createExpressionFromText(psiParameter.getName(), delegate); argumentList.add(expression); } if (psiParameter == anchorParameter) { @@ -480,7 +493,7 @@ private PsiMethod generateDelegate(final PsiMethod methodToReplaceIn) throws Inc } static PsiType getInitializerType(PsiType forcedType, PsiExpression parameterInitializer, PsiLocalVariable localVariable) { - final PsiType initializerType; + PsiType initializerType; if (forcedType == null) { if (parameterInitializer == null) { if (localVariable != null) { @@ -514,13 +527,13 @@ private void processChangedMethodCall(PsiElement element) throws IncorrectOperat PsiElementFactory factory = JavaPsiFacade.getInstance(methodCall.getProject()).getElementFactory(); PsiExpression expression = factory.createExpressionFromText(myParameterName, null); - final PsiExpressionList argList = methodCall.getArgumentList(); - final PsiExpression[] exprs = argList.getExpressions(); + PsiExpressionList argList = methodCall.getArgumentList(); + PsiExpression[] exprs = argList.getExpressions(); boolean first = false; PsiElement anchor = null; if (myMethodToSearchFor.isVarArgs()) { - final int oldParamCount = myMethodToSearchFor.getParameterList().getParametersCount() - 1; + int oldParamCount = myMethodToSearchFor.getParameterList().getParametersCount() - 1; if (exprs.length >= oldParamCount) { if (oldParamCount > 1) { anchor = exprs[oldParamCount - 2]; @@ -555,8 +568,8 @@ else if (first && exprs.length > 0) { } } - private void removeParametersFromCall(final PsiExpressionList argList) { - final PsiExpression[] exprs = argList.getExpressions(); + private void removeParametersFromCall(PsiExpressionList argList) { + PsiExpression[] exprs = argList.getExpressions(); for (int i = myParametersToRemove.size() - 1; i >= 0; i--) { int paramNum = myParametersToRemove.get(i); if (paramNum < exprs.length) { @@ -570,6 +583,9 @@ private void removeParametersFromCall(final PsiExpressionList argList) { } } + @Nonnull + @Override + @RequiredReadAction protected String getCommandName() { return RefactoringLocalize.introduceParameterCommand(DescriptiveNameUtil.getDescriptiveName(myMethodToReplaceIn)).get(); } @@ -577,9 +593,9 @@ protected String getCommandName() { @Nullable private static PsiParameter getAnchorParameter(PsiMethod methodToReplaceIn) { PsiParameterList parameterList = methodToReplaceIn.getParameterList(); - final PsiParameter anchorParameter; - final PsiParameter[] parameters = parameterList.getParameters(); - final int length = parameters.length; + PsiParameter anchorParameter; + PsiParameter[] parameters = parameterList.getParameters(); + int length = parameters.length; if (!methodToReplaceIn.isVarArgs()) { anchorParameter = length > 0 ? parameters[length - 1] : null; } @@ -591,38 +607,46 @@ private static PsiParameter getAnchorParameter(PsiMethod methodToReplaceIn) { return anchorParameter; } + @Override public PsiMethod getMethodToReplaceIn() { return myMethodToReplaceIn; } @Nonnull + @Override public PsiMethod getMethodToSearchFor() { return myMethodToSearchFor; } + @Override public JavaExpressionWrapper getParameterInitializer() { return myInitializerWrapper; } @Nonnull + @Override public String getParameterName() { return myParameterName; } + @Override public boolean isDeclareFinal() { return myDeclareFinal; } + @Override public boolean isGenerateDelegate() { return myGenerateDelegate; } @Nonnull + @Override public IntList getParametersToRemove() { return myParametersToRemove; } @Nonnull + @Override public Project getProject() { return myProject; } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceParameter/IntroduceParameterUtil.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceParameter/IntroduceParameterUtil.java index 121108ac17..12c4873349 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceParameter/IntroduceParameterUtil.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/introduceParameter/IntroduceParameterUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.java.impl.refactoring.introduceParameter; +import consulo.annotation.access.RequiredReadAction; import consulo.language.psi.PsiElement; import consulo.language.psi.PsiManager; import com.intellij.java.language.psi.PsiMethod; @@ -33,8 +34,7 @@ public class IntroduceParameterUtil { private IntroduceParameterUtil() { } - - public static boolean insideMethodToBeReplaced(PsiElement methodUsage, final PsiMethod methodToReplaceIn) { + public static boolean insideMethodToBeReplaced(PsiElement methodUsage, PsiMethod methodToReplaceIn) { PsiElement parent = methodUsage.getParent(); while (parent != null) { if (parent.equals(methodToReplaceIn)) { @@ -54,7 +54,7 @@ public static boolean isMethodUsage(UsageInfo usageInfo) { return false; } - public static void addSuperCall(UsageInfo usage, UsageInfo[] usages, final IntroduceParameterData data) + public static void addSuperCall(UsageInfo usage, UsageInfo[] usages, IntroduceParameterData data) throws IncorrectOperationException { for (IntroduceParameterMethodUsagesProcessor processor : IntroduceParameterMethodUsagesProcessor.EP_NAME.getExtensions()) { if (!processor.processAddSuperCall(data, usage, usages)) { @@ -63,7 +63,7 @@ public static void addSuperCall(UsageInfo usage, UsageInfo[] usages, final Intro } } - public static void addDefaultConstructor(UsageInfo usage, UsageInfo[] usages, final IntroduceParameterData data) + public static void addDefaultConstructor(UsageInfo usage, UsageInfo[] usages, IntroduceParameterData data) throws IncorrectOperationException { for (IntroduceParameterMethodUsagesProcessor processor : IntroduceParameterMethodUsagesProcessor.EP_NAME.getExtensions()) { if (!processor.processAddDefaultConstructor(data, usage, usages)) { @@ -72,7 +72,7 @@ public static void addDefaultConstructor(UsageInfo usage, UsageInfo[] usages, fi } } - public static void changeExternalUsage(UsageInfo usage, UsageInfo[] usages, final IntroduceParameterData data) + public static void changeExternalUsage(UsageInfo usage, UsageInfo[] usages, IntroduceParameterData data) throws IncorrectOperationException { for (IntroduceParameterMethodUsagesProcessor processor : IntroduceParameterMethodUsagesProcessor.EP_NAME.getExtensions()) { if (!processor.processChangeMethodUsage(data, usage, usages)) { @@ -84,9 +84,8 @@ public static void changeExternalUsage(UsageInfo usage, UsageInfo[] usages, fina public static void changeMethodSignatureAndResolveFieldConflicts( UsageInfo usage, UsageInfo[] usages, - final IntroduceParameterData data - ) - throws IncorrectOperationException { + IntroduceParameterData data + ) throws IncorrectOperationException { for (IntroduceParameterMethodUsagesProcessor processor : IntroduceParameterMethodUsagesProcessor.EP_NAME.getExtensions()) { if (!processor.processChangeMethodSignature(data, usage, usages)) { break; @@ -94,10 +93,11 @@ public static void changeMethodSignatureAndResolveFieldConflicts( } } + @RequiredReadAction public static void processUsages(UsageInfo[] usages, IntroduceParameterData data) { PsiManager manager = PsiManager.getInstance(data.getProject()); - List methodUsages = new ArrayList(); + List methodUsages = new ArrayList<>(); for (UsageInfo usage : usages) { if (usage instanceof InternalUsageInfo) { @@ -128,6 +128,7 @@ else if (!data.isGenerateDelegate()) { } } + @RequiredReadAction public static boolean isMethodInUsages(IntroduceParameterData data, PsiMethod method, UsageInfo[] usages) { PsiManager manager = PsiManager.getInstance(data.getProject()); for (UsageInfo info : usages) { diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationMapSet.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationMapSet.java index 39e9537381..817d988a55 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationMapSet.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/migration/MigrationMapSet.java @@ -15,59 +15,47 @@ */ package com.intellij.java.impl.refactoring.migration; +import consulo.application.Application; +import consulo.component.util.text.UniqueNameGenerator; +import consulo.container.boot.ContainerPathManager; +import consulo.language.codeStyle.CodeStyleSettingsManager; import consulo.logging.Logger; -import consulo.component.extension.Extensions; -import consulo.util.xml.serializer.InvalidDataException; +import consulo.util.io.FileUtil; import consulo.util.jdom.JDOMUtil; -import consulo.ide.impl.idea.openapi.util.io.FileUtil; -import consulo.ide.impl.idea.openapi.util.io.FileUtilRt; import consulo.util.lang.StringUtil; -import consulo.language.codeStyle.CodeStyleSettingsManager; -import consulo.component.util.text.UniqueNameGenerator; -import consulo.container.boot.ContainerPathManager; +import consulo.util.xml.serializer.InvalidDataException; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; -import org.jetbrains.annotations.NonNls; - -import jakarta.annotation.Nonnull; -import jakarta.annotation.Nullable; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Set; +import java.util.TreeSet; public class MigrationMapSet { private static final Logger LOG = Logger.getInstance(MigrationMapSet.class); private ArrayList myMaps; - @NonNls private static final String MIGRATION_MAP = "migrationMap"; - @NonNls private static final String ENTRY = "entry"; - @NonNls private static final String NAME = "name"; - @NonNls private static final String OLD_NAME = "oldName"; - @NonNls private static final String NEW_NAME = "newName"; - @NonNls private static final String DESCRIPTION = "description"; - @NonNls private static final String VALUE = "value"; - @NonNls private static final String TYPE = "type"; - @NonNls private static final String PACKAGE_TYPE = "package"; - @NonNls private static final String CLASS_TYPE = "class"; - @NonNls private static final String RECURSIVE = "recursive"; - @NonNls private static final String[] DEFAULT_MAPS = new String[]{ "/com/intellij/refactoring/migration/res/Swing__1_0_3____1_1_.xml", }; @@ -117,12 +105,12 @@ public void removeMap(MigrationMap map) { } private static boolean isPredefined(String name) { - for (PredefinedMigrationProvider provider : Extensions.getExtensions(PredefinedMigrationProvider.EP_NAME)) { - URL migrationMap = provider.getMigrationMap(); - String fileName = FileUtil.getNameWithoutExtension(new File(migrationMap.getFile())); - if (fileName.equals(name)) { - return true; - } + boolean fileNameMatches = Application.get().getExtensionPoint(PredefinedMigrationProvider.class).anyMatchSafe(provider -> { + File file = new File(provider.getMigrationMap().getFile()); + return FileUtil.getNameWithoutExtension(file).equals(name); + }); + if (fileNameMatches) { + return true; } for (String defaultTemplate : DEFAULT_MAPS) { @@ -161,7 +149,9 @@ private void copyPredefinedMaps(File dir) { File deletedFiles = new File(dir, "deleted.txt"); if (deletedFiles.isFile()) { try { - myDeletedMaps.addAll(Arrays.asList(FileUtil.loadFile(deletedFiles, true).split("\n"))); + myDeletedMaps.addAll(Arrays.asList( + consulo.ide.impl.idea.openapi.util.io.FileUtil.loadFile(deletedFiles, true).split("\n") + )); } catch (IOException e) { LOG.error(e); @@ -195,28 +185,19 @@ private static void copyMap(File dir, URL url, String fileName) { return; } - try { - FileOutputStream outputStream = new FileOutputStream(targetFile); - InputStream inputStream = url.openStream(); - - try { - FileUtil.copy(inputStream, outputStream); - } - finally { - outputStream.close(); - inputStream.close(); - } + try (FileOutputStream outputStream = new FileOutputStream(targetFile); InputStream inputStream = url.openStream()) { + FileUtil.copy(inputStream, outputStream); } catch (Exception e) { LOG.error(e); } } - private static File[] getMapFiles(final File dir) { + private static File[] getMapFiles(File dir) { if (dir == null) { return new File[0]; } - File[] ret = dir.listFiles((f) -> FileUtilRt.extensionEquals(f.getPath(), "xml")); + File[] ret = dir.listFiles((f) -> FileUtil.extensionEquals(f.getPath(), "xml")); if (ret == null) { LOG.error("cannot read directory: " + dir.getAbsolutePath()); return new File[0]; @@ -232,16 +213,16 @@ private void loadMaps() { copyPredefinedMaps(dir); File[] files = getMapFiles(dir); - for (int i = 0; i < files.length; i++) { + for (File file : files) { try { - MigrationMap map = readMap(files[i]); + MigrationMap map = readMap(file); if (map != null) { - map.setFileName(FileUtil.getNameWithoutExtension(files[i])); + map.setFileName(FileUtil.getNameWithoutExtension(file)); myMaps.add(map); } } catch (InvalidDataException | JDOMException e) { - LOG.error("Invalid data in file: " + files[i].getAbsolutePath()); + LOG.error("Invalid data in file: " + file.getAbsolutePath()); } catch (IOException e) { LOG.error(e); @@ -261,8 +242,7 @@ private static MigrationMap readMap(File file) throws JDOMException, InvalidData MigrationMap map = new MigrationMap(); - for (Iterator i = root.getChildren().iterator(); i.hasNext(); ) { - Element node = (Element)i.next(); + for (Element node : root.getChildren()) { if (NAME.equals(node.getName())) { String name = node.getAttributeValue(VALUE); map.setName(name); @@ -291,7 +271,7 @@ private static MigrationMap readMap(File file) throws JDOMException, InvalidData entry.setType(MigrationMapEntry.CLASS); if (typeStr.equals(PACKAGE_TYPE)) { entry.setType(MigrationMapEntry.PACKAGE); - @NonNls String isRecursiveStr = node.getAttributeValue(RECURSIVE); + String isRecursiveStr = node.getAttributeValue(RECURSIVE); if (isRecursiveStr != null && isRecursiveStr.equals("true")) { entry.setRecursive(true); } @@ -314,7 +294,7 @@ public void saveMaps() throws IOException { File[] files = getMapFiles(dir); - @NonNls String[] filePaths = new String[myMaps.size()]; + String[] filePaths = new String[myMaps.size()]; Document[] documents = new Document[myMaps.size()]; UniqueNameGenerator namesProvider = new UniqueNameGenerator(); diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassToInnerHandler.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassToInnerHandler.java index f21dc63dea..320e7b615f 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassToInnerHandler.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassToInnerHandler.java @@ -48,7 +48,7 @@ public interface MoveClassToInnerHandler { void retargetClassRefsInMoved(@Nonnull Map mapping); - void retargetNonCodeUsages(@Nonnull final Map oldToNewElementMap, @Nonnull NonCodeUsageInfo[] myNonCodeUsages); + void retargetNonCodeUsages(@Nonnull Map oldToNewElementMap, @Nonnull NonCodeUsageInfo[] myNonCodeUsages); void removeRedundantImports(PsiFile targetClassFile); } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassToInnerProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassToInnerProcessor.java index 2778bde2c3..9a22ab5542 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassToInnerProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassToInnerProcessor.java @@ -21,8 +21,9 @@ import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.util.PsiUtil; import com.intellij.java.language.util.VisibilityUtil; -import consulo.application.ApplicationManager; -import consulo.application.util.function.Processor; +import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; +import consulo.application.Application; import consulo.language.editor.refactoring.BaseRefactoringProcessor; import consulo.language.editor.refactoring.localize.RefactoringLocalize; import consulo.language.editor.refactoring.move.MoveCallback; @@ -32,13 +33,13 @@ import consulo.language.editor.util.PsiUtilBase; import consulo.language.psi.PsiElement; import consulo.language.psi.PsiNamedElement; -import consulo.language.psi.PsiReference; import consulo.language.psi.search.ReferencesSearch; -import consulo.language.psi.util.PsiElementFilter; import consulo.language.psi.util.PsiTreeUtil; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.MoveRenameUsageInfo; import consulo.usage.NonCodeUsageInfo; import consulo.usage.UsageInfo; @@ -47,7 +48,7 @@ import consulo.util.dataholder.Key; import consulo.util.lang.Comparing; import consulo.util.lang.StringUtil; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import jakarta.annotation.Nonnull; import java.util.*; @@ -71,8 +72,8 @@ public class MoveClassToInnerProcessor extends BaseRefactoringProcessor { public MoveClassToInnerProcessor( Project project, - final PsiClass[] classesToMove, - @Nonnull final PsiClass targetClass, + PsiClass[] classesToMove, + @Nonnull PsiClass targetClass, boolean searchInComments, boolean searchInNonJavaFiles, MoveCallback moveCallback @@ -86,7 +87,7 @@ public MoveClassToInnerProcessor( myTargetPackage = JavaDirectoryService.getInstance().getPackage(myTargetClass.getContainingFile().getContainingDirectory()); } - private void setClassesToMove(final PsiClass[] classesToMove) { + private void setClassesToMove(PsiClass[] classesToMove) { myClassesToMove = classesToMove; mySourcePackage = new PsiJavaPackage[classesToMove.length]; mySourceVisibility = new String[classesToMove.length]; @@ -98,15 +99,18 @@ private void setClassesToMove(final PsiClass[] classesToMove) { } @Nonnull - protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) { + @Override + protected UsageViewDescriptor createUsageViewDescriptor(@Nonnull UsageInfo[] usages) { return new MoveMultipleElementsViewDescriptor(myClassesToMove, myTargetClass.getQualifiedName()); } @Nonnull + @Override + @RequiredReadAction public UsageInfo[] findUsages() { - final List usages = new ArrayList(); + List usages = new ArrayList<>(); for (PsiClass classToMove : myClassesToMove) { - final String newName = myTargetClass.getQualifiedName() + "." + classToMove.getName(); + String newName = myTargetClass.getQualifiedName() + "." + classToMove.getName(); Collections.addAll( usages, MoveClassesOrPackagesUtil.findUsages(classToMove, mySearchInComments, mySearchInNonJavaFiles, newName) @@ -115,32 +119,35 @@ public UsageInfo[] findUsages() { return usages.toArray(new UsageInfo[usages.size()]); } - protected boolean preprocessUsages(final Ref refUsages) { - final UsageInfo[] usages = refUsages.get(); + @Override + @RequiredUIAccess + protected boolean preprocessUsages(SimpleReference refUsages) { + UsageInfo[] usages = refUsages.get(); return showConflicts(getConflicts(usages), usages); } - protected void refreshElements(final PsiElement[] elements) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - final PsiClass[] classesToMove = new PsiClass[elements.length]; - for (int i = 0; i < classesToMove.length; i++) { - classesToMove[i] = (PsiClass)elements[i]; - } - setClassesToMove(classesToMove); + @Override + protected void refreshElements(@Nonnull PsiElement[] elements) { + Application.get().runReadAction(() -> { + PsiClass[] classesToMove = new PsiClass[elements.length]; + for (int i = 0; i < classesToMove.length; i++) { + classesToMove[i] = (PsiClass)elements[i]; } + setClassesToMove(classesToMove); }); } - protected void performRefactoring(UsageInfo[] usages) { + @Override + @RequiredUIAccess + protected void performRefactoring(@Nonnull UsageInfo[] usages) { if (!prepareWritable(usages)) { return; } MoveClassToInnerHandler[] handlers = MoveClassToInnerHandler.EP_NAME.getExtensions(); - ArrayList usageList = new ArrayList(Arrays.asList(usages)); - List importStatements = new ArrayList(); + List usageList = new ArrayList<>(Arrays.asList(usages)); + List importStatements = new ArrayList<>(); for (MoveClassToInnerHandler handler : handlers) { importStatements.addAll(handler.filterImports(usageList, myProject)); } @@ -148,7 +155,7 @@ protected void performRefactoring(UsageInfo[] usages) { usages = usageList.toArray(new UsageInfo[usageList.size()]); saveNonCodeUsages(usages); - final Map oldToNewElementsMapping = new HashMap(); + Map oldToNewElementsMapping = new HashMap<>(); try { for (PsiClass classToMove : myClassesToMove) { PsiClass newClass = null; @@ -193,8 +200,9 @@ protected void performRefactoring(UsageInfo[] usages) { } } - private boolean prepareWritable(final UsageInfo[] usages) { - Set elementsToMakeWritable = new HashSet(); + @RequiredUIAccess + private boolean prepareWritable(UsageInfo[] usages) { + Set elementsToMakeWritable = new HashSet<>(); Collections.addAll(elementsToMakeWritable, myClassesToMove); elementsToMakeWritable.add(myTargetClass); for (UsageInfo usage : usages) { @@ -203,22 +211,19 @@ private boolean prepareWritable(final UsageInfo[] usages) { elementsToMakeWritable.add(element); } } - if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, PsiUtilBase.toPsiElementArray(elementsToMakeWritable))) { - return false; - } - return true; + return CommonRefactoringUtil.checkReadOnlyStatus(myProject, PsiUtilBase.toPsiElementArray(elementsToMakeWritable)); } - private void saveNonCodeUsages(final UsageInfo[] usages) { + @RequiredReadAction + private void saveNonCodeUsages(UsageInfo[] usages) { for (PsiClass classToMove : myClassesToMove) { for (UsageInfo usageInfo : usages) { - if (usageInfo instanceof NonCodeUsageInfo) { - final NonCodeUsageInfo nonCodeUsage = (NonCodeUsageInfo)usageInfo; + if (usageInfo instanceof NonCodeUsageInfo nonCodeUsage) { PsiElement element = nonCodeUsage.getElement(); if (element != null && PsiTreeUtil.isAncestor(classToMove, element, false)) { List list = element.getCopyableUserData(ourNonCodeUsageKey); if (list == null) { - list = new ArrayList(); + list = new ArrayList<>(); element.putCopyableUserData(ourNonCodeUsageKey, list); } list.add(nonCodeUsage); @@ -228,19 +233,22 @@ private void saveNonCodeUsages(final UsageInfo[] usages) { } } + @Override + @RequiredWriteAction protected void performPsiSpoilingRefactoring() { if (myNonCodeUsages != null) { RenameUtil.renameNonCodeUsages(myProject, myNonCodeUsages); } if (myMoveCallback != null) { - if (myMoveCallback instanceof MoveClassesOrPackagesCallback) { - ((MoveClassesOrPackagesCallback)myMoveCallback).classesMovedToInner(myTargetClass); + if (myMoveCallback instanceof MoveClassesOrPackagesCallback moveClassesOrPackagesCallback) { + moveClassesOrPackagesCallback.classesMovedToInner(myTargetClass); } myMoveCallback.refactoringCompleted(); } } @Nonnull + @Override protected String getCommandName() { return RefactoringLocalize.moveClassToInnerCommandName( (myClassesToMove.length > 1 ? "classes " : "class ") + StringUtil.join( @@ -253,18 +261,20 @@ protected String getCommandName() { } @Nonnull - protected Collection getElementsToWrite(@Nonnull final UsageViewDescriptor descriptor) { - List result = new ArrayList(); + @Override + protected Collection getElementsToWrite(@Nonnull UsageViewDescriptor descriptor) { + List result = new ArrayList<>(); result.addAll(super.getElementsToWrite(descriptor)); result.add(myTargetClass); return result; } - public MultiMap getConflicts(final UsageInfo[] usages) { - MultiMap conflicts = new MultiMap(); + @RequiredReadAction + public MultiMap getConflicts(UsageInfo[] usages) { + MultiMap conflicts = new MultiMap<>(); for (PsiClass classToMove : myClassesToMove) { - final PsiClass innerClass = myTargetClass.findInnerClassByName(classToMove.getName(), false); + PsiClass innerClass = myTargetClass.findInnerClassByName(classToMove.getName(), false); if (innerClass != null) { conflicts.putValue( innerClass, @@ -300,7 +310,8 @@ public MultiMap getConflicts(final UsageInfo[] usages) { return conflicts; } - private void detectInaccessibleClassUsages(final UsageInfo[] usages, final ConflictsCollector collector, final String visibility) { + @RequiredReadAction + private void detectInaccessibleClassUsages(UsageInfo[] usages, ConflictsCollector collector, String visibility) { for (UsageInfo usage : usages) { if (usage instanceof MoveRenameUsageInfo && !(usage instanceof NonCodeUsageInfo)) { PsiElement element = usage.getElement(); @@ -314,37 +325,37 @@ private void detectInaccessibleClassUsages(final UsageInfo[] usages, final Confl } } - private boolean isInaccessibleFromTarget(final PsiElement element, final String visibility) { - final PsiJavaPackage elementPackage = + private boolean isInaccessibleFromTarget(PsiElement element, String visibility) { + PsiJavaPackage elementPackage = JavaDirectoryService.getInstance().getPackage(element.getContainingFile().getContainingDirectory()); return !PsiUtil.isAccessible(myTargetClass, element, null) || (!myTargetClass.isInterface() && visibility.equals(PsiModifier.PACKAGE_LOCAL) && !Comparing.equal(elementPackage, myTargetPackage)); } - private void detectInaccessibleMemberUsages(final ConflictsCollector collector) { + private void detectInaccessibleMemberUsages(ConflictsCollector collector) { PsiElement[] members = collectPackageLocalMembers(collector.getClassToMove()); for (PsiElement member : members) { - ReferencesSearch.search(member).forEach(new Processor() { - public boolean process(final PsiReference psiReference) { - PsiElement element = psiReference.getElement(); - for (PsiClass psiClass : myClassesToMove) { - if (PsiTreeUtil.isAncestor(psiClass, element, false)) { - return true; - } - } - if (isInaccessibleFromTarget(element, PsiModifier.PACKAGE_LOCAL)) { - collector.addConflict(psiReference.resolve(), element); + ReferencesSearch.search(member).forEach(psiReference -> { + PsiElement element = psiReference.getElement(); + for (PsiClass psiClass : myClassesToMove) { + if (PsiTreeUtil.isAncestor(psiClass, element, false)) { + return true; } - return true; } + if (isInaccessibleFromTarget(element, PsiModifier.PACKAGE_LOCAL)) { + collector.addConflict(psiReference.resolve(), element); + } + return true; }); } } + @RequiredReadAction private static PsiElement[] collectPackageLocalMembers(PsiElement classToMove) { - return PsiTreeUtil.collectElements(classToMove, new PsiElementFilter() { - public boolean isAccepted(final PsiElement element) { + return PsiTreeUtil.collectElements( + classToMove, + element -> { if (element instanceof PsiMember) { PsiMember member = (PsiMember)element; if (VisibilityUtil.getVisibilityModifier(member.getModifierList()) == PsiModifier.PACKAGE_LOCAL) { @@ -353,31 +364,32 @@ public boolean isAccepted(final PsiElement element) { } return false; } - }); + ); } private static class ConflictsCollector { private final PsiClass myClassToMove; private final MultiMap myConflicts; - private final Set myReportedContainers = new HashSet(); + private final Set myReportedContainers = new HashSet<>(); - public ConflictsCollector(PsiClass classToMove, final MultiMap conflicts) { + public ConflictsCollector(PsiClass classToMove, MultiMap conflicts) { myClassToMove = classToMove; myConflicts = conflicts; } - public synchronized void addConflict(final PsiElement targetElement, final PsiElement sourceElement) { + @RequiredReadAction + public synchronized void addConflict(PsiElement targetElement, PsiElement sourceElement) { PsiElement container = ConflictsUtil.getContainer(sourceElement); if (!myReportedContainers.contains(container)) { myReportedContainers.add(container); String targetDescription = (targetElement == myClassToMove) ? "Class " + CommonRefactoringUtil.htmlEmphasize(myClassToMove.getName()) : StringUtil.capitalize(RefactoringUIUtil.getDescription(targetElement, true)); - final String message = RefactoringLocalize.elementWillNoLongerBeAccessible( + LocalizeValue message = RefactoringLocalize.elementWillNoLongerBeAccessible( targetDescription, RefactoringUIUtil.getDescription(container, true) - ).get(); - myConflicts.putValue(targetElement, message); + ); + myConflicts.putValue(targetElement, message.get()); } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesImpl.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesImpl.java index 655d61e933..7ebdd5f268 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesImpl.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesImpl.java @@ -60,7 +60,7 @@ import consulo.usage.UsageInfo; import consulo.util.collection.MultiMap; import consulo.util.lang.Comparing; -import consulo.util.lang.ref.Ref; +import consulo.util.lang.ref.SimpleReference; import consulo.virtualFileSystem.VirtualFile; import jakarta.annotation.Nullable; @@ -71,26 +71,27 @@ public class MoveClassesOrPackagesImpl { private static final Logger LOG = Logger.getInstance(MoveClassesOrPackagesImpl.class); + @RequiredUIAccess public static void doMove( - final Project project, + Project project, PsiElement[] adjustedElements, PsiElement initialTargetElement, - final MoveCallback moveCallback + MoveCallback moveCallback ) { if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, Arrays.asList(adjustedElements), true)) { return; } - final String initialTargetPackageName = getInitialTargetPackageName(initialTargetElement, adjustedElements); - final PsiDirectory initialTargetDirectory = getInitialTargetDirectory(initialTargetElement, adjustedElements); - final boolean isTargetDirectoryFixed = initialTargetDirectory == null; + String initialTargetPackageName = getInitialTargetPackageName(initialTargetElement, adjustedElements); + PsiDirectory initialTargetDirectory = getInitialTargetDirectory(initialTargetElement, adjustedElements); + boolean isTargetDirectoryFixed = initialTargetDirectory == null; boolean searchTextOccurences = false; for (int i = 0; i < adjustedElements.length && !searchTextOccurences; i++) { PsiElement psiElement = adjustedElements[i]; searchTextOccurences = TextOccurrencesUtil.isSearchTextOccurencesEnabled(psiElement); } - final MoveClassesOrPackagesDialog moveDialog = + MoveClassesOrPackagesDialog moveDialog = new MoveClassesOrPackagesDialog(project, searchTextOccurences, adjustedElements, initialTargetElement, moveCallback); boolean searchInComments = JavaRefactoringSettings.getInstance().MOVE_SEARCH_IN_COMMENTS; boolean searchForTextOccurences = JavaRefactoringSettings.getInstance().MOVE_SEARCH_FOR_TEXT; @@ -109,15 +110,15 @@ public static void doMove( @Nullable @RequiredUIAccess - public static PsiElement[] adjustForMove(final Project project, final PsiElement[] elements, final PsiElement targetElement) { - final PsiElement[] psiElements = new PsiElement[elements.length]; - List names = new ArrayList(); + public static PsiElement[] adjustForMove(Project project, PsiElement[] elements, PsiElement targetElement) { + PsiElement[] psiElements = new PsiElement[elements.length]; + List names = new ArrayList<>(); for (int idx = 0; idx < elements.length; idx++) { PsiElement element = elements[idx]; if (element instanceof PsiDirectory directory) { PsiJavaPackage aPackage = JavaDirectoryService.getInstance().getPackage(directory); LOG.assertTrue(aPackage != null); - if (aPackage.getQualifiedName().length() == 0) { //is default package + if (aPackage.getQualifiedName().isEmpty()) { //is default package String message = RefactoringLocalize.movePackageRefactoringCannotBeAppliedToDefaultPackage().get(); CommonRefactoringUtil.showErrorMessage( RefactoringLocalize.moveTitle().get(), @@ -210,10 +211,10 @@ private static boolean isAlreadyChecked(PsiElement[] psiElements, int idx, PsiJa @RequiredUIAccess private static boolean checkMovePackage(Project project, PsiJavaPackage aPackage) { - final PsiDirectory[] directories = aPackage.getDirectories(); - final VirtualFile[] virtualFiles = aPackage.occursInPackagePrefixes(); + PsiDirectory[] directories = aPackage.getDirectories(); + VirtualFile[] virtualFiles = aPackage.occursInPackagePrefixes(); if (directories.length > 1 || virtualFiles.length > 0) { - final StringBuffer message = new StringBuffer(); + StringBuffer message = new StringBuffer(); RenameUtil.buildPackagePrefixChangedMessage(virtualFiles, message, aPackage.getQualifiedName()); if (directories.length > 1) { DirectoryAsPackageRenameHandlerBase.buildMultipleDirectoriesInPackageMessage( @@ -238,8 +239,8 @@ private static boolean checkMovePackage(Project project, PsiJavaPackage aPackage } @RequiredUIAccess - static boolean checkNesting(final Project project, final PsiJavaPackage srcPackage, final PsiElement targetElement, boolean showError) { - final PsiJavaPackage targetPackage = targetElement instanceof PsiJavaPackage javaPackage + static boolean checkNesting(Project project, PsiJavaPackage srcPackage, PsiElement targetElement, boolean showError) { + PsiJavaPackage targetPackage = targetElement instanceof PsiJavaPackage javaPackage ? javaPackage : targetElement instanceof PsiDirectory directory ? JavaDirectoryService.getInstance().getPackage(directory) @@ -259,14 +260,14 @@ static boolean checkNesting(final Project project, final PsiJavaPackage srcPacka return true; } - public static String getInitialTargetPackageName(PsiElement initialTargetElement, final PsiElement[] movedElements) { + public static String getInitialTargetPackageName(PsiElement initialTargetElement, PsiElement[] movedElements) { String name = getContainerPackageName(initialTargetElement); if (name == null) { if (movedElements != null) { name = getTargetPackageNameForMovedElement(movedElements[0]); } if (name == null) { - final PsiDirectory commonDirectory = getCommonDirectory(movedElements); + PsiDirectory commonDirectory = getCommonDirectory(movedElements); if (commonDirectory != null && JavaDirectoryService.getInstance().getPackage(commonDirectory) != null) { name = JavaDirectoryService.getInstance().getPackage(commonDirectory).getQualifiedName(); } @@ -283,9 +284,9 @@ private static PsiDirectory getCommonDirectory(PsiElement[] movedElements) { PsiDirectory commonDirectory = null; for (PsiElement movedElement : movedElements) { - final PsiFile containingFile = movedElement.getContainingFile(); + PsiFile containingFile = movedElement.getContainingFile(); if (containingFile != null) { - final PsiDirectory containingDirectory = containingFile.getContainingDirectory(); + PsiDirectory containingDirectory = containingFile.getContainingDirectory(); if (containingDirectory != null) { if (commonDirectory == null) { commonDirectory = containingDirectory; @@ -306,7 +307,7 @@ private static PsiDirectory getCommonDirectory(PsiElement[] movedElements) { } } - private static String getContainerPackageName(final PsiElement psiElement) { + private static String getContainerPackageName(PsiElement psiElement) { if (psiElement instanceof PsiJavaPackage javaPackage) { return javaPackage.getQualifiedName(); } @@ -324,9 +325,9 @@ else if (psiElement != null) { } } - private static String getTargetPackageNameForMovedElement(final PsiElement psiElement) { + private static String getTargetPackageNameForMovedElement(PsiElement psiElement) { if (psiElement instanceof PsiJavaPackage psiPackage) { - final PsiJavaPackage parentPackage = psiPackage.getParentPackage(); + PsiJavaPackage parentPackage = psiPackage.getParentPackage(); return parentPackage != null ? parentPackage.getQualifiedName() : ""; } else if (psiElement instanceof PsiDirectory directory) { @@ -344,11 +345,11 @@ else if (psiElement != null) { } - public static PsiDirectory getInitialTargetDirectory(PsiElement initialTargetElement, final PsiElement[] movedElements) { + public static PsiDirectory getInitialTargetDirectory(PsiElement initialTargetElement, PsiElement[] movedElements) { PsiDirectory initialTargetDirectory = getContainerDirectory(initialTargetElement); if (initialTargetDirectory == null) { if (movedElements != null) { - final PsiDirectory commonDirectory = getCommonDirectory(movedElements); + PsiDirectory commonDirectory = getCommonDirectory(movedElements); if (commonDirectory != null) { initialTargetDirectory = commonDirectory; } @@ -361,9 +362,9 @@ public static PsiDirectory getInitialTargetDirectory(PsiElement initialTargetEle } @Nullable - public static PsiDirectory getContainerDirectory(final PsiElement psiElement) { + public static PsiDirectory getContainerDirectory(PsiElement psiElement) { if (psiElement instanceof PsiJavaPackage javaPackage) { - final PsiDirectory[] directories = javaPackage.getDirectories(); + PsiDirectory[] directories = javaPackage.getDirectories(); return directories.length == 1 ? directories[0] : null; //?? } if (psiElement instanceof PsiDirectory directory) { @@ -376,7 +377,7 @@ public static PsiDirectory getContainerDirectory(final PsiElement psiElement) { } @RequiredUIAccess - public static void doRearrangePackage(final Project project, final PsiDirectory[] directories) { + public static void doRearrangePackage(Project project, PsiDirectory[] directories) { if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, Arrays.asList(directories), true)) { return; } @@ -389,19 +390,18 @@ public static void doRearrangePackage(final Project project, final PsiDirectory[ if (!chooser.isOK()) { return; } - final PsiDirectory selectedTarget = chooser.getSelectedDirectory(); + PsiDirectory selectedTarget = chooser.getSelectedDirectory(); if (selectedTarget == null) { return; } - final MultiMap conflicts = new MultiMap<>(); - final Runnable analyzeConflicts = () -> - RefactoringConflictsUtil.analyzeModuleConflicts( - project, - Arrays.asList(directories), - UsageInfo.EMPTY_ARRAY, - selectedTarget, - conflicts - ); + MultiMap conflicts = new MultiMap<>(); + Runnable analyzeConflicts = () -> RefactoringConflictsUtil.analyzeModuleConflicts( + project, + Arrays.asList(directories), + UsageInfo.EMPTY_ARRAY, + selectedTarget, + conflicts + ); if (!ProgressManager.getInstance() .runProcessWithProgressSynchronously(analyzeConflicts, "Analyze Module Conflicts...", true, project)) { return; @@ -411,15 +411,16 @@ public static void doRearrangePackage(final Project project, final PsiDirectory[ throw new BaseRefactoringProcessor.ConflictsInTestsException(conflicts.values()); } else { - final ConflictsDialog conflictsDialog = new ConflictsDialog(project, conflicts); + ConflictsDialog conflictsDialog = new ConflictsDialog(project, conflicts); conflictsDialog.show(); if (!conflictsDialog.isOK()) { return; } } } - final Ref ex = Ref.create(null); - final String commandDescription = RefactoringLocalize.movingDirectoriesCommand().get(); + SimpleReference ex = SimpleReference.create(); + String commandDescription = RefactoringLocalize.movingDirectoriesCommand().get(); + @RequiredUIAccess Runnable runnable = () -> project.getApplication().runWriteAction(() -> { LocalHistoryAction a = LocalHistory.getInstance().startAction(commandDescription); try { @@ -433,27 +434,27 @@ public static void doRearrangePackage(final Project project, final PsiDirectory[ } }); CommandProcessor.getInstance().executeCommand(project, runnable, commandDescription, null); - if (ex.get() != null) { + if (!ex.isNull()) { RefactoringUIUtil.processIncorrectOperation(project, ex.get()); } } @RequiredUIAccess - private static List buildRearrangeTargetsList(final Project project, final PsiDirectory[] directories) { - final VirtualFile[] sourceRoots = ProjectRootManager.getInstance(project).getContentSourceRoots(); + private static List buildRearrangeTargetsList(Project project, PsiDirectory[] directories) { + VirtualFile[] sourceRoots = ProjectRootManager.getInstance(project).getContentSourceRoots(); List sourceRootDirectories = new ArrayList<>(); sourceRoots: - for (final VirtualFile sourceRoot : sourceRoots) { + for (VirtualFile sourceRoot : sourceRoots) { PsiDirectory sourceRootDirectory = PsiManager.getInstance(project).findDirectory(sourceRoot); if (sourceRootDirectory == null) { continue; } - final PsiJavaPackage aPackage = JavaDirectoryService.getInstance().getPackage(sourceRootDirectory); + PsiJavaPackage aPackage = JavaDirectoryService.getInstance().getPackage(sourceRootDirectory); if (aPackage == null) { continue; } - final String packagePrefix = aPackage.getQualifiedName(); - for (final PsiDirectory directory : directories) { + String packagePrefix = aPackage.getQualifiedName(); + for (PsiDirectory directory : directories) { String qualifiedName = JavaDirectoryService.getInstance().getPackage(directory).getQualifiedName(); if (!qualifiedName.startsWith(packagePrefix)) { continue sourceRoots; @@ -466,11 +467,11 @@ private static List buildRearrangeTargetsList(final Project projec private static void rearrangeDirectoriesToTarget(PsiDirectory[] directories, PsiDirectory selectedTarget) throws IncorrectOperationException { - final VirtualFile sourceRoot = selectedTarget.getVirtualFile(); + VirtualFile sourceRoot = selectedTarget.getVirtualFile(); for (PsiDirectory directory : directories) { - final PsiJavaPackage parentPackage = JavaDirectoryService.getInstance().getPackage(directory).getParentPackage(); - final PackageWrapper wrapper = new PackageWrapper(parentPackage); - final PsiDirectory moveTarget = RefactoringUtil.createPackageDirectoryInSourceRoot(wrapper, sourceRoot); + PsiJavaPackage parentPackage = JavaDirectoryService.getInstance().getPackage(directory).getParentPackage(); + PackageWrapper wrapper = new PackageWrapper(parentPackage); + PsiDirectory moveTarget = RefactoringUtil.createPackageDirectoryInSourceRoot(wrapper, sourceRoot); MoveClassesOrPackagesUtil.moveDirectoryRecursively(directory, moveTarget); } } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java index 1c09cb5689..2a10f551e6 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java @@ -28,6 +28,7 @@ import com.intellij.java.language.psi.util.PsiUtil; import com.intellij.java.language.util.VisibilityUtil; import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; import consulo.language.editor.refactoring.BaseRefactoringProcessor; import consulo.language.editor.refactoring.event.RefactoringElementListener; import consulo.language.editor.refactoring.localize.RefactoringLocalize; @@ -69,21 +70,20 @@ public class MoveClassesOrPackagesProcessor extends BaseRefactoringProcessor { private boolean mySearchInNonJavaFiles; private final PackageWrapper myTargetPackage; private final MoveCallback myMoveCallback; - protected @Nonnull - final MoveDestination myMoveDestination; + protected final MoveDestination myMoveDestination; protected NonCodeUsageInfo[] myNonCodeUsages; public MoveClassesOrPackagesProcessor( Project project, PsiElement[] elements, - @Nonnull final MoveDestination moveDestination, + @Nonnull MoveDestination moveDestination, boolean searchInComments, boolean searchInNonJavaFiles, MoveCallback moveCallback ) { super(project); - final Set toMove = new LinkedHashSet<>(); + Set toMove = new LinkedHashSet<>(); for (PsiElement element : elements) { if (element instanceof PsiClassOwner classOwner) { Collections.addAll(toMove, classOwner.getClasses()); @@ -95,11 +95,11 @@ public MoveClassesOrPackagesProcessor( myElementsToMove = PsiUtilCore.toPsiElementArray(toMove); Arrays.sort(myElementsToMove, (o1, o2) -> { if (o1 instanceof PsiClass class1 && o2 instanceof PsiClass class2) { - final PsiFile containingFile = o1.getContainingFile(); + PsiFile containingFile = o1.getContainingFile(); if (Comparing.equal(containingFile, o2.getContainingFile())) { - final VirtualFile virtualFile = containingFile.getVirtualFile(); + VirtualFile virtualFile = containingFile.getVirtualFile(); if (virtualFile != null) { - final String fileName = virtualFile.getNameWithoutExtension(); + String fileName = virtualFile.getNameWithoutExtension(); if (Comparing.strEqual(fileName, class1.getName())) { return -1; } @@ -178,11 +178,11 @@ protected UsageInfo[] findUsages() { if (newName == null) { continue; } - final UsageInfo[] usages = MoveClassesOrPackagesUtil.findUsages(element, mySearchInComments, mySearchInNonJavaFiles, newName); + UsageInfo[] usages = MoveClassesOrPackagesUtil.findUsages(element, mySearchInComments, mySearchInNonJavaFiles, newName); allUsages.addAll(new ArrayList<>(Arrays.asList(usages))); if (element instanceof PsiJavaPackage javaPackage) { for (PsiDirectory directory : javaPackage.getDirectories()) { - final UsageInfo[] dirUsages = + UsageInfo[] dirUsages = MoveClassesOrPackagesUtil.findUsages(directory, mySearchInComments, mySearchInNonJavaFiles, newName); allUsages.addAll(new ArrayList<>(Arrays.asList(dirUsages))); } @@ -193,7 +193,7 @@ protected UsageInfo[] findUsages() { conflicts, allUsages.toArray(new UsageInfo[allUsages.size()]) ); - final UsageInfo[] usageInfos = allUsages.toArray(new UsageInfo[allUsages.size()]); + UsageInfo[] usageInfos = allUsages.toArray(new UsageInfo[allUsages.size()]); detectPackageLocalsMoved(usageInfos, conflicts); detectPackageLocalsUsed(conflicts); if (!conflicts.isEmpty()) { @@ -226,13 +226,14 @@ public Collection getConflicts() { } } + @RequiredUIAccess protected boolean preprocessUsages(Ref refUsages) { - final UsageInfo[] usages = refUsages.get(); - final MultiMap conflicts = new MultiMap<>(); + UsageInfo[] usages = refUsages.get(); + MultiMap conflicts = new MultiMap<>(); ArrayList filteredUsages = new ArrayList<>(); for (UsageInfo usage : usages) { if (usage instanceof ConflictsUsageInfo info) { - final PsiElement element = info.getElement(); + PsiElement element = info.getElement(); conflicts.putValues(element, info.getConflicts()); } else { @@ -253,7 +254,7 @@ private boolean isInsideMoved(PsiElement place) { return false; } - private void detectPackageLocalsUsed(final MultiMap conflicts) { + private void detectPackageLocalsUsed(MultiMap conflicts) { PackageLocalsUsageCollector visitor = new PackageLocalsUsageCollector(myElementsToMove, myTargetPackage, conflicts); for (PsiElement element : myElementsToMove) { @@ -264,11 +265,11 @@ private void detectPackageLocalsUsed(final MultiMap conflict } @RequiredReadAction - private void detectPackageLocalsMoved(final UsageInfo[] usages, final MultiMap conflicts) { -// final HashSet reportedPackageLocalUsed = new HashSet(); - final HashSet movedClasses = new HashSet<>(); - final HashMap> reportedClassToContainers = new HashMap<>(); - final PackageWrapper aPackage = myTargetPackage; + private void detectPackageLocalsMoved(UsageInfo[] usages, MultiMap conflicts) { +// Set reportedPackageLocalUsed = new HashSet(); + Set movedClasses = new HashSet<>(); + Map> reportedClassToContainers = new HashMap<>(); + PackageWrapper aPackage = myTargetPackage; for (UsageInfo usage : usages) { PsiElement element = usage.getElement(); if (element == null) { @@ -299,8 +300,7 @@ private void detectPackageLocalsMoved(final UsageInfo[] usages, final MultiMap

{ - final PsiElement element = reference.getElement(); + PsiElement element = reference.getElement(); if (element instanceof PsiReferenceExpression expression) { - final PsiExpression qualifierExpression = expression.getQualifierExpression(); + PsiExpression qualifierExpression = expression.getQualifierExpression(); if (qualifierExpression != null) { - final PsiType type = qualifierExpression.getType(); + PsiType type = qualifierExpression.getType(); if (type != null) { - final PsiClass resolvedTypeClass = PsiUtil.resolveClassInType(type); + PsiClass resolvedTypeClass = PsiUtil.resolveClassInType(type); if (isDescendantOf.value(resolvedTypeClass)) { instanceReferenceVisitor.visitMemberReference(memberWrapper.getMember(), expression, isDescendantOf); } @@ -405,16 +401,18 @@ private static void findPublicClassConflicts(PsiClass aClass, final MyClassInsta } private static void findInstancesOfPackageLocal( - final PsiClass aClass, - final UsageInfo[] usages, - final MyClassInstanceReferenceVisitor instanceReferenceVisitor + PsiClass aClass, + UsageInfo[] usages, + MyClassInstanceReferenceVisitor instanceReferenceVisitor ) { ClassReferenceScanner referenceScanner = new ClassReferenceScanner(aClass) { + @Override + @RequiredReadAction public PsiReference[] findReferences() { ArrayList result = new ArrayList<>(); for (UsageInfo usage : usages) { if (usage instanceof MoveRenameUsageInfo moveRenameUsageInfo && moveRenameUsageInfo.getReferencedElement() == aClass) { - final PsiReference reference = usage.getReference(); + PsiReference reference = usage.getReference(); if (reference != null) { result.add(reference); } @@ -430,9 +428,9 @@ public PsiReference[] findReferences() { @Nullable @RequiredReadAction private String getNewQName(PsiElement element) { - final String qualifiedName = myTargetPackage.getQualifiedName(); - final String newQName; - final String oldQName; + String qualifiedName = myTargetPackage.getQualifiedName(); + String newQName; + String oldQName; if (element instanceof PsiClass psiClass) { newQName = StringUtil.getQualifiedName(qualifiedName, psiClass.getName()); oldQName = psiClass.getQualifiedName(); @@ -452,11 +450,13 @@ else if (element instanceof PsiJavaPackage javaPackage) { return newQName; } + @Override protected void refreshElements(PsiElement[] elements) { LOG.assertTrue(elements.length == myElementsToMove.length); System.arraycopy(elements, 0, myElementsToMove, 0, elements.length); } + @Override protected boolean isPreviewUsages(@Nonnull UsageInfo[] usages) { if (UsageViewUtil.hasNonCodeUsages(usages)) { WindowManager.getInstance().getStatusBar(myProject) @@ -468,6 +468,8 @@ protected boolean isPreviewUsages(@Nonnull UsageInfo[] usages) { } } + @Override + @RequiredWriteAction protected void performRefactoring(@Nonnull UsageInfo[] usages) { // If files are being moved then I need to collect some information to delete these // filese from CVS. I need to know all common parents of the moved files and releative @@ -476,7 +478,7 @@ protected void performRefactoring(@Nonnull UsageInfo[] usages) { // Move files with correction of references. try { - final Map allClasses = new HashMap<>(); + Map allClasses = new HashMap<>(); for (PsiElement element : myElementsToMove) { if (element instanceof PsiClass psiClass) { if (allClasses.containsKey(psiClass)) { @@ -487,17 +489,17 @@ protected void performRefactoring(@Nonnull UsageInfo[] usages) { } } } - final Map oldToNewElementsMapping = new HashMap<>(); + Map oldToNewElementsMapping = new HashMap<>(); for (int idx = 0; idx < myElementsToMove.length; idx++) { PsiElement element = myElementsToMove[idx]; - final RefactoringElementListener elementListener = getTransaction().getElementListener(element); + RefactoringElementListener elementListener = getTransaction().getElementListener(element); if (element instanceof PsiJavaPackage javaPackage) { - final PsiDirectory[] directories = javaPackage.getDirectories(); - final PsiJavaPackage newElement = MoveClassesOrPackagesUtil.doMovePackage(javaPackage, myMoveDestination); + PsiDirectory[] directories = javaPackage.getDirectories(); + PsiJavaPackage newElement = MoveClassesOrPackagesUtil.doMovePackage(javaPackage, myMoveDestination); LOG.assertTrue(newElement != null, element); oldToNewElementsMapping.put(element, newElement); int i = 0; - final PsiDirectory[] newDirectories = newElement.getDirectories(); + PsiDirectory[] newDirectories = newElement.getDirectories(); if (newDirectories.length == 1) {//everything is moved in one directory for (PsiDirectory directory : directories) { oldToNewElementsMapping.put(directory, newDirectories[0]); @@ -512,7 +514,7 @@ protected void performRefactoring(@Nonnull UsageInfo[] usages) { } else if (element instanceof PsiClass psiClass) { MoveClassesOrPackagesUtil.prepareMoveClass(psiClass); - final PsiClass newElement = MoveClassesOrPackagesUtil.doMoveClass( + PsiClass newElement = MoveClassesOrPackagesUtil.doMoveClass( psiClass, myMoveDestination.getTargetDirectory(element.getContainingFile()), allClasses.get(psiClass) @@ -541,6 +543,8 @@ else if (element instanceof PsiClass psiClass) { } } + @Override + @RequiredWriteAction protected void performPsiSpoilingRefactoring() { RenameUtil.renameNonCodeUsages(myProject, myNonCodeUsages); if (myMoveCallback != null) { @@ -552,6 +556,7 @@ protected void performPsiSpoilingRefactoring() { } @Nonnull + @Override protected String getCommandName() { String elements = RefactoringUIUtil.calculatePsiElementDescriptionList(myElementsToMove); String target = myTargetPackage.getQualifiedName(); @@ -567,6 +572,7 @@ public MyClassInstanceReferenceVisitor(MultiMap conflicts) { myConflicts = conflicts; } + @Override @RequiredReadAction public void visitQualifier( PsiReferenceExpression qualified, @@ -576,7 +582,7 @@ public void visitQualifier( PsiElement resolved = qualified.resolve(); if (resolved instanceof PsiMember member) { - final PsiClass containingClass = member.getContainingClass(); + PsiClass containingClass = member.getContainingClass(); RefactoringUtil.IsDescendantOf isDescendantOf = myIsDescendantOfCache.get(containingClass); if (isDescendantOf == null) { isDescendantOf = new RefactoringUtil.IsDescendantOf(containingClass); @@ -587,15 +593,15 @@ public void visitQualifier( } private synchronized void visitMemberReference( - final PsiModifierListOwner member, + PsiModifierListOwner member, PsiReferenceExpression qualified, - final RefactoringUtil.IsDescendantOf descendantOf + RefactoringUtil.IsDescendantOf descendantOf ) { if (member.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) { visitPackageLocalMemberReference(qualified, member); } else if (member.hasModifierProperty(PsiModifier.PROTECTED)) { - final PsiExpression qualifier = qualified.getQualifierExpression(); + PsiExpression qualifier = qualified.getQualifierExpression(); if (qualifier != null && !(qualifier instanceof PsiThisExpression) && !(qualifier instanceof PsiSuperExpression)) { visitPackageLocalMemberReference(qualified, member); } @@ -605,7 +611,7 @@ else if (!isInInheritor(qualified, descendantOf)) { } } - private boolean isInInheritor(PsiReferenceExpression qualified, final RefactoringUtil.IsDescendantOf descendantOf) { + private boolean isInInheritor(PsiReferenceExpression qualified, RefactoringUtil.IsDescendantOf descendantOf) { PsiClass aClass = PsiTreeUtil.getParentOfType(qualified, PsiClass.class); while (aClass != null) { if (descendantOf.value(aClass)) { @@ -645,25 +651,25 @@ private void visitPackageLocalMemberReference(PsiJavaCodeReferenceElement qualif } } + @Override public void visitTypeCast(PsiTypeCastExpression typeCastExpression, PsiExpression instanceRef, PsiElement referencedInstance) { } + @Override public void visitReadUsage(PsiExpression instanceRef, PsiType expectedType, PsiElement referencedInstance) { } + @Override public void visitWriteUsage(PsiExpression instanceRef, PsiType assignedType, PsiElement referencedInstance) { } } private static class NonPublicClassMemberWrappersSet extends HashSet { public void addElement(PsiMember member) { - final PsiNamedElement namedElement = (PsiNamedElement)member; - if (member.hasModifierProperty(PsiModifier.PUBLIC)) { - return; - } - if (member.hasModifierProperty(PsiModifier.PRIVATE)) { + if (member.isPublic() || member.isPrivate()) { return; } + PsiNamedElement namedElement = (PsiNamedElement)member; add(new ClassMemberWrapper(namedElement)); } diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesUtil.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesUtil.java index 304ba939a5..cc66ed8148 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesUtil.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesUtil.java @@ -19,8 +19,8 @@ import com.intellij.java.impl.refactoring.PackageWrapper; import com.intellij.java.impl.refactoring.util.RefactoringUtil; import com.intellij.java.language.psi.*; -import consulo.application.ApplicationManager; -import consulo.application.util.function.Computable; +import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; import consulo.document.util.TextRange; import consulo.ide.impl.idea.openapi.vfs.VfsUtil; import consulo.ide.util.DirectoryChooserUtil; @@ -34,15 +34,17 @@ import consulo.module.content.ProjectFileIndex; import consulo.module.content.ProjectRootManager; import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; import consulo.usage.MoveRenameUsageInfo; import consulo.usage.UsageInfo; -import consulo.usage.UsageViewBundle; +import consulo.usage.localize.UsageLocalize; import consulo.virtualFileSystem.VirtualFile; - +import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import java.io.File; import java.util.*; +import java.util.function.Supplier; public class MoveClassesOrPackagesUtil { private static final Logger LOG = Logger.getInstance(MoveClassesOrPackagesUtil.class); @@ -50,16 +52,17 @@ public class MoveClassesOrPackagesUtil { private MoveClassesOrPackagesUtil() { } + @RequiredReadAction public static UsageInfo[] findUsages( - final PsiElement element, + PsiElement element, boolean searchInStringsAndComments, boolean searchInNonJavaFiles, - final String newQName + String newQName ) { PsiManager manager = element.getManager(); - ArrayList results = new ArrayList(); - Set foundReferences = new HashSet(); + ArrayList results = new ArrayList<>(); + Set foundReferences = new HashSet<>(); GlobalSearchScope projectScope = GlobalSearchScope.projectScope(manager.getProject()); for (PsiReference reference : ReferencesSearch.search(element, projectScope, false)) { @@ -92,11 +95,11 @@ private static void preprocessUsages(ArrayList results) { public static void findNonCodeUsages( boolean searchInStringsAndComments, boolean searchInNonJavaFiles, - final PsiElement element, - final String newQName, + PsiElement element, + String newQName, ArrayList results ) { - final String stringToSearch = getStringToSearch(element); + String stringToSearch = getStringToSearch(element); if (stringToSearch == null) { return; } @@ -120,11 +123,12 @@ else if (element instanceof PsiDirectory) { } // Does not process non-code usages! + @RequiredWriteAction public static PsiJavaPackage doMovePackage(PsiJavaPackage aPackage, MoveDestination moveDestination) throws IncorrectOperationException { - final PackageWrapper targetPackage = moveDestination.getTargetPackage(); + PackageWrapper targetPackage = moveDestination.getTargetPackage(); - final String newPrefix; + String newPrefix; if ("".equals(targetPackage.getQualifiedName())) { newPrefix = ""; } @@ -132,13 +136,13 @@ public static PsiJavaPackage doMovePackage(PsiJavaPackage aPackage, MoveDestinat newPrefix = targetPackage.getQualifiedName() + "."; } - final String newPackageQualifiedName = newPrefix + aPackage.getName(); + String newPackageQualifiedName = newPrefix + aPackage.getName(); // do actual move - final GlobalSearchScope projectScope = GlobalSearchScope.projectScope(aPackage.getProject()); + GlobalSearchScope projectScope = GlobalSearchScope.projectScope(aPackage.getProject()); PsiDirectory[] dirs = aPackage.getDirectories(projectScope); for (PsiDirectory dir : dirs) { - final PsiDirectory targetDirectory = moveDestination.getTargetDirectory(dir); + PsiDirectory targetDirectory = moveDestination.getTargetDirectory(dir); if (targetDirectory != null) { moveDirectoryRecursively(dir, targetDirectory); } @@ -149,32 +153,33 @@ public static PsiJavaPackage doMovePackage(PsiJavaPackage aPackage, MoveDestinat return JavaPsiFacade.getInstance(targetPackage.getManager().getProject()).findPackage(newPackageQualifiedName); } + @RequiredWriteAction public static void moveDirectoryRecursively(PsiDirectory dir, PsiDirectory destination) throws IncorrectOperationException { if (dir.getParentDirectory() == destination) { return; } - moveDirectoryRecursively(dir, destination, new HashSet()); + moveDirectoryRecursively(dir, destination, new HashSet<>()); } - private static void moveDirectoryRecursively(PsiDirectory dir, PsiDirectory destination, HashSet movedPaths) + @RequiredWriteAction + private static void moveDirectoryRecursively(PsiDirectory dir, PsiDirectory destination, Set movedPaths) throws IncorrectOperationException { - final PsiManager manager = dir.getManager(); - final VirtualFile destVFile = destination.getVirtualFile(); - final VirtualFile sourceVFile = dir.getVirtualFile(); + VirtualFile destVFile = destination.getVirtualFile(); + VirtualFile sourceVFile = dir.getVirtualFile(); if (movedPaths.contains(sourceVFile)) { return; } String targetName = dir.getName(); - final PsiJavaPackage aPackage = JavaDirectoryService.getInstance().getPackage(dir); + PsiJavaPackage aPackage = JavaDirectoryService.getInstance().getPackage(dir); if (aPackage != null) { - final String sourcePackageName = aPackage.getName(); + String sourcePackageName = aPackage.getName(); if (!sourcePackageName.equals(targetName)) { targetName = sourcePackageName; } } - final PsiDirectory subdirectoryInDest; - final boolean isSourceRoot = RefactoringUtil.isSourceRoot(dir); + PsiDirectory subdirectoryInDest; + boolean isSourceRoot = RefactoringUtil.isSourceRoot(dir); if (VfsUtil.isAncestor(sourceVFile, destVFile, false) || isSourceRoot) { PsiDirectory exitsingSubdir = destination.findSubdirectory(targetName); if (exitsingSubdir == null) { @@ -195,7 +200,7 @@ private static void moveDirectoryRecursively(PsiDirectory dir, PsiDirectory dest movedPaths.add(virtualFile); } else { - final PsiFile[] files = dir.getFiles(); + PsiFile[] files = dir.getFiles(); for (PsiFile file : files) { try { subdirectoryInDest.checkAdd(file); @@ -206,7 +211,7 @@ private static void moveDirectoryRecursively(PsiDirectory dir, PsiDirectory dest MoveFilesOrDirectoriesUtil.doMoveFile(file, subdirectoryInDest); } - final PsiDirectory[] subdirectories = dir.getSubdirectories(); + PsiDirectory[] subdirectories = dir.getSubdirectories(); for (PsiDirectory subdirectory : subdirectories) { if (!subdirectory.equals(subdirectoryInDest)) { moveDirectoryRecursively(subdirectory, subdirectoryInDest, movedPaths); @@ -231,11 +236,13 @@ public static void finishMoveClass(PsiClass aClass) { } // Does not process non-code usages! + @RequiredWriteAction public static PsiClass doMoveClass(PsiClass aClass, PsiDirectory moveDestination) throws IncorrectOperationException { return doMoveClass(aClass, moveDestination, true); } // Does not process non-code usages! + @RequiredWriteAction public static PsiClass doMoveClass(PsiClass aClass, PsiDirectory moveDestination, boolean moveAllClassesInFile) throws IncorrectOperationException { PsiClass newClass; @@ -249,17 +256,17 @@ public static PsiClass doMoveClass(PsiClass aClass, PsiDirectory moveDestination } PsiFile file = aClass.getContainingFile(); - final PsiJavaPackage newPackage = JavaDirectoryService.getInstance().getPackage(moveDestination); + PsiJavaPackage newPackage = JavaDirectoryService.getInstance().getPackage(moveDestination); newClass = aClass; if (!moveDestination.equals(file.getContainingDirectory())) { LOG.assertTrue(file.getVirtualFile() != null, aClass); MoveFilesOrDirectoriesUtil.doMoveFile(file, moveDestination); - if (file instanceof PsiClassOwner && newPackage != null /*&& !JspPsiUtil.isInJspFile(file)*/) { + if (file instanceof PsiClassOwner classOwner && newPackage != null /*&& !JspPsiUtil.isInJspFile(file)*/) { // Do not rely on class instance identity retention after setPackageName (Scala) String aClassName = aClass.getName(); - ((PsiClassOwner)file).setPackageName(newPackage.getQualifiedName()); - newClass = findClassByName((PsiClassOwner)file, aClassName); + classOwner.setPackageName(newPackage.getQualifiedName()); + newClass = findClassByName(classOwner, aClassName); LOG.assertTrue(newClass != null); } } @@ -267,6 +274,7 @@ public static PsiClass doMoveClass(PsiClass aClass, PsiDirectory moveDestination } @Nullable + @RequiredReadAction private static PsiClass findClassByName(PsiClassOwner file, String name) { PsiClass[] classes = file.getClasses(); for (PsiClass aClass : classes) { @@ -286,63 +294,59 @@ public static String getPackageName(PackageWrapper aPackage) { return name; } else { - return UsageViewBundle.message("default.package.presentable.name"); + return UsageLocalize.defaultPackagePresentableName().get(); } } @Nullable - public static PsiDirectory chooseDestinationPackage(Project project, String packageName, @Nullable PsiDirectory baseDir) { - final PsiManager psiManager = PsiManager.getInstance(project); - final PackageWrapper packageWrapper = new PackageWrapper(psiManager, packageName); - final PsiJavaPackage aPackage = JavaPsiFacade.getInstance(project).findPackage(packageName); + @RequiredUIAccess + public static PsiDirectory chooseDestinationPackage(@Nonnull Project project, String packageName, @Nullable PsiDirectory baseDir) { + PsiManager psiManager = PsiManager.getInstance(project); + PackageWrapper packageWrapper = new PackageWrapper(psiManager, packageName); + PsiJavaPackage aPackage = JavaPsiFacade.getInstance(project).findPackage(packageName); PsiDirectory directory; PsiDirectory[] directories = aPackage != null ? aPackage.getDirectories() : null; - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); - final boolean filterOutSources = baseDir != null && fileIndex.isInTestSourceContent(baseDir.getVirtualFile()); + ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); + boolean filterOutSources = baseDir != null && fileIndex.isInTestSourceContent(baseDir.getVirtualFile()); if (directories != null && directories.length == 1 && !(filterOutSources && !fileIndex.isInTestSourceContent(directories[0].getVirtualFile()))) { directory = directories[0]; } else { - final VirtualFile[] contentSourceRoots = ProjectRootManager.getInstance(project).getContentSourceRoots(); + VirtualFile[] contentSourceRoots = ProjectRootManager.getInstance(project).getContentSourceRoots(); if (contentSourceRoots.length == 1 && !(filterOutSources && !fileIndex.isInTestSourceContent(contentSourceRoots[0]))) { - directory = ApplicationManager.getApplication().runWriteAction(new Computable() { - @Override - public PsiDirectory compute() { - return RefactoringUtil.createPackageDirectoryInSourceRoot(packageWrapper, contentSourceRoots[0]); - } - }); + directory = project.getApplication().runWriteAction( + (Supplier)() -> RefactoringUtil.createPackageDirectoryInSourceRoot(packageWrapper, contentSourceRoots[0]) + ); } else { - final VirtualFile sourceRootForFile = chooseSourceRoot(packageWrapper, contentSourceRoots, baseDir); + VirtualFile sourceRootForFile = chooseSourceRoot(packageWrapper, contentSourceRoots, baseDir); if (sourceRootForFile == null) { return null; } - directory = ApplicationManager.getApplication().runWriteAction(new Computable() { - @Override - public PsiDirectory compute() { - return new AutocreatingSingleSourceRootMoveDestination(packageWrapper, sourceRootForFile) - .getTargetDirectory((PsiDirectory)null); - } - }); + directory = project.getApplication().runWriteAction( + (Supplier)() -> new AutocreatingSingleSourceRootMoveDestination(packageWrapper, sourceRootForFile) + .getTargetDirectory((PsiDirectory)null) + ); } } return directory; } + @RequiredReadAction public static VirtualFile chooseSourceRoot( - final PackageWrapper targetPackage, - final VirtualFile[] contentSourceRoots, - final PsiDirectory initialDirectory + PackageWrapper targetPackage, + VirtualFile[] contentSourceRoots, + PsiDirectory initialDirectory ) { Project project = targetPackage.getManager().getProject(); //ensure that there would be no duplicates: e.g. when one content root is subfolder of another root (configured via excluded roots) - LinkedHashSet targetDirectories = new LinkedHashSet(); - Map relativePathsToCreate = new HashMap(); + Set targetDirectories = new LinkedHashSet<>(); + Map relativePathsToCreate = new HashMap<>(); buildDirectoryList(targetPackage, contentSourceRoots, targetDirectories, relativePathsToCreate); - final PsiDirectory selectedDirectory = DirectoryChooserUtil.chooseDirectory( + PsiDirectory selectedDirectory = DirectoryChooserUtil.chooseDirectory( targetDirectories.toArray(new PsiDirectory[targetDirectories.size()]), initialDirectory, project, @@ -352,21 +356,22 @@ public static VirtualFile chooseSourceRoot( if (selectedDirectory == null) { return null; } - final VirtualFile virt = selectedDirectory.getVirtualFile(); - final VirtualFile sourceRootForFile = ProjectRootManager.getInstance(project).getFileIndex().getSourceRootForFile(virt); + VirtualFile virt = selectedDirectory.getVirtualFile(); + VirtualFile sourceRootForFile = ProjectRootManager.getInstance(project).getFileIndex().getSourceRootForFile(virt); LOG.assertTrue(sourceRootForFile != null); return sourceRootForFile; } + @RequiredReadAction public static void buildDirectoryList( PackageWrapper aPackage, VirtualFile[] contentSourceRoots, - LinkedHashSet targetDirectories, + Set targetDirectories, Map relativePathsToCreate ) { sourceRoots: for (VirtualFile root : contentSourceRoots) { - final PsiDirectory[] directories = aPackage.getDirectories(); + PsiDirectory[] directories = aPackage.getDirectories(); for (PsiDirectory directory : directories) { if (VfsUtil.isAncestor(root, directory.getVirtualFile(), false)) { targetDirectories.add(directory); @@ -384,13 +389,13 @@ public static void buildDirectoryList( if (currentDirectory == null) { continue; } - final String[] shortNames = qNameToCreate.split("\\."); + String[] shortNames = qNameToCreate.split("\\."); for (int j = 0; j < shortNames.length; j++) { String shortName = shortNames[j]; - final PsiDirectory subdirectory = currentDirectory.findSubdirectory(shortName); + PsiDirectory subdirectory = currentDirectory.findSubdirectory(shortName); if (subdirectory == null) { targetDirectories.add(currentDirectory); - final StringBuffer postfix = new StringBuffer(); + StringBuffer postfix = new StringBuffer(); for (int k = j; k < shortNames.length; k++) { String name = shortNames[k]; postfix.append(File.separatorChar);