From 657561cfc36516db3d9eb7c49f1c48e275931632 Mon Sep 17 00:00:00 2001 From: UNV Date: Fri, 2 May 2025 04:54:59 +0300 Subject: [PATCH 1/4] Reformatting users of EP_NAME. --- .../impl/analysis/GenericsHighlightUtil.java | 3148 ++++++++++------- .../impl/analysis/HighlightClassUtil.java | 2059 ++++++----- .../quickfix/QualifySuperArgumentFix.java | 68 +- 3 files changed, 2927 insertions(+), 2348 deletions(-) diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index cf05f41d1e..33a75216b4 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -53,1512 +53,1924 @@ import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import java.util.*; /** * @author cdr */ public class GenericsHighlightUtil { - private static final Logger LOG = Logger.getInstance(GenericsHighlightUtil.class); - - private GenericsHighlightUtil() { - } - - @Nullable - public static HighlightInfo checkInferredTypeArguments(PsiTypeParameterListOwner listOwner, PsiElement call, PsiSubstitutor substitutor) { - return checkInferredTypeArguments(listOwner.getTypeParameters(), call, substitutor); - } - - @Nullable - private static HighlightInfo checkInferredTypeArguments(PsiTypeParameter[] typeParameters, PsiElement call, PsiSubstitutor substitutor) { - final Pair inferredTypeArgument = GenericsUtil.findTypeParameterWithBoundError(typeParameters, substitutor, call, false); - if (inferredTypeArgument != null) { - final PsiType extendsType = inferredTypeArgument.second; - final PsiTypeParameter typeParameter = inferredTypeArgument.first; - PsiClass boundClass = extendsType instanceof PsiClassType ? ((PsiClassType) extendsType).resolve() : null; - - @NonNls String messageKey = boundClass == null || typeParameter.isInterface() == boundClass.isInterface() ? "generics.inferred.type.for.type.parameter.is.not.within.its.bound.extend" : - "generics.inferred.type.for.type.parameter.is.not.within.its.bound.implement"; - - String description = JavaErrorBundle.message(messageKey, HighlightUtil.formatClass(typeParameter), JavaHighlightUtil.formatType(extendsType), JavaHighlightUtil.formatType(substitutor - .substitute(typeParameter))); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(call).descriptionAndTooltip(description).create(); + private static final Logger LOG = Logger.getInstance(GenericsHighlightUtil.class); + + private GenericsHighlightUtil() { + } + + @Nullable + public static HighlightInfo checkInferredTypeArguments( + PsiTypeParameterListOwner listOwner, + PsiElement call, + PsiSubstitutor substitutor + ) { + return checkInferredTypeArguments(listOwner.getTypeParameters(), call, substitutor); + } + + @Nullable + private static HighlightInfo checkInferredTypeArguments( + PsiTypeParameter[] typeParameters, + PsiElement call, + PsiSubstitutor substitutor + ) { + final Pair inferredTypeArgument = + GenericsUtil.findTypeParameterWithBoundError(typeParameters, substitutor, call, false); + if (inferredTypeArgument != null) { + final PsiType extendsType = inferredTypeArgument.second; + final PsiTypeParameter typeParameter = inferredTypeArgument.first; + PsiClass boundClass = extendsType instanceof PsiClassType ? ((PsiClassType)extendsType).resolve() : null; + + @NonNls String messageKey = boundClass == null || typeParameter.isInterface() == boundClass.isInterface() + ? "generics.inferred.type.for.type.parameter.is.not.within.its.bound.extend" + : "generics.inferred.type.for.type.parameter.is.not.within.its.bound.implement"; + + String description = JavaErrorBundle.message( + messageKey, + HighlightUtil.formatClass(typeParameter), + JavaHighlightUtil.formatType(extendsType), + JavaHighlightUtil.formatType(substitutor.substitute(typeParameter)) + ); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(call) + .descriptionAndTooltip(description) + .create(); + } + + return null; } - return null; - } + @Nullable + public static HighlightInfo checkParameterizedReferenceTypeArguments( + final PsiElement resolved, + final PsiJavaCodeReferenceElement referenceElement, + final PsiSubstitutor substitutor, + @Nonnull JavaSdkVersion javaSdkVersion + ) { + if (!(resolved instanceof PsiTypeParameterListOwner)) { + return null; + } + final PsiTypeParameterListOwner typeParameterListOwner = (PsiTypeParameterListOwner)resolved; + return checkReferenceTypeArgumentList( + typeParameterListOwner, + referenceElement.getParameterList(), + substitutor, + true, + javaSdkVersion + ); + } + + @Nullable + public static HighlightInfo checkReferenceTypeArgumentList( + final PsiTypeParameterListOwner typeParameterListOwner, + final PsiReferenceParameterList referenceParameterList, + final PsiSubstitutor substitutor, + boolean registerIntentions, + @Nonnull JavaSdkVersion javaSdkVersion + ) { + PsiDiamondType.DiamondInferenceResult inferenceResult = null; + PsiTypeElement[] referenceElements = null; + if (referenceParameterList != null) { + referenceElements = referenceParameterList.getTypeParameterElements(); + if (referenceElements.length == 1 && referenceElements[0].getType() instanceof PsiDiamondType) { + if (!typeParameterListOwner.hasTypeParameters()) { + final String description = JavaErrorBundle.message("generics.diamond.not.applicable"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(referenceParameterList) + .descriptionAndTooltip(description) + .create(); + } + inferenceResult = ((PsiDiamondType)referenceElements[0].getType()).resolveInferredTypes(); + final String errorMessage = inferenceResult.getErrorMessage(); + if (errorMessage != null) { + final PsiType expectedType = detectExpectedType(referenceParameterList); + if (!(inferenceResult.failedToInfer() && expectedType instanceof PsiClassType && ((PsiClassType)expectedType).isRaw())) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(referenceParameterList) + .descriptionAndTooltip(errorMessage) + .create(); + } + } + } + } + + final PsiTypeParameter[] typeParameters = typeParameterListOwner.getTypeParameters(); + final int targetParametersNum = typeParameters.length; + final int refParametersNum = referenceParameterList == null ? 0 : referenceParameterList.getTypeArguments().length; + if (targetParametersNum != refParametersNum && refParametersNum != 0) { + final String description; + if (targetParametersNum == 0) { + if (PsiTreeUtil.getParentOfType(referenceParameterList, PsiCall.class) != null && + typeParameterListOwner instanceof PsiMethod && + (javaSdkVersion.isAtLeast(JavaSdkVersion.JDK_1_7) || hasSuperMethodsWithTypeParams((PsiMethod)typeParameterListOwner))) { + description = null; + } + else { + description = JavaErrorBundle.message( + "generics.type.or.method.does.not.have.type.parameters", + typeParameterListOwnerCategoryDescription(typeParameterListOwner), + typeParameterListOwnerDescription(typeParameterListOwner) + ); + } + } + else { + description = JavaErrorBundle.message("generics.wrong.number.of.type.arguments", refParametersNum, targetParametersNum); + } + + if (description != null) { + final HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(referenceParameterList) + .descriptionAndTooltip(description) + .create(); + if (registerIntentions) { + if (typeParameterListOwner instanceof PsiClass) { + QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance() + .createChangeClassSignatureFromUsageFix((PsiClass)typeParameterListOwner, referenceParameterList)); + } + + PsiElement grandParent = referenceParameterList.getParent().getParent(); + if (grandParent instanceof PsiTypeElement) { + PsiElement variable = grandParent.getParent(); + if (variable instanceof PsiVariable) { + if (targetParametersNum == 0) { + QuickFixAction.registerQuickFixAction( + highlightInfo, + QuickFixFactory.getInstance().createRemoveTypeArgumentsFix(variable) + ); + } + registerVariableParameterizedTypeFixes( + highlightInfo, + (PsiVariable)variable, + referenceParameterList, + javaSdkVersion + ); + } + } + } + return highlightInfo; + } + } + + // bounds check + if (targetParametersNum > 0 && refParametersNum != 0) { + if (inferenceResult != null) { + final PsiType[] types = inferenceResult.getTypes(); + for (int i = 0; i < typeParameters.length; i++) { + final PsiType type = types[i]; + final HighlightInfo highlightInfo = checkTypeParameterWithinItsBound( + typeParameters[i], + substitutor, + type, + referenceElements[0], + referenceParameterList + ); + if (highlightInfo != null) { + return highlightInfo; + } + } + } + else { + for (int i = 0; i < typeParameters.length; i++) { + final PsiTypeElement typeElement = referenceElements[i]; + final HighlightInfo highlightInfo = checkTypeParameterWithinItsBound( + typeParameters[i], + substitutor, + typeElement.getType(), + typeElement, + referenceParameterList + ); + if (highlightInfo != null) { + return highlightInfo; + } + } + } + } - @Nullable - public static HighlightInfo checkParameterizedReferenceTypeArguments(final PsiElement resolved, - final PsiJavaCodeReferenceElement referenceElement, - final PsiSubstitutor substitutor, - @Nonnull JavaSdkVersion javaSdkVersion) { - if (!(resolved instanceof PsiTypeParameterListOwner)) { - return null; + return null; } - final PsiTypeParameterListOwner typeParameterListOwner = (PsiTypeParameterListOwner) resolved; - return checkReferenceTypeArgumentList(typeParameterListOwner, referenceElement.getParameterList(), substitutor, true, javaSdkVersion); - } - - @Nullable - public static HighlightInfo checkReferenceTypeArgumentList(final PsiTypeParameterListOwner typeParameterListOwner, - final PsiReferenceParameterList referenceParameterList, - final PsiSubstitutor substitutor, - boolean registerIntentions, - @Nonnull JavaSdkVersion javaSdkVersion) { - PsiDiamondType.DiamondInferenceResult inferenceResult = null; - PsiTypeElement[] referenceElements = null; - if (referenceParameterList != null) { - referenceElements = referenceParameterList.getTypeParameterElements(); - if (referenceElements.length == 1 && referenceElements[0].getType() instanceof PsiDiamondType) { - if (!typeParameterListOwner.hasTypeParameters()) { - final String description = JavaErrorBundle.message("generics.diamond.not.applicable"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(referenceParameterList).descriptionAndTooltip(description).create(); - } - inferenceResult = ((PsiDiamondType) referenceElements[0].getType()).resolveInferredTypes(); - final String errorMessage = inferenceResult.getErrorMessage(); - if (errorMessage != null) { - final PsiType expectedType = detectExpectedType(referenceParameterList); - if (!(inferenceResult.failedToInfer() && expectedType instanceof PsiClassType && ((PsiClassType) expectedType).isRaw())) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(referenceParameterList).descriptionAndTooltip(errorMessage).create(); - } - } - } + + private static boolean hasSuperMethodsWithTypeParams(PsiMethod method) { + for (PsiMethod superMethod : method.findDeepestSuperMethods()) { + if (superMethod.hasTypeParameters()) { + return true; + } + } + return false; } - final PsiTypeParameter[] typeParameters = typeParameterListOwner.getTypeParameters(); - final int targetParametersNum = typeParameters.length; - final int refParametersNum = referenceParameterList == null ? 0 : referenceParameterList.getTypeArguments().length; - if (targetParametersNum != refParametersNum && refParametersNum != 0) { - final String description; - if (targetParametersNum == 0) { - if (PsiTreeUtil.getParentOfType(referenceParameterList, PsiCall.class) != null && - typeParameterListOwner instanceof PsiMethod && - (javaSdkVersion.isAtLeast(JavaSdkVersion.JDK_1_7) || hasSuperMethodsWithTypeParams((PsiMethod) typeParameterListOwner))) { - description = null; - } else { - description = JavaErrorBundle.message("generics.type.or.method.does.not.have.type.parameters", typeParameterListOwnerCategoryDescription(typeParameterListOwner), - typeParameterListOwnerDescription(typeParameterListOwner)); - } - } else { - description = JavaErrorBundle.message("generics.wrong.number.of.type.arguments", refParametersNum, targetParametersNum); - } - - if (description != null) { - final HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(referenceParameterList).descriptionAndTooltip(description).create(); - if (registerIntentions) { - if (typeParameterListOwner instanceof PsiClass) { - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance() - .createChangeClassSignatureFromUsageFix((PsiClass) typeParameterListOwner, referenceParameterList)); - } - - PsiElement grandParent = referenceParameterList.getParent().getParent(); - if (grandParent instanceof PsiTypeElement) { - PsiElement variable = grandParent.getParent(); - if (variable instanceof PsiVariable) { - if (targetParametersNum == 0) { - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance().createRemoveTypeArgumentsFix(variable)); - } - registerVariableParameterizedTypeFixes(highlightInfo, (PsiVariable) variable, referenceParameterList, javaSdkVersion); - } - } + private static PsiType detectExpectedType(PsiReferenceParameterList referenceParameterList) { + final PsiNewExpression newExpression = PsiTreeUtil.getParentOfType(referenceParameterList, PsiNewExpression.class); + LOG.assertTrue(newExpression != null); + final PsiElement parent = newExpression.getParent(); + PsiType expectedType = null; + if (parent instanceof PsiVariable && newExpression.equals(((PsiVariable)parent).getInitializer())) { + expectedType = ((PsiVariable)parent).getType(); } - return highlightInfo; - } + else if (parent instanceof PsiAssignmentExpression && newExpression.equals(((PsiAssignmentExpression)parent).getRExpression())) { + expectedType = ((PsiAssignmentExpression)parent).getLExpression().getType(); + } + else if (parent instanceof PsiReturnStatement) { + PsiElement method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class, PsiLambdaExpression.class); + if (method instanceof PsiMethod) { + expectedType = ((PsiMethod)method).getReturnType(); + } + } + else if (parent instanceof PsiExpressionList) { + final PsiElement pParent = parent.getParent(); + if (pParent instanceof PsiCallExpression && parent.equals(((PsiCallExpression)pParent).getArgumentList())) { + final PsiMethod method = ((PsiCallExpression)pParent).resolveMethod(); + if (method != null) { + final PsiExpression[] expressions = ((PsiCallExpression)pParent).getArgumentList().getExpressions(); + final int idx = ArrayUtil.find(expressions, newExpression); + if (idx > -1) { + final PsiParameterList parameterList = method.getParameterList(); + if (idx < parameterList.getParametersCount()) { + expectedType = parameterList.getParameters()[idx].getType(); + } + } + } + } + } + return expectedType; + } + + @Nullable + private static HighlightInfo checkTypeParameterWithinItsBound( + PsiTypeParameter classParameter, + final PsiSubstitutor substitutor, + final PsiType type, + final PsiElement typeElement2Highlight, + PsiReferenceParameterList referenceParameterList + ) { + final PsiClass referenceClass = type instanceof PsiClassType ? ((PsiClassType)type).resolve() : null; + final PsiType psiType = substitutor.substitute(classParameter); + if (psiType instanceof PsiClassType && !(PsiUtil.resolveClassInType(psiType) instanceof PsiTypeParameter)) { + if (GenericsUtil.checkNotInBounds(type, psiType, referenceParameterList)) { + final String description = "Actual type argument and inferred type contradict each other"; + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeElement2Highlight) + .descriptionAndTooltip(description) + .create(); + } + } + + final PsiClassType[] bounds = classParameter.getSuperTypes(); + for (PsiClassType type1 : bounds) { + PsiType bound = substitutor.substitute(type1); + if (!bound.equalsToText(JavaClassNames.JAVA_LANG_OBJECT) && GenericsUtil.checkNotInBounds( + type, + bound, + referenceParameterList + )) { + PsiClass boundClass = bound instanceof PsiClassType ? ((PsiClassType)bound).resolve() : null; + + @NonNls final String messageKey = + boundClass == null || referenceClass == null || referenceClass.isInterface() == boundClass.isInterface() ? "generics.type.parameter.is.not.within" + + ".its.bound.extend" : "generics.type.parameter.is.not.within.its.bound.implement"; + + String description = JavaErrorBundle.message( + messageKey, + referenceClass != null ? HighlightUtil.formatClass(referenceClass) : type.getPresentableText(), + JavaHighlightUtil + .formatType(bound) + ); + + final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeElement2Highlight) + .descriptionAndTooltip(description) + .create(); + if (bound instanceof PsiClassType && referenceClass != null && info != null) { + QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance() + .createExtendsListFix(referenceClass, (PsiClassType)bound, true), null); + } + return info; + } + } + return null; } - // bounds check - if (targetParametersNum > 0 && refParametersNum != 0) { - if (inferenceResult != null) { - final PsiType[] types = inferenceResult.getTypes(); - for (int i = 0; i < typeParameters.length; i++) { - final PsiType type = types[i]; - final HighlightInfo highlightInfo = checkTypeParameterWithinItsBound(typeParameters[i], substitutor, type, referenceElements[0], referenceParameterList); - if (highlightInfo != null) { - return highlightInfo; - } + private static String typeParameterListOwnerDescription(final PsiTypeParameterListOwner typeParameterListOwner) { + if (typeParameterListOwner instanceof PsiClass) { + return HighlightUtil.formatClass((PsiClass)typeParameterListOwner); } - } else { - for (int i = 0; i < typeParameters.length; i++) { - final PsiTypeElement typeElement = referenceElements[i]; - final HighlightInfo highlightInfo = checkTypeParameterWithinItsBound(typeParameters[i], substitutor, typeElement.getType(), typeElement, referenceParameterList); - if (highlightInfo != null) { - return highlightInfo; - } + else if (typeParameterListOwner instanceof PsiMethod) { + return JavaHighlightUtil.formatMethod((PsiMethod)typeParameterListOwner); + } + else { + LOG.error("Unknown " + typeParameterListOwner); + return "?"; } - } } - return null; - } + private static String typeParameterListOwnerCategoryDescription(final PsiTypeParameterListOwner typeParameterListOwner) { + if (typeParameterListOwner instanceof PsiClass) { + return JavaErrorBundle.message("generics.holder.type"); + } + else if (typeParameterListOwner instanceof PsiMethod) { + return JavaErrorBundle.message("generics.holder.method"); + } + else { + LOG.error("Unknown " + typeParameterListOwner); + return "?"; + } + } - private static boolean hasSuperMethodsWithTypeParams(PsiMethod method) { - for (PsiMethod superMethod : method.findDeepestSuperMethods()) { - if (superMethod.hasTypeParameters()) { - return true; - } + @Nullable + public static HighlightInfo checkElementInTypeParameterExtendsList( + @Nonnull PsiReferenceList referenceList, + @Nonnull PsiClass aClass, + @Nonnull JavaResolveResult resolveResult, + @Nonnull PsiElement element + ) { + final PsiJavaCodeReferenceElement[] referenceElements = referenceList.getReferenceElements(); + PsiClass extendFrom = (PsiClass)resolveResult.getElement(); + if (extendFrom == null) { + return null; + } + HighlightInfo errorResult = null; + if (!extendFrom.isInterface() && referenceElements.length != 0 && element != referenceElements[0]) { + String description = JavaErrorBundle.message("interface.expected"); + errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(element) + .descriptionAndTooltip(description) + .create(); + PsiClassType type = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory() + .createType(extendFrom, resolveResult.getSubstitutor()); + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createMoveBoundClassToFrontFix(aClass, type), + null + ); + } + else if (referenceElements.length != 0 && element != referenceElements[0] + && referenceElements[0].resolve() instanceof PsiTypeParameter) { + final String description = JavaErrorBundle.message("type.parameter.cannot.be.followed.by.other.bounds"); + errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(element) + .descriptionAndTooltip(description) + .create(); + PsiClassType type = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory() + .createType(extendFrom, resolveResult.getSubstitutor()); + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createExtendsListFix(aClass, type, false), + null + ); + } + return errorResult; } - return false; - } - - private static PsiType detectExpectedType(PsiReferenceParameterList referenceParameterList) { - final PsiNewExpression newExpression = PsiTreeUtil.getParentOfType(referenceParameterList, PsiNewExpression.class); - LOG.assertTrue(newExpression != null); - final PsiElement parent = newExpression.getParent(); - PsiType expectedType = null; - if (parent instanceof PsiVariable && newExpression.equals(((PsiVariable) parent).getInitializer())) { - expectedType = ((PsiVariable) parent).getType(); - } else if (parent instanceof PsiAssignmentExpression && newExpression.equals(((PsiAssignmentExpression) parent).getRExpression())) { - expectedType = ((PsiAssignmentExpression) parent).getLExpression().getType(); - } else if (parent instanceof PsiReturnStatement) { - PsiElement method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class, PsiLambdaExpression.class); - if (method instanceof PsiMethod) { - expectedType = ((PsiMethod) method).getReturnType(); - } - } else if (parent instanceof PsiExpressionList) { - final PsiElement pParent = parent.getParent(); - if (pParent instanceof PsiCallExpression && parent.equals(((PsiCallExpression) pParent).getArgumentList())) { - final PsiMethod method = ((PsiCallExpression) pParent).resolveMethod(); - if (method != null) { - final PsiExpression[] expressions = ((PsiCallExpression) pParent).getArgumentList().getExpressions(); - final int idx = ArrayUtil.find(expressions, newExpression); - if (idx > -1) { - final PsiParameterList parameterList = method.getParameterList(); - if (idx < parameterList.getParametersCount()) { - expectedType = parameterList.getParameters()[idx].getType(); - } - } - } - } + + public static HighlightInfo checkInterfaceMultipleInheritance(PsiClass aClass) { + final PsiClassType[] types = aClass.getSuperTypes(); + if (types.length < 2) { + return null; + } + Map inheritedClasses = new HashMap<>(); + final TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); + return checkInterfaceMultipleInheritance(aClass, aClass, PsiSubstitutor.EMPTY, inheritedClasses, new HashSet<>(), textRange); + } + + private static HighlightInfo checkInterfaceMultipleInheritance( + PsiClass aClass, + PsiElement place, + PsiSubstitutor derivedSubstitutor, + Map inheritedClasses, + Set visited, + TextRange textRange + ) { + final List superTypes = + PsiClassImplUtil.getScopeCorrectedSuperTypes(aClass, place.getResolveScope()); + for (PsiClassType.ClassResolveResult result : superTypes) { + final PsiClass superClass = result.getElement(); + if (superClass == null || visited.contains(superClass)) { + continue; + } + PsiSubstitutor superTypeSubstitutor = result.getSubstitutor(); + superTypeSubstitutor = MethodSignatureUtil.combineSubstitutors(superTypeSubstitutor, derivedSubstitutor); + + final PsiSubstitutor inheritedSubstitutor = inheritedClasses.get(superClass); + if (inheritedSubstitutor != null) { + final PsiTypeParameter[] typeParameters = superClass.getTypeParameters(); + for (PsiTypeParameter typeParameter : typeParameters) { + PsiType type1 = inheritedSubstitutor.substitute(typeParameter); + PsiType type2 = superTypeSubstitutor.substitute(typeParameter); + + if (!Comparing.equal(type1, type2)) { + String description = JavaErrorBundle.message( + "generics.cannot.be.inherited.with.different.type.arguments", + HighlightUtil.formatClass(superClass), + JavaHighlightUtil + .formatType(type1), + JavaHighlightUtil.formatType(type2) + ); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(textRange) + .descriptionAndTooltip(description) + .create(); + } + } + } + inheritedClasses.put(superClass, superTypeSubstitutor); + visited.add(superClass); + final HighlightInfo highlightInfo = + checkInterfaceMultipleInheritance(superClass, place, superTypeSubstitutor, inheritedClasses, visited, textRange); + visited.remove(superClass); + + if (highlightInfo != null) { + return highlightInfo; + } + } + return null; } - return expectedType; - } - - @Nullable - private static HighlightInfo checkTypeParameterWithinItsBound(PsiTypeParameter classParameter, - final PsiSubstitutor substitutor, - final PsiType type, - final PsiElement typeElement2Highlight, - PsiReferenceParameterList referenceParameterList) { - final PsiClass referenceClass = type instanceof PsiClassType ? ((PsiClassType) type).resolve() : null; - final PsiType psiType = substitutor.substitute(classParameter); - if (psiType instanceof PsiClassType && !(PsiUtil.resolveClassInType(psiType) instanceof PsiTypeParameter)) { - if (GenericsUtil.checkNotInBounds(type, psiType, referenceParameterList)) { - final String description = "Actual type argument and inferred type contradict each other"; - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement2Highlight).descriptionAndTooltip(description).create(); - } + + @Nonnull + public static Collection checkOverrideEquivalentMethods(@Nonnull PsiClass aClass) { + List result = new ArrayList<>(); + final Collection signaturesWithSupers = aClass.getVisibleSignatures(); + PsiManager manager = aClass.getManager(); + Map sameErasureMethods = + Maps.newHashMap(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY); + + final Set foundProblems = Sets.newHashSet(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY); + for (HierarchicalMethodSignature signature : signaturesWithSupers) { + HighlightInfo info = checkSameErasureNotSubSignatureInner(signature, manager, aClass, sameErasureMethods); + if (info != null && foundProblems.add(signature)) { + result.add(info); + } + if (aClass instanceof PsiTypeParameter) { + info = HighlightMethodUtil.checkMethodIncompatibleReturnType( + signature, + signature.getSuperSignatures(), + true, + HighlightNamesUtil.getClassDeclarationTextRange(aClass) + ); + if (info != null) { + result.add(info); + } + } + } + + return result; + } + + public static HighlightInfo checkDefaultMethodOverrideEquivalentToObjectNonPrivate( + @Nonnull LanguageLevel languageLevel, + @Nonnull PsiClass aClass, + @Nonnull PsiMethod method, + @Nonnull PsiElement methodIdentifier + ) { + if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && aClass.isInterface() && method.hasModifierProperty(PsiModifier.DEFAULT)) { + HierarchicalMethodSignature sig = method.getHierarchicalMethodSignature(); + for (HierarchicalMethodSignature methodSignature : sig.getSuperSignatures()) { + final PsiMethod objectMethod = methodSignature.getMethod(); + final PsiClass containingClass = objectMethod.getContainingClass(); + if (containingClass != null && JavaClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) + && objectMethod.hasModifierProperty(PsiModifier.PUBLIC)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(methodIdentifier) + .descriptionAndTooltip("Default method '" + sig.getName() + "' overrides a member of 'java.lang.Object'") + .create(); + } + } + } + return null; } - final PsiClassType[] bounds = classParameter.getSuperTypes(); - for (PsiClassType type1 : bounds) { - PsiType bound = substitutor.substitute(type1); - if (!bound.equalsToText(JavaClassNames.JAVA_LANG_OBJECT) && GenericsUtil.checkNotInBounds(type, bound, referenceParameterList)) { - PsiClass boundClass = bound instanceof PsiClassType ? ((PsiClassType) bound).resolve() : null; + public static HighlightInfo checkUnrelatedDefaultMethods(@Nonnull PsiClass aClass, @Nonnull PsiIdentifier classIdentifier) { + final Map> overrideEquivalent = PsiSuperMethodUtil.collectOverrideEquivalents(aClass); - @NonNls final String messageKey = boundClass == null || referenceClass == null || referenceClass.isInterface() == boundClass.isInterface() ? "generics.type.parameter.is.not.within" + - ".its.bound.extend" : "generics.type.parameter.is.not.within.its.bound.implement"; + final boolean isInterface = aClass.isInterface(); + for (Set overrideEquivalentMethods : overrideEquivalent.values()) { + if (overrideEquivalentMethods.size() <= 1) { + continue; + } + List defaults = null; + List abstracts = null; + boolean hasConcrete = false; + for (PsiMethod method : overrideEquivalentMethods) { + final boolean isDefault = method.hasModifierProperty(PsiModifier.DEFAULT); + final boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT); + if (isDefault) { + if (defaults == null) { + defaults = new ArrayList<>(2); + } + defaults.add(method); + } + if (isAbstract) { + if (abstracts == null) { + abstracts = new ArrayList<>(2); + } + abstracts.add(method); + } + hasConcrete |= !isDefault && !isAbstract; + } - String description = JavaErrorBundle.message(messageKey, referenceClass != null ? HighlightUtil.formatClass(referenceClass) : type.getPresentableText(), JavaHighlightUtil - .formatType(bound)); + if (!hasConcrete && defaults != null) { + final PsiMethod defaultMethod = defaults.get(0); + if (MethodSignatureUtil.findMethodBySuperMethod(aClass, defaultMethod, false) != null) { + continue; + } + final PsiClass defaultMethodContainingClass = defaultMethod.getContainingClass(); + if (defaultMethodContainingClass == null) { + continue; + } + final PsiMethod unrelatedMethod = abstracts != null ? abstracts.get(0) : defaults.get(1); + final PsiClass unrelatedMethodContainingClass = unrelatedMethod.getContainingClass(); + if (unrelatedMethodContainingClass == null) { + continue; + } + if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT) && !(aClass instanceof PsiTypeParameter) + && abstracts != null && unrelatedMethodContainingClass.isInterface()) { + if (defaultMethodContainingClass.isInheritor(unrelatedMethodContainingClass, true) + && MethodSignatureUtil.isSubsignature( + unrelatedMethod.getSignature(TypeConversionUtil.getSuperClassSubstitutor( + unrelatedMethodContainingClass, + defaultMethodContainingClass, + PsiSubstitutor.EMPTY + )), + defaultMethod.getSignature(PsiSubstitutor.EMPTY) + ) + ) { + continue; + } + final String key = + aClass instanceof PsiEnumConstantInitializer ? "enum.constant.should.implement.method" : "class.must.be.abstract"; + final String message = JavaErrorBundle.message( + key, + HighlightUtil.formatClass(aClass, false), + JavaHighlightUtil.formatMethod(abstracts.get(0)), + HighlightUtil.formatClass(unrelatedMethodContainingClass, false) + ); + final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(classIdentifier) + .descriptionAndTooltip(message) + .create(); + QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createImplementMethodsFix(aClass)); + return info; + } + if (isInterface || abstracts == null || unrelatedMethodContainingClass.isInterface()) { + final List defaultContainingClasses = ContainerUtil.mapNotNull(defaults, PsiMethod::getContainingClass); + final String unrelatedDefaults = hasUnrelatedDefaults(defaultContainingClasses); + if (unrelatedDefaults == null && (abstracts == null || !hasNotOverriddenAbstract( + defaultContainingClasses, + unrelatedMethodContainingClass + ))) { + continue; + } - final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement2Highlight).descriptionAndTooltip(description).create(); - if (bound instanceof PsiClassType && referenceClass != null && info != null) { - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance() - .createExtendsListFix(referenceClass, (PsiClassType) bound, true), null); + final String message = + unrelatedDefaults != null ? " inherits unrelated defaults for " : " inherits abstract and default for "; + final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(classIdentifier) + .descriptionAndTooltip( + HighlightUtil.formatClass(aClass) + + message + + JavaHighlightUtil.formatMethod(defaultMethod) + " from types " + ( + unrelatedDefaults != null + ? unrelatedDefaults + : HighlightUtil.formatClass(defaultMethodContainingClass) + " and " + + HighlightUtil.formatClass(unrelatedMethodContainingClass) + ) + ) + .create(); + QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createImplementMethodsFix(aClass)); + return info; + } + } } - return info; - } - } - return null; - } - - private static String typeParameterListOwnerDescription(final PsiTypeParameterListOwner typeParameterListOwner) { - if (typeParameterListOwner instanceof PsiClass) { - return HighlightUtil.formatClass((PsiClass) typeParameterListOwner); - } else if (typeParameterListOwner instanceof PsiMethod) { - return JavaHighlightUtil.formatMethod((PsiMethod) typeParameterListOwner); - } else { - LOG.error("Unknown " + typeParameterListOwner); - return "?"; - } - } - - private static String typeParameterListOwnerCategoryDescription(final PsiTypeParameterListOwner typeParameterListOwner) { - if (typeParameterListOwner instanceof PsiClass) { - return JavaErrorBundle.message("generics.holder.type"); - } else if (typeParameterListOwner instanceof PsiMethod) { - return JavaErrorBundle.message("generics.holder.method"); - } else { - LOG.error("Unknown " + typeParameterListOwner); - return "?"; - } - } - - @Nullable - public static HighlightInfo checkElementInTypeParameterExtendsList(@Nonnull PsiReferenceList referenceList, - @Nonnull PsiClass aClass, - @Nonnull JavaResolveResult resolveResult, - @Nonnull PsiElement element) { - final PsiJavaCodeReferenceElement[] referenceElements = referenceList.getReferenceElements(); - PsiClass extendFrom = (PsiClass) resolveResult.getElement(); - if (extendFrom == null) { - return null; + return null; } - HighlightInfo errorResult = null; - if (!extendFrom.isInterface() && referenceElements.length != 0 && element != referenceElements[0]) { - String description = JavaErrorBundle.message("interface.expected"); - errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); - PsiClassType type = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(extendFrom, resolveResult.getSubstitutor()); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createMoveBoundClassToFrontFix(aClass, type), null); - } else if (referenceElements.length != 0 && element != referenceElements[0] && referenceElements[0].resolve() instanceof PsiTypeParameter) { - final String description = JavaErrorBundle.message("type.parameter.cannot.be.followed.by.other.bounds"); - errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); - PsiClassType type = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(extendFrom, resolveResult.getSubstitutor()); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createExtendsListFix(aClass, type, false), null); + + private static boolean belongToOneHierarchy( + @Nonnull PsiClass defaultMethodContainingClass, + @Nonnull PsiClass unrelatedMethodContainingClass + ) { + return defaultMethodContainingClass.isInheritor(unrelatedMethodContainingClass, true) || unrelatedMethodContainingClass.isInheritor( + defaultMethodContainingClass, + true + ); } - return errorResult; - } - public static HighlightInfo checkInterfaceMultipleInheritance(PsiClass aClass) { - final PsiClassType[] types = aClass.getSuperTypes(); - if (types.length < 2) { - return null; + private static boolean hasNotOverriddenAbstract( + List defaultContainingClasses, + @Nonnull PsiClass abstractMethodContainingClass + ) { + return defaultContainingClasses.stream() + .noneMatch(containingClass -> belongToOneHierarchy(containingClass, abstractMethodContainingClass)); } - Map inheritedClasses = new HashMap<>(); - final TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - return checkInterfaceMultipleInheritance(aClass, aClass, PsiSubstitutor.EMPTY, inheritedClasses, new HashSet<>(), textRange); - } - - private static HighlightInfo checkInterfaceMultipleInheritance(PsiClass aClass, - PsiElement place, - PsiSubstitutor derivedSubstitutor, - Map inheritedClasses, - Set visited, - TextRange textRange) { - final List superTypes = PsiClassImplUtil.getScopeCorrectedSuperTypes(aClass, place.getResolveScope()); - for (PsiClassType.ClassResolveResult result : superTypes) { - final PsiClass superClass = result.getElement(); - if (superClass == null || visited.contains(superClass)) { - continue; - } - PsiSubstitutor superTypeSubstitutor = result.getSubstitutor(); - superTypeSubstitutor = MethodSignatureUtil.combineSubstitutors(superTypeSubstitutor, derivedSubstitutor); - - final PsiSubstitutor inheritedSubstitutor = inheritedClasses.get(superClass); - if (inheritedSubstitutor != null) { - final PsiTypeParameter[] typeParameters = superClass.getTypeParameters(); - for (PsiTypeParameter typeParameter : typeParameters) { - PsiType type1 = inheritedSubstitutor.substitute(typeParameter); - PsiType type2 = superTypeSubstitutor.substitute(typeParameter); - - if (!Comparing.equal(type1, type2)) { - String description = JavaErrorBundle.message("generics.cannot.be.inherited.with.different.type.arguments", HighlightUtil.formatClass(superClass), JavaHighlightUtil - .formatType(type1), JavaHighlightUtil.formatType(type2)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - } + + private static String hasUnrelatedDefaults(List defaults) { + if (defaults.size() > 1) { + PsiClass[] defaultClasses = defaults.toArray(PsiClass.EMPTY_ARRAY); + ArrayList classes = new ArrayList<>(defaults); + for (final PsiClass aClass1 : defaultClasses) { + classes.removeIf(aClass2 -> aClass1.isInheritor(aClass2, true)); + } + + if (classes.size() > 1) { + return HighlightUtil.formatClass(classes.get(0)) + " and " + HighlightUtil.formatClass(classes.get(1)); + } } - } - inheritedClasses.put(superClass, superTypeSubstitutor); - visited.add(superClass); - final HighlightInfo highlightInfo = checkInterfaceMultipleInheritance(superClass, place, superTypeSubstitutor, inheritedClasses, visited, textRange); - visited.remove(superClass); - if (highlightInfo != null) { - return highlightInfo; - } + return null; } - return null; - } - - @Nonnull - public static Collection checkOverrideEquivalentMethods(@Nonnull PsiClass aClass) { - List result = new ArrayList<>(); - final Collection signaturesWithSupers = aClass.getVisibleSignatures(); - PsiManager manager = aClass.getManager(); - Map sameErasureMethods = Maps.newHashMap(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY); - - final Set foundProblems = Sets.newHashSet(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY); - for (HierarchicalMethodSignature signature : signaturesWithSupers) { - HighlightInfo info = checkSameErasureNotSubSignatureInner(signature, manager, aClass, sameErasureMethods); - if (info != null && foundProblems.add(signature)) { - result.add(info); - } - if (aClass instanceof PsiTypeParameter) { - info = HighlightMethodUtil.checkMethodIncompatibleReturnType(signature, signature.getSuperSignatures(), true, HighlightNamesUtil.getClassDeclarationTextRange(aClass)); - if (info != null) { - result.add(info); + + public static HighlightInfo checkUnrelatedConcrete(@Nonnull PsiClass psiClass, @Nonnull PsiIdentifier classIdentifier) { + final PsiClass superClass = psiClass.getSuperClass(); + if (superClass != null && superClass.hasTypeParameters()) { + final Collection visibleSignatures = superClass.getVisibleSignatures(); + final Map overrideEquivalent = + Maps.newHashMap(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY); + for (HierarchicalMethodSignature hms : visibleSignatures) { + final PsiMethod method = hms.getMethod(); + if (method.isConstructor()) { + continue; + } + if (method.hasModifierProperty(PsiModifier.ABSTRACT) || method.hasModifierProperty(PsiModifier.DEFAULT)) { + continue; + } + if (psiClass.findMethodsBySignature(method, false).length > 0) { + continue; + } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + continue; + } + final PsiSubstitutor containingClassSubstitutor = + TypeConversionUtil.getSuperClassSubstitutor(containingClass, psiClass, PsiSubstitutor.EMPTY); + final PsiSubstitutor finalSubstitutor = + PsiSuperMethodUtil.obtainFinalSubstitutor(containingClass, containingClassSubstitutor, hms.getSubstitutor(), false); + final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, finalSubstitutor, false); + final PsiMethod foundMethod = overrideEquivalent.get(signature); + PsiClass foundMethodContainingClass; + if (foundMethod != null + && !foundMethod.hasModifierProperty(PsiModifier.ABSTRACT) + && !foundMethod.hasModifierProperty(PsiModifier.DEFAULT) + && (foundMethodContainingClass = foundMethod.getContainingClass()) != null) { + final String description = "Methods " + + JavaHighlightUtil.formatMethod(foundMethod) + " from " + HighlightUtil.formatClass(foundMethodContainingClass) + + " and " + + JavaHighlightUtil.formatMethod(method) + " from " + HighlightUtil.formatClass(containingClass) + + " are inherited with the same signature"; + + final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(classIdentifier) + .descriptionAndTooltip(description) + .create(); + //todo override fix + return info; + } + overrideEquivalent.put(signature, method); + } } - } + return null; } - return result; - } - - public static HighlightInfo checkDefaultMethodOverrideEquivalentToObjectNonPrivate(@Nonnull LanguageLevel languageLevel, - @Nonnull PsiClass aClass, - @Nonnull PsiMethod method, - @Nonnull PsiElement methodIdentifier) { - if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && aClass.isInterface() && method.hasModifierProperty(PsiModifier.DEFAULT)) { - HierarchicalMethodSignature sig = method.getHierarchicalMethodSignature(); - for (HierarchicalMethodSignature methodSignature : sig.getSuperSignatures()) { - final PsiMethod objectMethod = methodSignature.getMethod(); - final PsiClass containingClass = objectMethod.getContainingClass(); - if (containingClass != null && JavaClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) && objectMethod.hasModifierProperty(PsiModifier.PUBLIC)) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip("Default method '" + sig.getName() + "' overrides a member of 'java.lang.Object'").range - (methodIdentifier).create(); - } - } - } - return null; - } - - public static HighlightInfo checkUnrelatedDefaultMethods(@Nonnull PsiClass aClass, @Nonnull PsiIdentifier classIdentifier) { - final Map> overrideEquivalent = PsiSuperMethodUtil.collectOverrideEquivalents(aClass); - - final boolean isInterface = aClass.isInterface(); - for (Set overrideEquivalentMethods : overrideEquivalent.values()) { - if (overrideEquivalentMethods.size() <= 1) { - continue; - } - List defaults = null; - List abstracts = null; - boolean hasConcrete = false; - for (PsiMethod method : overrideEquivalentMethods) { - final boolean isDefault = method.hasModifierProperty(PsiModifier.DEFAULT); - final boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT); - if (isDefault) { - if (defaults == null) { - defaults = new ArrayList<>(2); - } - defaults.add(method); - } - if (isAbstract) { - if (abstracts == null) { - abstracts = new ArrayList<>(2); - } - abstracts.add(method); - } - hasConcrete |= !isDefault && !isAbstract; - } - - if (!hasConcrete && defaults != null) { - final PsiMethod defaultMethod = defaults.get(0); - if (MethodSignatureUtil.findMethodBySuperMethod(aClass, defaultMethod, false) != null) { - continue; - } - final PsiClass defaultMethodContainingClass = defaultMethod.getContainingClass(); - if (defaultMethodContainingClass == null) { - continue; - } - final PsiMethod unrelatedMethod = abstracts != null ? abstracts.get(0) : defaults.get(1); - final PsiClass unrelatedMethodContainingClass = unrelatedMethod.getContainingClass(); - if (unrelatedMethodContainingClass == null) { - continue; - } - if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT) && !(aClass instanceof PsiTypeParameter) && abstracts != null && unrelatedMethodContainingClass.isInterface()) { - if (defaultMethodContainingClass.isInheritor(unrelatedMethodContainingClass, true) && MethodSignatureUtil.isSubsignature(unrelatedMethod.getSignature(TypeConversionUtil - .getSuperClassSubstitutor(unrelatedMethodContainingClass, defaultMethodContainingClass, PsiSubstitutor.EMPTY)), defaultMethod.getSignature(PsiSubstitutor.EMPTY))) { - continue; - } - final String key = aClass instanceof PsiEnumConstantInitializer ? "enum.constant.should.implement.method" : "class.must.be.abstract"; - final String message = JavaErrorBundle.message(key, HighlightUtil.formatClass(aClass, false), JavaHighlightUtil.formatMethod(abstracts.get(0)), HighlightUtil.formatClass - (unrelatedMethodContainingClass, false)); - final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(classIdentifier).descriptionAndTooltip(message).create(); - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createImplementMethodsFix(aClass)); - return info; - } - if (isInterface || abstracts == null || unrelatedMethodContainingClass.isInterface()) { - final List defaultContainingClasses = ContainerUtil.mapNotNull(defaults, PsiMethod::getContainingClass); - final String unrelatedDefaults = hasUnrelatedDefaults(defaultContainingClasses); - if (unrelatedDefaults == null && (abstracts == null || !hasNotOverriddenAbstract(defaultContainingClasses, unrelatedMethodContainingClass))) { - continue; - } - - final String message = unrelatedDefaults != null ? " inherits unrelated defaults for " : " inherits abstract and default for "; - final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(classIdentifier).descriptionAndTooltip(HighlightUtil.formatClass(aClass) + - message + - JavaHighlightUtil.formatMethod(defaultMethod) + " from types " + - (unrelatedDefaults != null ? unrelatedDefaults : HighlightUtil.formatClass(defaultMethodContainingClass) + " and " + HighlightUtil.formatClass - (unrelatedMethodContainingClass))).create(); - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createImplementMethodsFix(aClass)); - return info; - } - } - } - return null; - } - - private static boolean belongToOneHierarchy(@Nonnull PsiClass defaultMethodContainingClass, @Nonnull PsiClass unrelatedMethodContainingClass) { - return defaultMethodContainingClass.isInheritor(unrelatedMethodContainingClass, true) || unrelatedMethodContainingClass.isInheritor(defaultMethodContainingClass, true); - } - - private static boolean hasNotOverriddenAbstract(List defaultContainingClasses, @Nonnull PsiClass abstractMethodContainingClass) { - return defaultContainingClasses.stream().noneMatch(containingClass -> belongToOneHierarchy(containingClass, abstractMethodContainingClass)); - } - - private static String hasUnrelatedDefaults(List defaults) { - if (defaults.size() > 1) { - PsiClass[] defaultClasses = defaults.toArray(PsiClass.EMPTY_ARRAY); - ArrayList classes = new ArrayList<>(defaults); - for (final PsiClass aClass1 : defaultClasses) { - classes.removeIf(aClass2 -> aClass1.isInheritor(aClass2, true)); - } - - if (classes.size() > 1) { - return HighlightUtil.formatClass(classes.get(0)) + " and " + HighlightUtil.formatClass(classes.get(1)); - } - } + @Nullable + private static HighlightInfo checkSameErasureNotSubSignatureInner( + @Nonnull HierarchicalMethodSignature signature, + @Nonnull PsiManager manager, + @Nonnull PsiClass aClass, + @Nonnull Map sameErasureMethods + ) { + PsiMethod method = signature.getMethod(); + JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); + if (!facade.getResolveHelper().isAccessible(method, aClass, null)) { + return null; + } + MethodSignature signatureToErase = method.getSignature(PsiSubstitutor.EMPTY); + MethodSignatureBackedByPsiMethod sameErasure = sameErasureMethods.get(signatureToErase); + HighlightInfo info; + if (sameErasure != null) { + if (aClass instanceof PsiTypeParameter + || MethodSignatureUtil.findMethodBySuperMethod(aClass, sameErasure.getMethod(), false) != null + || !(InheritanceUtil.isInheritorOrSelf( + sameErasure.getMethod().getContainingClass(), + method.getContainingClass(), + true + ) + || InheritanceUtil.isInheritorOrSelf(method.getContainingClass(), sameErasure.getMethod().getContainingClass(), true))) { + info = checkSameErasureNotSubSignatureOrSameClass(sameErasure, signature, aClass, method); + if (info != null) { + return info; + } + } + } + else { + sameErasureMethods.put(signatureToErase, signature); + } + List supers = signature.getSuperSignatures(); + for (HierarchicalMethodSignature superSignature : supers) { + info = checkSameErasureNotSubSignatureInner(superSignature, manager, aClass, sameErasureMethods); + if (info != null) { + return info; + } + + if (superSignature.isRaw() && !signature.isRaw()) { + final PsiType[] parameterTypes = signature.getParameterTypes(); + PsiType[] erasedTypes = superSignature.getErasedParameterTypes(); + for (int i = 0; i < erasedTypes.length; i++) { + if (!Comparing.equal(parameterTypes[i], erasedTypes[i])) { + return getSameErasureMessage( + false, + method, + superSignature.getMethod(), + HighlightNamesUtil.getClassDeclarationTextRange(aClass) + ); + } + } + } - return null; - } - - public static HighlightInfo checkUnrelatedConcrete(@Nonnull PsiClass psiClass, @Nonnull PsiIdentifier classIdentifier) { - final PsiClass superClass = psiClass.getSuperClass(); - if (superClass != null && superClass.hasTypeParameters()) { - final Collection visibleSignatures = superClass.getVisibleSignatures(); - final Map overrideEquivalent = Maps.newHashMap(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY); - for (HierarchicalMethodSignature hms : visibleSignatures) { - final PsiMethod method = hms.getMethod(); - if (method.isConstructor()) { - continue; - } - if (method.hasModifierProperty(PsiModifier.ABSTRACT) || method.hasModifierProperty(PsiModifier.DEFAULT)) { - continue; - } - if (psiClass.findMethodsBySignature(method, false).length > 0) { - continue; - } - final PsiClass containingClass = method.getContainingClass(); - if (containingClass == null) { - continue; - } - final PsiSubstitutor containingClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(containingClass, psiClass, PsiSubstitutor.EMPTY); - final PsiSubstitutor finalSubstitutor = PsiSuperMethodUtil.obtainFinalSubstitutor(containingClass, containingClassSubstitutor, hms.getSubstitutor(), false); - final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, finalSubstitutor, false); - final PsiMethod foundMethod = overrideEquivalent.get(signature); - PsiClass foundMethodContainingClass; - if (foundMethod != null && - !foundMethod.hasModifierProperty(PsiModifier.ABSTRACT) && - !foundMethod.hasModifierProperty(PsiModifier.DEFAULT) && - (foundMethodContainingClass = foundMethod.getContainingClass()) != null) { - final String description = "Methods " + - JavaHighlightUtil.formatMethod(foundMethod) + " from " + HighlightUtil.formatClass(foundMethodContainingClass) + - " and " + - JavaHighlightUtil.formatMethod(method) + " from " + HighlightUtil.formatClass(containingClass) + - " are inherited with the same signature"; - - final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(classIdentifier).descriptionAndTooltip(description).create(); - //todo override fix - return info; - } - overrideEquivalent.put(signature, method); - } - } - return null; - } - - @Nullable - private static HighlightInfo checkSameErasureNotSubSignatureInner(@Nonnull HierarchicalMethodSignature signature, - @Nonnull PsiManager manager, - @Nonnull PsiClass aClass, - @Nonnull Map sameErasureMethods) { - PsiMethod method = signature.getMethod(); - JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); - if (!facade.getResolveHelper().isAccessible(method, aClass, null)) { - return null; - } - MethodSignature signatureToErase = method.getSignature(PsiSubstitutor.EMPTY); - MethodSignatureBackedByPsiMethod sameErasure = sameErasureMethods.get(signatureToErase); - HighlightInfo info; - if (sameErasure != null) { - if (aClass instanceof PsiTypeParameter || - MethodSignatureUtil.findMethodBySuperMethod(aClass, sameErasure.getMethod(), false) != null || - !(InheritanceUtil.isInheritorOrSelf(sameErasure.getMethod().getContainingClass(), method.getContainingClass(), true) || InheritanceUtil.isInheritorOrSelf(method - .getContainingClass(), sameErasure.getMethod().getContainingClass(), true))) { - info = checkSameErasureNotSubSignatureOrSameClass(sameErasure, signature, aClass, method); - if (info != null) { - return info; } - } - } else { - sameErasureMethods.put(signatureToErase, signature); + return null; } - List supers = signature.getSuperSignatures(); - for (HierarchicalMethodSignature superSignature : supers) { - info = checkSameErasureNotSubSignatureInner(superSignature, manager, aClass, sameErasureMethods); - if (info != null) { - return info; - } - - if (superSignature.isRaw() && !signature.isRaw()) { - final PsiType[] parameterTypes = signature.getParameterTypes(); - PsiType[] erasedTypes = superSignature.getErasedParameterTypes(); - for (int i = 0; i < erasedTypes.length; i++) { - if (!Comparing.equal(parameterTypes[i], erasedTypes[i])) { - return getSameErasureMessage(false, method, superSignature.getMethod(), HighlightNamesUtil.getClassDeclarationTextRange(aClass)); - } - } - } + @Nullable + private static HighlightInfo checkSameErasureNotSubSignatureOrSameClass( + final MethodSignatureBackedByPsiMethod signatureToCheck, + final HierarchicalMethodSignature superSignature, + final PsiClass aClass, + final PsiMethod superMethod + ) { + final PsiMethod checkMethod = signatureToCheck.getMethod(); + if (superMethod.equals(checkMethod)) { + return null; + } + PsiClass checkContainingClass = checkMethod.getContainingClass(); + LOG.assertTrue(checkContainingClass != null); + PsiClass superContainingClass = superMethod.getContainingClass(); + boolean checkEqualsSuper = checkContainingClass.equals(superContainingClass); + if (checkMethod.isConstructor()) { + if (!superMethod.isConstructor() || !checkEqualsSuper) { + return null; + } + } + else if (superMethod.isConstructor()) { + return null; + } + + final boolean atLeast17 = JavaVersionService.getInstance().isAtLeast(aClass, JavaSdkVersion.JDK_1_7); + if (checkMethod.hasModifierProperty(PsiModifier.STATIC) && !checkEqualsSuper && !atLeast17) { + return null; + } + + if (superMethod.hasModifierProperty(PsiModifier.STATIC) && superContainingClass != null && + superContainingClass.isInterface() && !checkEqualsSuper && PsiUtil.isLanguageLevel8OrHigher(superContainingClass)) { + return null; + } + + final PsiType retErasure1 = TypeConversionUtil.erasure(checkMethod.getReturnType()); + final PsiType retErasure2 = TypeConversionUtil.erasure(superMethod.getReturnType()); + + boolean differentReturnTypeErasure = !Comparing.equal(retErasure1, retErasure2); + if (checkEqualsSuper && atLeast17) { + if (retErasure1 != null && retErasure2 != null) { + differentReturnTypeErasure = !TypeConversionUtil.isAssignable(retErasure1, retErasure2); + } + else { + differentReturnTypeErasure = !(retErasure1 == null && retErasure2 == null); + } + } + + if (differentReturnTypeErasure + && !TypeConversionUtil.isVoidType(retErasure1) + && !TypeConversionUtil.isVoidType(retErasure2) + && !(checkEqualsSuper && Arrays.equals(superSignature.getParameterTypes(), signatureToCheck.getParameterTypes())) + && !atLeast17) { + int idx = 0; + final PsiType[] erasedTypes = signatureToCheck.getErasedParameterTypes(); + boolean erasure = erasedTypes.length > 0; + for (PsiType type : superSignature.getParameterTypes()) { + erasure &= Comparing.equal(type, erasedTypes[idx]); + idx++; + } + + if (!erasure) { + return null; + } + } + + if (!checkEqualsSuper && MethodSignatureUtil.isSubsignature(superSignature, signatureToCheck)) { + return null; + } + if (superContainingClass != null && !superContainingClass.isInterface() && checkContainingClass.isInterface() && !aClass.equals( + superContainingClass)) { + return null; + } + if (aClass.equals(checkContainingClass)) { + boolean sameClass = aClass.equals(superContainingClass); + return getSameErasureMessage( + sameClass, + checkMethod, + superMethod, + HighlightNamesUtil.getMethodDeclarationTextRange(checkMethod) + ); + } + else { + return getSameErasureMessage(false, checkMethod, superMethod, HighlightNamesUtil.getClassDeclarationTextRange(aClass)); + } } - return null; - } - - @Nullable - private static HighlightInfo checkSameErasureNotSubSignatureOrSameClass(final MethodSignatureBackedByPsiMethod signatureToCheck, - final HierarchicalMethodSignature superSignature, - final PsiClass aClass, - final PsiMethod superMethod) { - final PsiMethod checkMethod = signatureToCheck.getMethod(); - if (superMethod.equals(checkMethod)) { - return null; + + private static HighlightInfo getSameErasureMessage( + final boolean sameClass, + @Nonnull PsiMethod method, + @Nonnull PsiMethod superMethod, + TextRange textRange + ) { + @NonNls final String key = sameClass + ? "generics.methods.have.same.erasure" + : method.hasModifierProperty(PsiModifier.STATIC) + ? "generics.methods.have.same.erasure.hide" + : "generics.methods.have.same.erasure.override"; + String description = JavaErrorBundle.message(key, HighlightMethodUtil.createClashMethodMessage(method, superMethod, !sameClass)); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); } - PsiClass checkContainingClass = checkMethod.getContainingClass(); - LOG.assertTrue(checkContainingClass != null); - PsiClass superContainingClass = superMethod.getContainingClass(); - boolean checkEqualsSuper = checkContainingClass.equals(superContainingClass); - if (checkMethod.isConstructor()) { - if (!superMethod.isConstructor() || !checkEqualsSuper) { + + public static HighlightInfo checkTypeParameterInstantiation(PsiNewExpression expression) { + PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference(); + if (classReference == null) { + return null; + } + final JavaResolveResult result = classReference.advancedResolve(false); + final PsiElement element = result.getElement(); + if (element instanceof PsiTypeParameter) { + String description = JavaErrorBundle.message( + "generics.type.parameter.cannot.be.instantiated", + HighlightUtil.formatClass((PsiTypeParameter)element) + ); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(classReference) + .descriptionAndTooltip(description) + .create(); + } return null; - } - } else if (superMethod.isConstructor()) { - return null; } - final boolean atLeast17 = JavaVersionService.getInstance().isAtLeast(aClass, JavaSdkVersion.JDK_1_7); - if (checkMethod.hasModifierProperty(PsiModifier.STATIC) && !checkEqualsSuper && !atLeast17) { - return null; - } + public static HighlightInfo checkWildcardUsage(PsiTypeElement typeElement) { + PsiType type = typeElement.getType(); + if (type instanceof PsiWildcardType) { + if (typeElement.getParent() instanceof PsiReferenceParameterList) { + PsiElement parent = typeElement.getParent().getParent(); + LOG.assertTrue(parent instanceof PsiJavaCodeReferenceElement, parent); + PsiElement refParent = parent.getParent(); + if (refParent instanceof PsiAnonymousClass) { + refParent = refParent.getParent(); + } + if (refParent instanceof PsiNewExpression) { + PsiNewExpression newExpression = (PsiNewExpression)refParent; + if (!(newExpression.getType() instanceof PsiArrayType)) { + String description = + JavaErrorBundle.message("wildcard.type.cannot.be.instantiated", JavaHighlightUtil.formatType(type)); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeElement) + .descriptionAndTooltip(description) + .create(); + } + } + else if (refParent instanceof PsiReferenceList) { + PsiElement refPParent = refParent.getParent(); + if (!(refPParent instanceof PsiTypeParameter) || refParent != ((PsiTypeParameter)refPParent).getExtendsList()) { + String description = JavaErrorBundle.message("generics.wildcard.not.expected"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeElement) + .descriptionAndTooltip(description) + .create(); + } + } + } + else { + String description = JavaErrorBundle.message("generics.wildcards.may.be.used.only.as.reference.parameters"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeElement) + .descriptionAndTooltip(description) + .create(); + } + } - if (superMethod.hasModifierProperty(PsiModifier.STATIC) && superContainingClass != null && - superContainingClass.isInterface() && !checkEqualsSuper && PsiUtil.isLanguageLevel8OrHigher(superContainingClass)) { - return null; + return null; } - final PsiType retErasure1 = TypeConversionUtil.erasure(checkMethod.getReturnType()); - final PsiType retErasure2 = TypeConversionUtil.erasure(superMethod.getReturnType()); + public static HighlightInfo checkReferenceTypeUsedAsTypeArgument(PsiTypeElement typeElement, LanguageLevel level) { + final PsiType type = typeElement.getType(); + if (type != PsiType.NULL && type instanceof PsiPrimitiveType + || type instanceof PsiWildcardType && ((PsiWildcardType)type).getBound() instanceof PsiPrimitiveType) { + final PsiElement element = new PsiMatcherImpl(typeElement) + .parent(PsiMatchers.hasClass(PsiReferenceParameterList.class)) + .parent(PsiMatchers.hasClass(PsiJavaCodeReferenceElement.class, PsiNewExpression.class)) + .getElement(); + if (element == null) { + return null; + } - boolean differentReturnTypeErasure = !Comparing.equal(retErasure1, retErasure2); - if (checkEqualsSuper && atLeast17) { - if (retErasure1 != null && retErasure2 != null) { - differentReturnTypeErasure = !TypeConversionUtil.isAssignable(retErasure1, retErasure2); - } else { - differentReturnTypeErasure = !(retErasure1 == null && retErasure2 == null); - } - } + if (level.isAtLeast(LanguageLevel.JDK_X)) { + return null; + } + + String text = JavaErrorBundle.message("generics.type.argument.cannot.be.of.primitive.type"); + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeElement) + .descriptionAndTooltip(text) + .create(); + + PsiType toConvert = type; + if (type instanceof PsiWildcardType) { + toConvert = ((PsiWildcardType)type).getBound(); + } + if (toConvert instanceof PsiPrimitiveType) { + final PsiClassType boxedType = ((PsiPrimitiveType)toConvert).getBoxedType(typeElement); + if (boxedType != null) { + QuickFixAction.registerQuickFixAction( + highlightInfo, + QuickFixFactory.getInstance().createReplacePrimitiveWithBoxedTypeAction( + typeElement, + toConvert.getPresentableText(), + ((PsiPrimitiveType)toConvert).getBoxedTypeName() + ) + ); + } + } + return highlightInfo; + } - if (differentReturnTypeErasure && - !TypeConversionUtil.isVoidType(retErasure1) && - !TypeConversionUtil.isVoidType(retErasure2) && - !(checkEqualsSuper && Arrays.equals(superSignature.getParameterTypes(), signatureToCheck.getParameterTypes())) && - !atLeast17) { - int idx = 0; - final PsiType[] erasedTypes = signatureToCheck.getErasedParameterTypes(); - boolean erasure = erasedTypes.length > 0; - for (PsiType type : superSignature.getParameterTypes()) { - erasure &= Comparing.equal(type, erasedTypes[idx]); - idx++; - } - - if (!erasure) { return null; - } } - if (!checkEqualsSuper && MethodSignatureUtil.isSubsignature(superSignature, signatureToCheck)) { - return null; - } - if (superContainingClass != null && !superContainingClass.isInterface() && checkContainingClass.isInterface() && !aClass.equals(superContainingClass)) { - return null; - } - if (aClass.equals(checkContainingClass)) { - boolean sameClass = aClass.equals(superContainingClass); - return getSameErasureMessage(sameClass, checkMethod, superMethod, HighlightNamesUtil.getMethodDeclarationTextRange(checkMethod)); - } else { - return getSameErasureMessage(false, checkMethod, superMethod, HighlightNamesUtil.getClassDeclarationTextRange(aClass)); - } - } - - private static HighlightInfo getSameErasureMessage(final boolean sameClass, @Nonnull PsiMethod method, @Nonnull PsiMethod superMethod, TextRange textRange) { - @NonNls final String key = sameClass ? "generics.methods.have.same.erasure" : method.hasModifierProperty(PsiModifier.STATIC) ? "generics.methods.have.same.erasure.hide" : "generics.methods" + - ".have.same.erasure.override"; - String description = JavaErrorBundle.message(key, HighlightMethodUtil.createClashMethodMessage(method, superMethod, !sameClass)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - } - - public static HighlightInfo checkTypeParameterInstantiation(PsiNewExpression expression) { - PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference(); - if (classReference == null) { - return null; - } - final JavaResolveResult result = classReference.advancedResolve(false); - final PsiElement element = result.getElement(); - if (element instanceof PsiTypeParameter) { - String description = JavaErrorBundle.message("generics.type.parameter.cannot.be.instantiated", HighlightUtil.formatClass((PsiTypeParameter) element)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(classReference).descriptionAndTooltip(description).create(); + public static HighlightInfo checkForeachExpressionTypeIsIterable(PsiExpression expression) { + if (expression == null || expression.getType() == null) { + return null; + } + final PsiType itemType = JavaGenericsUtil.getCollectionItemType(expression); + if (itemType == null) { + String description = JavaErrorBundle.message("foreach.not.applicable", JavaHighlightUtil.formatType(expression.getType())); + final HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(description) + .create(); + QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance().createNotIterableForEachLoopFix(expression)); + return highlightInfo; + } + return null; } - return null; - } - - public static HighlightInfo checkWildcardUsage(PsiTypeElement typeElement) { - PsiType type = typeElement.getType(); - if (type instanceof PsiWildcardType) { - if (typeElement.getParent() instanceof PsiReferenceParameterList) { - PsiElement parent = typeElement.getParent().getParent(); - LOG.assertTrue(parent instanceof PsiJavaCodeReferenceElement, parent); - PsiElement refParent = parent.getParent(); - if (refParent instanceof PsiAnonymousClass) { - refParent = refParent.getParent(); - } - if (refParent instanceof PsiNewExpression) { - PsiNewExpression newExpression = (PsiNewExpression) refParent; - if (!(newExpression.getType() instanceof PsiArrayType)) { - String description = JavaErrorBundle.message("wildcard.type.cannot.be.instantiated", JavaHighlightUtil.formatType(type)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create(); - } - } else if (refParent instanceof PsiReferenceList) { - PsiElement refPParent = refParent.getParent(); - if (!(refPParent instanceof PsiTypeParameter) || refParent != ((PsiTypeParameter) refPParent).getExtendsList()) { - String description = JavaErrorBundle.message("generics.wildcard.not.expected"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create(); - } - } - } else { - String description = JavaErrorBundle.message("generics.wildcards.may.be.used.only.as.reference.parameters"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create(); - } + + public static HighlightInfo checkForEachParameterType(@Nonnull PsiForeachStatement statement, @Nonnull PsiParameter parameter) { + final PsiExpression expression = statement.getIteratedValue(); + final PsiType itemType = expression == null ? null : JavaGenericsUtil.getCollectionItemType(expression); + if (itemType == null) { + return null; + } + + final PsiType parameterType = parameter.getType(); + if (TypeConversionUtil.isAssignable(parameterType, itemType)) { + return null; + } + HighlightInfo highlightInfo = + HighlightUtil.createIncompatibleTypeHighlightInfo(itemType, parameterType, parameter.getTextRange(), 0); + HighlightUtil.registerChangeVariableTypeFixes(parameter, itemType, expression, highlightInfo); + return highlightInfo; } - return null; - } + //http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.2 + @Nullable + public static HighlightInfo checkAccessStaticFieldFromEnumConstructor( + @Nonnull PsiReferenceExpression expr, + @Nonnull JavaResolveResult result + ) { + final PsiElement resolved = result.getElement(); - public static HighlightInfo checkReferenceTypeUsedAsTypeArgument(PsiTypeElement typeElement, LanguageLevel level) { - final PsiType type = typeElement.getType(); - if (type != PsiType.NULL && type instanceof PsiPrimitiveType || type instanceof PsiWildcardType && ((PsiWildcardType) type).getBound() instanceof PsiPrimitiveType) { - final PsiElement element = new PsiMatcherImpl(typeElement).parent(PsiMatchers.hasClass(PsiReferenceParameterList.class)).parent(PsiMatchers.hasClass(PsiJavaCodeReferenceElement.class, - PsiNewExpression.class)).getElement(); - if (element == null) { - return null; - } + if (!(resolved instanceof PsiField)) { + return null; + } + if (!((PsiModifierListOwner)resolved).hasModifierProperty(PsiModifier.STATIC)) { + return null; + } + if (expr.getParent() instanceof PsiSwitchLabelStatement) { + return null; + } + final PsiMember constructorOrInitializer = PsiUtil.findEnclosingConstructorOrInitializer(expr); + if (constructorOrInitializer == null) { + return null; + } + if (constructorOrInitializer.hasModifierProperty(PsiModifier.STATIC)) { + return null; + } + final PsiClass aClass = constructorOrInitializer instanceof PsiEnumConstantInitializer + ? (PsiClass)constructorOrInitializer + : constructorOrInitializer.getContainingClass(); + if (aClass == null || !(aClass.isEnum() || aClass instanceof PsiEnumConstantInitializer)) { + return null; + } + final PsiField field = (PsiField)resolved; + if (aClass instanceof PsiEnumConstantInitializer) { + if (field.getContainingClass() != aClass.getSuperClass()) { + return null; + } + } + else if (field.getContainingClass() != aClass) { + return null; + } - if (level.isAtLeast(LanguageLevel.JDK_X)) { - return null; - } - - String text = JavaErrorBundle.message("generics.type.argument.cannot.be.of.primitive.type"); - HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(text).create(); - - PsiType toConvert = type; - if (type instanceof PsiWildcardType) { - toConvert = ((PsiWildcardType) type).getBound(); - } - if (toConvert instanceof PsiPrimitiveType) { - final PsiClassType boxedType = ((PsiPrimitiveType) toConvert).getBoxedType(typeElement); - if (boxedType != null) { - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance() - .createReplacePrimitiveWithBoxedTypeAction(typeElement, toConvert.getPresentableText(), ((PsiPrimitiveType) - toConvert).getBoxedTypeName())); - } - } - return highlightInfo; - } + if (!JavaVersionService.getInstance().isAtLeast(field, JavaSdkVersion.JDK_1_6)) { + final PsiType type = field.getType(); + if (type instanceof PsiClassType && ((PsiClassType)type).resolve() == aClass) { + return null; + } + } - return null; - } + if (PsiUtil.isCompileTimeConstant((PsiVariable)field)) { + return null; + } - public static HighlightInfo checkForeachExpressionTypeIsIterable(PsiExpression expression) { - if (expression == null || expression.getType() == null) { - return null; - } - final PsiType itemType = JavaGenericsUtil.getCollectionItemType(expression); - if (itemType == null) { - String description = JavaErrorBundle.message("foreach.not.applicable", JavaHighlightUtil.formatType(expression.getType())); - final HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance().createNotIterableForEachLoopFix(expression)); - return highlightInfo; - } - return null; - } - - public static HighlightInfo checkForEachParameterType(@Nonnull PsiForeachStatement statement, @Nonnull PsiParameter parameter) { - final PsiExpression expression = statement.getIteratedValue(); - final PsiType itemType = expression == null ? null : JavaGenericsUtil.getCollectionItemType(expression); - if (itemType == null) { - return null; - } + String description = JavaErrorBundle.message( + "illegal.to.access.static.member.from.enum.constructor.or.instance.initializer", + HighlightMessageUtil.getSymbolName(resolved, result + .getSubstitutor()) + ); - final PsiType parameterType = parameter.getType(); - if (TypeConversionUtil.isAssignable(parameterType, itemType)) { - return null; - } - HighlightInfo highlightInfo = HighlightUtil.createIncompatibleTypeHighlightInfo(itemType, parameterType, parameter.getTextRange(), 0); - HighlightUtil.registerChangeVariableTypeFixes(parameter, itemType, expression, highlightInfo); - return highlightInfo; - } - - //http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.2 - @Nullable - public static HighlightInfo checkAccessStaticFieldFromEnumConstructor(@Nonnull PsiReferenceExpression expr, @Nonnull JavaResolveResult result) { - final PsiElement resolved = result.getElement(); - - if (!(resolved instanceof PsiField)) { - return null; - } - if (!((PsiModifierListOwner) resolved).hasModifierProperty(PsiModifier.STATIC)) { - return null; + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expr).descriptionAndTooltip(description).create(); } - if (expr.getParent() instanceof PsiSwitchLabelStatement) { - return null; - } - final PsiMember constructorOrInitializer = PsiUtil.findEnclosingConstructorOrInitializer(expr); - if (constructorOrInitializer == null) { - return null; - } - if (constructorOrInitializer.hasModifierProperty(PsiModifier.STATIC)) { - return null; - } - final PsiClass aClass = constructorOrInitializer instanceof PsiEnumConstantInitializer ? (PsiClass) constructorOrInitializer : constructorOrInitializer.getContainingClass(); - if (aClass == null || !(aClass.isEnum() || aClass instanceof PsiEnumConstantInitializer)) { - return null; - } - final PsiField field = (PsiField) resolved; - if (aClass instanceof PsiEnumConstantInitializer) { - if (field.getContainingClass() != aClass.getSuperClass()) { + + @Nullable + public static HighlightInfo checkEnumInstantiation(PsiElement expression, PsiClass aClass) { + if (aClass != null && aClass.isEnum() && (!(expression instanceof PsiNewExpression) + || ((PsiNewExpression)expression).getArrayDimensions().length == 0 && ((PsiNewExpression)expression).getArrayInitializer() == null)) { + String description = JavaErrorBundle.message("enum.types.cannot.be.instantiated"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(description) + .create(); + } return null; - } - } else if (field.getContainingClass() != aClass) { - return null; } + @Nullable + public static HighlightInfo checkGenericArrayCreation(PsiElement element, PsiType type) { + if (type instanceof PsiArrayType) { + if (!JavaGenericsUtil.isReifiableType(((PsiArrayType)type).getComponentType())) { + String description = JavaErrorBundle.message("generic.array.creation"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(element) + .descriptionAndTooltip(description) + .create(); + } + } - if (!JavaVersionService.getInstance().isAtLeast(field, JavaSdkVersion.JDK_1_6)) { - final PsiType type = field.getType(); - if (type instanceof PsiClassType && ((PsiClassType) type).resolve() == aClass) { return null; - } - } - - if (PsiUtil.isCompileTimeConstant((PsiVariable) field)) { - return null; } - String description = JavaErrorBundle.message("illegal.to.access.static.member.from.enum.constructor.or.instance.initializer", HighlightMessageUtil.getSymbolName(resolved, result - .getSubstitutor())); + private static final MethodSignature ourValuesEnumSyntheticMethod = + MethodSignatureUtil.createMethodSignature("values", PsiType.EMPTY_ARRAY, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expr).descriptionAndTooltip(description).create(); - } + public static boolean isEnumSyntheticMethod(MethodSignature methodSignature, Project project) { + if (methodSignature.equals(ourValuesEnumSyntheticMethod)) { + return true; + } + final PsiType javaLangString = PsiType.getJavaLangString(PsiManager.getInstance(project), GlobalSearchScope.allScope(project)); + final MethodSignature valueOfMethod = MethodSignatureUtil.createMethodSignature( + "valueOf", + new PsiType[]{javaLangString}, + PsiTypeParameter.EMPTY_ARRAY, + PsiSubstitutor.EMPTY + ); + return valueOfMethod.equals(methodSignature); + } + + @Nullable + public static HighlightInfo checkTypeParametersList( + PsiTypeParameterList list, + PsiTypeParameter[] parameters, + @Nonnull LanguageLevel level + ) { + final PsiElement parent = list.getParent(); + if (parent instanceof PsiClass && ((PsiClass)parent).isEnum()) { + String description = JavaErrorBundle.message("generics.enum.may.not.have.type.parameters"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(list) + .descriptionAndTooltip(description) + .create(); + } + if (PsiUtil.isAnnotationMethod(parent)) { + String description = JavaErrorBundle.message("generics.annotation.members.may.not.have.type.parameters"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(list) + .descriptionAndTooltip(description) + .create(); + } + if (parent instanceof PsiClass && ((PsiClass)parent).isAnnotationType()) { + String description = JavaErrorBundle.message("annotation.may.not.have.type.parameters"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(list) + .descriptionAndTooltip(description) + .create(); + } - @Nullable - public static HighlightInfo checkEnumInstantiation(PsiElement expression, PsiClass aClass) { - if (aClass != null && aClass.isEnum() && - (!(expression instanceof PsiNewExpression) || ((PsiNewExpression) expression).getArrayDimensions().length == 0 && ((PsiNewExpression) expression).getArrayInitializer() == null)) { - String description = JavaErrorBundle.message("enum.types.cannot.be.instantiated"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description).create(); - } - return null; - } - - @Nullable - public static HighlightInfo checkGenericArrayCreation(PsiElement element, PsiType type) { - if (type instanceof PsiArrayType) { - if (!JavaGenericsUtil.isReifiableType(((PsiArrayType) type).getComponentType())) { - String description = JavaErrorBundle.message("generic.array.creation"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); - } + for (int i = 0; i < parameters.length; i++) { + final PsiTypeParameter typeParameter1 = parameters[i]; + final HighlightInfo cyclicInheritance = HighlightClassUtil.checkCyclicInheritance(typeParameter1); + if (cyclicInheritance != null) { + return cyclicInheritance; + } + String name1 = typeParameter1.getName(); + for (int j = i + 1; j < parameters.length; j++) { + final PsiTypeParameter typeParameter2 = parameters[j]; + String name2 = typeParameter2.getName(); + if (Comparing.strEqual(name1, name2)) { + String message = JavaErrorBundle.message("generics.duplicate.type.parameter", name1); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeParameter2) + .descriptionAndTooltip(message) + .create(); + } + } + if (!level.isAtLeast(LanguageLevel.JDK_1_7)) { + for (PsiJavaCodeReferenceElement referenceElement : typeParameter1.getExtendsList().getReferenceElements()) { + final PsiElement resolve = referenceElement.resolve(); + if (resolve instanceof PsiTypeParameter && ArrayUtil.find(parameters, resolve) > i) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(referenceElement.getTextRange()) + .descriptionAndTooltip("Illegal forward reference") + .create(); + } + } + } + } + return null; } - return null; - } - - private static final MethodSignature ourValuesEnumSyntheticMethod = MethodSignatureUtil.createMethodSignature("values", PsiType.EMPTY_ARRAY, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY); + @Nonnull + public static Collection checkCatchParameterIsClass(PsiParameter parameter) { + if (!(parameter.getDeclarationScope() instanceof PsiCatchSection)) { + return Collections.emptyList(); + } + final Collection result = ContainerUtil.newArrayList(); + + final List typeElements = PsiUtil.getParameterTypeElements(parameter); + for (PsiTypeElement typeElement : typeElements) { + final PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(typeElement.getType()); + if (aClass instanceof PsiTypeParameter) { + final String message = JavaErrorBundle.message("generics.cannot.catch.type.parameters"); + result.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeElement) + .descriptionAndTooltip(message) + .create()); + } + } - public static boolean isEnumSyntheticMethod(MethodSignature methodSignature, Project project) { - if (methodSignature.equals(ourValuesEnumSyntheticMethod)) { - return true; - } - final PsiType javaLangString = PsiType.getJavaLangString(PsiManager.getInstance(project), GlobalSearchScope.allScope(project)); - final MethodSignature valueOfMethod = MethodSignatureUtil.createMethodSignature("valueOf", new PsiType[]{javaLangString}, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY); - return valueOfMethod.equals(methodSignature); - } - - @Nullable - public static HighlightInfo checkTypeParametersList(PsiTypeParameterList list, PsiTypeParameter[] parameters, @Nonnull LanguageLevel level) { - final PsiElement parent = list.getParent(); - if (parent instanceof PsiClass && ((PsiClass) parent).isEnum()) { - String description = JavaErrorBundle.message("generics.enum.may.not.have.type.parameters"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list).descriptionAndTooltip(description).create(); - } - if (PsiUtil.isAnnotationMethod(parent)) { - String description = JavaErrorBundle.message("generics.annotation.members.may.not.have.type.parameters"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list).descriptionAndTooltip(description).create(); - } - if (parent instanceof PsiClass && ((PsiClass) parent).isAnnotationType()) { - String description = JavaErrorBundle.message("annotation.may.not.have.type.parameters"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list).descriptionAndTooltip(description).create(); + return result; } - for (int i = 0; i < parameters.length; i++) { - final PsiTypeParameter typeParameter1 = parameters[i]; - final HighlightInfo cyclicInheritance = HighlightClassUtil.checkCyclicInheritance(typeParameter1); - if (cyclicInheritance != null) { - return cyclicInheritance; - } - String name1 = typeParameter1.getName(); - for (int j = i + 1; j < parameters.length; j++) { - final PsiTypeParameter typeParameter2 = parameters[j]; - String name2 = typeParameter2.getName(); - if (Comparing.strEqual(name1, name2)) { - String message = JavaErrorBundle.message("generics.duplicate.type.parameter", name1); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeParameter2).descriptionAndTooltip(message).create(); - } - } - if (!level.isAtLeast(LanguageLevel.JDK_1_7)) { - for (PsiJavaCodeReferenceElement referenceElement : typeParameter1.getExtendsList().getReferenceElements()) { - final PsiElement resolve = referenceElement.resolve(); - if (resolve instanceof PsiTypeParameter && ArrayUtil.find(parameters, resolve) > i) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(referenceElement.getTextRange()).descriptionAndTooltip("Illegal forward reference").create(); - } - } - } - } - return null; - } + public static HighlightInfo checkInstanceOfGenericType(PsiInstanceOfExpression expression) { + final PsiTypeElement checkTypeElement = expression.getCheckType(); + if (checkTypeElement == null) { + return null; + } + return isIllegalForInstanceOf(checkTypeElement.getType(), checkTypeElement); + } + + /** + * 15.20.2 Type Comparison Operator instanceof + * ReferenceType mentioned after the instanceof operator is reifiable + */ + private static HighlightInfo isIllegalForInstanceOf(PsiType type, final PsiTypeElement typeElement) { + final PsiClass resolved = PsiUtil.resolveClassInClassTypeOnly(type); + if (resolved instanceof PsiTypeParameter) { + String description = JavaErrorBundle.message("generics.cannot.instanceof.type.parameters"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeElement) + .descriptionAndTooltip(description) + .create(); + } - @Nonnull - public static Collection checkCatchParameterIsClass(PsiParameter parameter) { - if (!(parameter.getDeclarationScope() instanceof PsiCatchSection)) { - return Collections.emptyList(); - } - final Collection result = ContainerUtil.newArrayList(); - - final List typeElements = PsiUtil.getParameterTypeElements(parameter); - for (PsiTypeElement typeElement : typeElements) { - final PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(typeElement.getType()); - if (aClass instanceof PsiTypeParameter) { - final String message = JavaErrorBundle.message("generics.cannot.catch.type.parameters"); - result.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(message).create()); - } + if (!JavaGenericsUtil.isReifiableType(type)) { + String description = JavaErrorBundle.message("illegal.generic.type.for.instanceof"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(typeElement) + .descriptionAndTooltip(description) + .create(); + } + + return null; } - return result; - } + public static HighlightInfo checkClassObjectAccessExpression(PsiClassObjectAccessExpression expression) { + PsiType type = expression.getOperand().getType(); + if (type instanceof PsiClassType) { + return canSelectFrom((PsiClassType)type, expression.getOperand()); + } + if (type instanceof PsiArrayType) { + final PsiType arrayComponentType = type.getDeepComponentType(); + if (arrayComponentType instanceof PsiClassType) { + return canSelectFrom((PsiClassType)arrayComponentType, expression.getOperand()); + } + } - public static HighlightInfo checkInstanceOfGenericType(PsiInstanceOfExpression expression) { - final PsiTypeElement checkTypeElement = expression.getCheckType(); - if (checkTypeElement == null) { - return null; + return null; } - return isIllegalForInstanceOf(checkTypeElement.getType(), checkTypeElement); - } - - /** - * 15.20.2 Type Comparison Operator instanceof - * ReferenceType mentioned after the instanceof operator is reifiable - */ - private static HighlightInfo isIllegalForInstanceOf(PsiType type, final PsiTypeElement typeElement) { - final PsiClass resolved = PsiUtil.resolveClassInClassTypeOnly(type); - if (resolved instanceof PsiTypeParameter) { - String description = JavaErrorBundle.message("generics.cannot.instanceof.type.parameters"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create(); + + @Nullable + private static HighlightInfo canSelectFrom(PsiClassType type, PsiTypeElement operand) { + PsiClass aClass = type.resolve(); + if (aClass instanceof PsiTypeParameter) { + String description = JavaErrorBundle.message("cannot.select.dot.class.from.type.variable"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(operand).descriptionAndTooltip(description).create(); + } + if (type.getParameters().length > 0) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(operand) + .descriptionAndTooltip("Cannot select from parameterized type") + .create(); + } + return null; } - if (!JavaGenericsUtil.isReifiableType(type)) { - String description = JavaErrorBundle.message("illegal.generic.type.for.instanceof"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create(); + @Nullable + public static HighlightInfo checkOverrideAnnotation( + @Nonnull PsiMethod method, + @Nonnull PsiAnnotation overrideAnnotation, + @Nonnull LanguageLevel languageLevel + ) { + try { + MethodSignatureBackedByPsiMethod superMethod = SuperMethodsSearch.search(method, null, true, false).findFirst(); + if (superMethod != null && method.getContainingClass().isInterface()) { + final PsiMethod psiMethod = superMethod.getMethod(); + final PsiClass containingClass = psiMethod.getContainingClass(); + if (containingClass != null && + JavaClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) && + psiMethod.hasModifierProperty(PsiModifier.PROTECTED)) { + superMethod = null; + } + } + if (superMethod == null) { + String description = JavaErrorBundle.message("method.does.not.override.super"); + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(overrideAnnotation) + .descriptionAndTooltip(description) + .create(); + if (highlightInfo != null) { + QuickFixFactory.getInstance().registerPullAsAbstractUpFixes(method, QuickFixActionRegistrar.create(highlightInfo)); + } + return highlightInfo; + } + PsiClass superClass = superMethod.getMethod().getContainingClass(); + if (languageLevel.equals(LanguageLevel.JDK_1_5) && + superClass != null && + superClass.isInterface()) { + String description = JavaErrorBundle.message("override.not.allowed.in.interfaces"); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(overrideAnnotation) + .descriptionAndTooltip(description) + .create(); + QuickFixAction.registerQuickFixAction( + info, + QuickFixFactory.getInstance().createIncreaseLanguageLevelFix(LanguageLevel.JDK_1_6) + ); + return info; + } + return null; + } + catch (IndexNotReadyException e) { + return null; + } } - return null; - } + @Nullable + public static HighlightInfo checkSafeVarargsAnnotation(PsiMethod method, LanguageLevel languageLevel) { + PsiModifierList list = method.getModifierList(); + final PsiAnnotation safeVarargsAnnotation = list.findAnnotation("java.lang.SafeVarargs"); + if (safeVarargsAnnotation == null) { + return null; + } + try { + if (!method.isVarArgs()) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(safeVarargsAnnotation) + .descriptionAndTooltip("@SafeVarargs is not allowed on methods with fixed arity") + .create(); + } + if (!isSafeVarargsNoOverridingCondition(method, languageLevel)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(safeVarargsAnnotation) + .descriptionAndTooltip("@SafeVarargs is not allowed on non-final instance methods") + .create(); + } - public static HighlightInfo checkClassObjectAccessExpression(PsiClassObjectAccessExpression expression) { - PsiType type = expression.getOperand().getType(); - if (type instanceof PsiClassType) { - return canSelectFrom((PsiClassType) type, expression.getOperand()); - } - if (type instanceof PsiArrayType) { - final PsiType arrayComponentType = type.getDeepComponentType(); - if (arrayComponentType instanceof PsiClassType) { - return canSelectFrom((PsiClassType) arrayComponentType, expression.getOperand()); - } - } + final PsiParameter varParameter = method.getParameterList().getParameters()[method.getParameterList().getParametersCount() - 1]; - return null; - } + for (PsiReference reference : ReferencesSearch.search(varParameter)) { + final PsiElement element = reference.getElement(); + if (element instanceof PsiExpression && !PsiUtil.isAccessedForReading((PsiExpression)element)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING) + .range(element) + .descriptionAndTooltip("@SafeVarargs do not suppress potentially unsafe operations") + .create(); + } + } - @Nullable - private static HighlightInfo canSelectFrom(PsiClassType type, PsiTypeElement operand) { - PsiClass aClass = type.resolve(); - if (aClass instanceof PsiTypeParameter) { - String description = JavaErrorBundle.message("cannot.select.dot.class.from.type.variable"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(operand).descriptionAndTooltip(description).create(); - } - if (type.getParameters().length > 0) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(operand).descriptionAndTooltip("Cannot select from parameterized type").create(); - } - return null; - } - - @Nullable - public static HighlightInfo checkOverrideAnnotation(@Nonnull PsiMethod method, @Nonnull PsiAnnotation overrideAnnotation, @Nonnull LanguageLevel languageLevel) { - try { - MethodSignatureBackedByPsiMethod superMethod = SuperMethodsSearch.search(method, null, true, false).findFirst(); - if (superMethod != null && method.getContainingClass().isInterface()) { - final PsiMethod psiMethod = superMethod.getMethod(); - final PsiClass containingClass = psiMethod.getContainingClass(); - if (containingClass != null && - JavaClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) && - psiMethod.hasModifierProperty(PsiModifier.PROTECTED)) { - superMethod = null; - } - } - if (superMethod == null) { - String description = JavaErrorBundle.message("method.does.not.override.super"); - HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(overrideAnnotation).descriptionAndTooltip(description).create(); - if(highlightInfo != null) { - QuickFixFactory.getInstance().registerPullAsAbstractUpFixes(method, QuickFixActionRegistrar.create(highlightInfo)); + + LOG.assertTrue(varParameter.isVarArgs()); + final PsiEllipsisType ellipsisType = (PsiEllipsisType)varParameter.getType(); + final PsiType componentType = ellipsisType.getComponentType(); + if (JavaGenericsUtil.isReifiableType(componentType)) { + PsiElement element = varParameter.getTypeElement(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING) + .range(element) + .descriptionAndTooltip("@SafeVarargs is not applicable for reifiable types") + .create(); + } + return null; + } + catch (IndexNotReadyException e) { + return null; } - return highlightInfo; - } - PsiClass superClass = superMethod.getMethod().getContainingClass(); - if (languageLevel.equals(LanguageLevel.JDK_1_5) && - superClass != null && - superClass.isInterface()) { - String description = JavaErrorBundle.message("override.not.allowed.in.interfaces"); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(overrideAnnotation).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createIncreaseLanguageLevelFix(LanguageLevel.JDK_1_6)); - return info; - } - return null; - } catch (IndexNotReadyException e) { - return null; - } - } - - @Nullable - public static HighlightInfo checkSafeVarargsAnnotation(PsiMethod method, LanguageLevel languageLevel) { - PsiModifierList list = method.getModifierList(); - final PsiAnnotation safeVarargsAnnotation = list.findAnnotation("java.lang.SafeVarargs"); - if (safeVarargsAnnotation == null) { - return null; - } - try { - if (!method.isVarArgs()) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(safeVarargsAnnotation).descriptionAndTooltip("@SafeVarargs is not allowed on methods with fixed arity").create(); - } - if (!isSafeVarargsNoOverridingCondition(method, languageLevel)) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(safeVarargsAnnotation).descriptionAndTooltip("@SafeVarargs is not allowed on non-final instance methods") - .create(); - } - - final PsiParameter varParameter = method.getParameterList().getParameters()[method.getParameterList().getParametersCount() - 1]; - - for (PsiReference reference : ReferencesSearch.search(varParameter)) { - final PsiElement element = reference.getElement(); - if (element instanceof PsiExpression && !PsiUtil.isAccessedForReading((PsiExpression) element)) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING).range(element).descriptionAndTooltip("@SafeVarargs do not suppress potentially unsafe operations").create(); - } - } - - - LOG.assertTrue(varParameter.isVarArgs()); - final PsiEllipsisType ellipsisType = (PsiEllipsisType) varParameter.getType(); - final PsiType componentType = ellipsisType.getComponentType(); - if (JavaGenericsUtil.isReifiableType(componentType)) { - PsiElement element = varParameter.getTypeElement(); - return HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING).range(element).descriptionAndTooltip("@SafeVarargs is not applicable for reifiable types").create(); - } - return null; - } catch (IndexNotReadyException e) { - return null; - } - } - - public static boolean isSafeVarargsNoOverridingCondition(PsiMethod method, LanguageLevel languageLevel) { - return method.hasModifierProperty(PsiModifier.FINAL) || - method.hasModifierProperty(PsiModifier.STATIC) || - method.isConstructor() || - method.hasModifierProperty(PsiModifier.PRIVATE) && languageLevel.isAtLeast(LanguageLevel.JDK_1_9); - } - - public static void checkEnumConstantForConstructorProblems(@Nonnull PsiEnumConstant enumConstant, @Nonnull HighlightInfoHolder holder, @Nonnull JavaSdkVersion javaSdkVersion) { - PsiClass containingClass = enumConstant.getContainingClass(); - if (enumConstant.getInitializingClass() == null) { - HighlightInfo highlightInfo = HighlightClassUtil.checkInstantiationOfAbstractClass(containingClass, enumConstant.getNameIdentifier()); - if (highlightInfo != null) { - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance().createImplementMethodsFix(enumConstant)); - holder.add(highlightInfo); - return; - } - highlightInfo = HighlightClassUtil.checkClassWithAbstractMethods(enumConstant.getContainingClass(), enumConstant, enumConstant.getNameIdentifier().getTextRange()); - if (highlightInfo != null) { - holder.add(highlightInfo); - return; - } - } - PsiClassType type = JavaPsiFacade.getInstance(holder.getProject()).getElementFactory().createType(containingClass); - - HighlightMethodUtil.checkConstructorCall(type.resolveGenerics(), enumConstant, type, null, holder, javaSdkVersion); - } - - @Nullable - public static HighlightInfo checkEnumSuperConstructorCall(PsiMethodCallExpression expr) { - PsiReferenceExpression methodExpression = expr.getMethodExpression(); - final PsiElement refNameElement = methodExpression.getReferenceNameElement(); - if (refNameElement != null && PsiKeyword.SUPER.equals(refNameElement.getText())) { - final PsiMember constructor = PsiUtil.findEnclosingConstructorOrInitializer(expr); - if (constructor instanceof PsiMethod) { - final PsiClass aClass = constructor.getContainingClass(); - if (aClass != null && aClass.isEnum()) { - final String message = JavaErrorBundle.message("call.to.super.is.not.allowed.in.enum.constructor"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expr).descriptionAndTooltip(message).create(); - } - } - } - return null; - } - - @Nullable - public static HighlightInfo checkVarArgParameterIsLast(@Nonnull PsiParameter parameter) { - PsiElement declarationScope = parameter.getDeclarationScope(); - if (declarationScope instanceof PsiMethod) { - PsiParameter[] params = ((PsiMethod) declarationScope).getParameterList().getParameters(); - if (params[params.length - 1] != parameter) { - String description = JavaErrorBundle.message("vararg.not.last.parameter"); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parameter).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createMakeVarargParameterLastFix(parameter)); - return info; - } - } - return null; - } - - @Nonnull - public static List checkEnumConstantModifierList(PsiModifierList modifierList) { - List list = null; - PsiElement[] children = modifierList.getChildren(); - for (PsiElement child : children) { - if (child instanceof PsiKeyword) { - if (list == null) { - list = new ArrayList<>(); - } - String description = JavaErrorBundle.message("modifiers.for.enum.constants"); - list.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(child).descriptionAndTooltip(description).create()); - } - } - return Lists.notNullize(list); - } - - @Nullable - public static HighlightInfo checkParametersAllowed(PsiReferenceParameterList refParamList) { - final PsiElement parent = refParamList.getParent(); - if (parent instanceof PsiReferenceExpression) { - final PsiElement grandParent = parent.getParent(); - if (!(grandParent instanceof PsiMethodCallExpression) && !(parent instanceof PsiMethodReferenceExpression)) { - final String message = JavaErrorBundle.message("generics.reference.parameters.not.allowed"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(refParamList).descriptionAndTooltip(message).create(); - } } - return null; - } - - @Nullable - public static HighlightInfo checkParametersOnRaw(PsiReferenceParameterList refParamList) { - JavaResolveResult resolveResult = null; - PsiElement parent = refParamList.getParent(); - PsiElement qualifier = null; - if (parent instanceof PsiJavaCodeReferenceElement) { - resolveResult = ((PsiJavaCodeReferenceElement) parent).advancedResolve(false); - qualifier = ((PsiJavaCodeReferenceElement) parent).getQualifier(); - } else if (parent instanceof PsiCallExpression) { - resolveResult = ((PsiCallExpression) parent).resolveMethodGenerics(); - if (parent instanceof PsiMethodCallExpression) { - final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression) parent).getMethodExpression(); - qualifier = methodExpression.getQualifier(); - } - } - if (resolveResult != null) { - PsiElement element = resolveResult.getElement(); - if (!(element instanceof PsiTypeParameterListOwner)) { - return null; - } - if (((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC)) { + public static boolean isSafeVarargsNoOverridingCondition(PsiMethod method, LanguageLevel languageLevel) { + return method.hasModifierProperty(PsiModifier.FINAL) || + method.hasModifierProperty(PsiModifier.STATIC) || + method.isConstructor() || + method.hasModifierProperty(PsiModifier.PRIVATE) && languageLevel.isAtLeast(LanguageLevel.JDK_1_9); + } + + public static void checkEnumConstantForConstructorProblems( + @Nonnull PsiEnumConstant enumConstant, + @Nonnull HighlightInfoHolder holder, + @Nonnull JavaSdkVersion javaSdkVersion + ) { + PsiClass containingClass = enumConstant.getContainingClass(); + if (enumConstant.getInitializingClass() == null) { + HighlightInfo highlightInfo = + HighlightClassUtil.checkInstantiationOfAbstractClass(containingClass, enumConstant.getNameIdentifier()); + if (highlightInfo != null) { + QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance().createImplementMethodsFix(enumConstant)); + holder.add(highlightInfo); + return; + } + highlightInfo = HighlightClassUtil.checkClassWithAbstractMethods( + enumConstant.getContainingClass(), + enumConstant, + enumConstant.getNameIdentifier().getTextRange() + ); + if (highlightInfo != null) { + holder.add(highlightInfo); + return; + } + } + PsiClassType type = JavaPsiFacade.getInstance(holder.getProject()).getElementFactory().createType(containingClass); + + HighlightMethodUtil.checkConstructorCall(type.resolveGenerics(), enumConstant, type, null, holder, javaSdkVersion); + } + + @Nullable + public static HighlightInfo checkEnumSuperConstructorCall(PsiMethodCallExpression expr) { + PsiReferenceExpression methodExpression = expr.getMethodExpression(); + final PsiElement refNameElement = methodExpression.getReferenceNameElement(); + if (refNameElement != null && PsiKeyword.SUPER.equals(refNameElement.getText())) { + final PsiMember constructor = PsiUtil.findEnclosingConstructorOrInitializer(expr); + if (constructor instanceof PsiMethod) { + final PsiClass aClass = constructor.getContainingClass(); + if (aClass != null && aClass.isEnum()) { + final String message = JavaErrorBundle.message("call.to.super.is.not.allowed.in.enum.constructor"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expr).descriptionAndTooltip(message).create(); + } + } + } return null; - } - if (qualifier instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement) qualifier).resolve() instanceof PsiTypeParameter) { + } + + @Nullable + public static HighlightInfo checkVarArgParameterIsLast(@Nonnull PsiParameter parameter) { + PsiElement declarationScope = parameter.getDeclarationScope(); + if (declarationScope instanceof PsiMethod) { + PsiParameter[] params = ((PsiMethod)declarationScope).getParameterList().getParameters(); + if (params[params.length - 1] != parameter) { + String description = JavaErrorBundle.message("vararg.not.last.parameter"); + HighlightInfo info = + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parameter).descriptionAndTooltip(description).create(); + QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createMakeVarargParameterLastFix(parameter)); + return info; + } + } return null; - } - PsiClass containingClass = ((PsiMember) element).getContainingClass(); - if (containingClass != null && PsiUtil.isRawSubstitutor(containingClass, resolveResult.getSubstitutor())) { - if ((parent instanceof PsiCallExpression || parent instanceof PsiMethodReferenceExpression) && PsiUtil.isLanguageLevel7OrHigher(parent)) { - return null; + } + + @Nonnull + public static List checkEnumConstantModifierList(PsiModifierList modifierList) { + List list = null; + PsiElement[] children = modifierList.getChildren(); + for (PsiElement child : children) { + if (child instanceof PsiKeyword) { + if (list == null) { + list = new ArrayList<>(); + } + String description = JavaErrorBundle.message("modifiers.for.enum.constants"); + list.add( + HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(child) + .descriptionAndTooltip(description) + .create() + ); + } + } + return Lists.notNullize(list); + } + + @Nullable + public static HighlightInfo checkParametersAllowed(PsiReferenceParameterList refParamList) { + final PsiElement parent = refParamList.getParent(); + if (parent instanceof PsiReferenceExpression) { + final PsiElement grandParent = parent.getParent(); + if (!(grandParent instanceof PsiMethodCallExpression) && !(parent instanceof PsiMethodReferenceExpression)) { + final String message = JavaErrorBundle.message("generics.reference.parameters.not.allowed"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(refParamList) + .descriptionAndTooltip(message) + .create(); + } } - if (element instanceof PsiMethod) { - if (((PsiMethod) element).findSuperMethods().length > 0) { - return null; - } - if (qualifier instanceof PsiReferenceExpression) { - final PsiType type = ((PsiReferenceExpression) qualifier).getType(); - final boolean isJavac7 = JavaVersionService.getInstance().isAtLeast(containingClass, JavaSdkVersion.JDK_1_7); - if (type instanceof PsiClassType && isJavac7 && ((PsiClassType) type).isRaw()) { - return null; - } - final PsiClass typeParameter = PsiUtil.resolveClassInType(type); - if (typeParameter instanceof PsiTypeParameter) { - if (isJavac7) { + return null; + } + + @Nullable + public static HighlightInfo checkParametersOnRaw(PsiReferenceParameterList refParamList) { + JavaResolveResult resolveResult = null; + PsiElement parent = refParamList.getParent(); + PsiElement qualifier = null; + if (parent instanceof PsiJavaCodeReferenceElement) { + resolveResult = ((PsiJavaCodeReferenceElement)parent).advancedResolve(false); + qualifier = ((PsiJavaCodeReferenceElement)parent).getQualifier(); + } + else if (parent instanceof PsiCallExpression) { + resolveResult = ((PsiCallExpression)parent).resolveMethodGenerics(); + if (parent instanceof PsiMethodCallExpression) { + final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)parent).getMethodExpression(); + qualifier = methodExpression.getQualifier(); + } + } + if (resolveResult != null) { + PsiElement element = resolveResult.getElement(); + if (!(element instanceof PsiTypeParameterListOwner)) { + return null; + } + if (((PsiModifierListOwner)element).hasModifierProperty(PsiModifier.STATIC)) { return null; - } - for (PsiClassType classType : typeParameter.getExtendsListTypes()) { - final PsiClass resolve = classType.resolve(); - if (resolve != null) { - final PsiMethod[] superMethods = resolve.findMethodsBySignature((PsiMethod) element, true); - for (PsiMethod superMethod : superMethods) { - if (!PsiUtil.isRawSubstitutor(superMethod, resolveResult.getSubstitutor())) { - return null; + } + if (qualifier instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement)qualifier).resolve() instanceof PsiTypeParameter) { + return null; + } + PsiClass containingClass = ((PsiMember)element).getContainingClass(); + if (containingClass != null && PsiUtil.isRawSubstitutor(containingClass, resolveResult.getSubstitutor())) { + if ((parent instanceof PsiCallExpression || parent instanceof PsiMethodReferenceExpression) + && PsiUtil.isLanguageLevel7OrHigher(parent)) { + return null; + } + + if (element instanceof PsiMethod) { + if (((PsiMethod)element).findSuperMethods().length > 0) { + return null; + } + if (qualifier instanceof PsiReferenceExpression) { + final PsiType type = ((PsiReferenceExpression)qualifier).getType(); + final boolean isJavac7 = JavaVersionService.getInstance().isAtLeast(containingClass, JavaSdkVersion.JDK_1_7); + if (type instanceof PsiClassType && isJavac7 && ((PsiClassType)type).isRaw()) { + return null; + } + final PsiClass typeParameter = PsiUtil.resolveClassInType(type); + if (typeParameter instanceof PsiTypeParameter) { + if (isJavac7) { + return null; + } + for (PsiClassType classType : typeParameter.getExtendsListTypes()) { + final PsiClass resolve = classType.resolve(); + if (resolve != null) { + final PsiMethod[] superMethods = resolve.findMethodsBySignature((PsiMethod)element, true); + for (PsiMethod superMethod : superMethods) { + if (!PsiUtil.isRawSubstitutor(superMethod, resolveResult.getSubstitutor())) { + return null; + } + } + } + } + } } - } } - } + final String message = + element instanceof PsiClass + ? JavaErrorBundle.message("generics.type.arguments.on.raw.type") + : JavaErrorBundle.message("generics.type.arguments.on.raw.method"); + + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(refParamList) + .descriptionAndTooltip(message) + .create(); } - } } - final String message = element instanceof PsiClass ? JavaErrorBundle.message("generics.type.arguments.on.raw.type") : JavaErrorBundle.message("generics.type.arguments.on.raw" + - ".method"); - - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(refParamList).descriptionAndTooltip(message).create(); - } - } - return null; - } - - public static HighlightInfo checkCannotInheritFromEnum(PsiClass superClass, PsiElement elementToHighlight) { - HighlightInfo errorResult = null; - if (Comparing.strEqual("java.lang.Enum", superClass.getQualifiedName())) { - String message = JavaErrorBundle.message("classes.extends.enum"); - errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(elementToHighlight).descriptionAndTooltip(message).create(); + return null; } - return errorResult; - } - public static HighlightInfo checkGenericCannotExtendException(PsiReferenceList list) { - PsiElement parent = list.getParent(); - if (!(parent instanceof PsiClass)) { - return null; + public static HighlightInfo checkCannotInheritFromEnum(PsiClass superClass, PsiElement elementToHighlight) { + HighlightInfo errorResult = null; + if (Comparing.strEqual("java.lang.Enum", superClass.getQualifiedName())) { + String message = JavaErrorBundle.message("classes.extends.enum"); + errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(elementToHighlight) + .descriptionAndTooltip(message) + .create(); + } + return errorResult; } - PsiClass aClass = (PsiClass) parent; - if (!aClass.hasTypeParameters() || aClass.getExtendsList() != list) { - return null; - } - PsiJavaCodeReferenceElement[] referenceElements = list.getReferenceElements(); - PsiClass throwableClass = null; - for (PsiJavaCodeReferenceElement referenceElement : referenceElements) { - PsiElement resolved = referenceElement.resolve(); - if (!(resolved instanceof PsiClass)) { - continue; - } - if (throwableClass == null) { - throwableClass = JavaPsiFacade.getInstance(aClass.getProject()).findClass("java.lang.Throwable", aClass.getResolveScope()); - } - if (InheritanceUtil.isInheritorOrSelf((PsiClass) resolved, throwableClass, true)) { - String message = JavaErrorBundle.message("generic.extend.exception"); - HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(referenceElement).descriptionAndTooltip(message).create(); - PsiClassType classType = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType((PsiClass) resolved); - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance().createExtendsListFix(aClass, classType, false)); - return highlightInfo; - } - } - return null; - } + public static HighlightInfo checkGenericCannotExtendException(PsiReferenceList list) { + PsiElement parent = list.getParent(); + if (!(parent instanceof PsiClass)) { + return null; + } + PsiClass aClass = (PsiClass)parent; - public static HighlightInfo checkEnumMustNotBeLocal(final PsiClass aClass) { - if (!aClass.isEnum()) { - return null; - } - PsiElement parent = aClass.getParent(); - if (!(parent instanceof PsiClass || parent instanceof PsiFile || parent instanceof PsiClassLevelDeclarationStatement)) { - String description = JavaErrorBundle.message("local.enum"); - TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + if (!aClass.hasTypeParameters() || aClass.getExtendsList() != list) { + return null; + } + PsiJavaCodeReferenceElement[] referenceElements = list.getReferenceElements(); + PsiClass throwableClass = null; + for (PsiJavaCodeReferenceElement referenceElement : referenceElements) { + PsiElement resolved = referenceElement.resolve(); + if (!(resolved instanceof PsiClass)) { + continue; + } + if (throwableClass == null) { + throwableClass = JavaPsiFacade.getInstance(aClass.getProject()).findClass("java.lang.Throwable", aClass.getResolveScope()); + } + if (InheritanceUtil.isInheritorOrSelf((PsiClass)resolved, throwableClass, true)) { + String message = JavaErrorBundle.message("generic.extend.exception"); + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(referenceElement) + .descriptionAndTooltip(message) + .create(); + PsiClassType classType = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType((PsiClass)resolved); + QuickFixAction.registerQuickFixAction( + highlightInfo, + QuickFixFactory.getInstance().createExtendsListFix(aClass, classType, false) + ); + return highlightInfo; + } + } + return null; } - return null; - } - public static HighlightInfo checkEnumWithoutConstantsCantHaveAbstractMethods(final PsiClass aClass) { - if (!aClass.isEnum()) { - return null; - } - for (PsiField field : aClass.getFields()) { - if (field instanceof PsiEnumConstant) { + public static HighlightInfo checkEnumMustNotBeLocal(final PsiClass aClass) { + if (!aClass.isEnum()) { + return null; + } + PsiElement parent = aClass.getParent(); + if (!(parent instanceof PsiClass || parent instanceof PsiFile || parent instanceof PsiClassLevelDeclarationStatement)) { + String description = JavaErrorBundle.message("local.enum"); + TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + } return null; - } - } - for (PsiMethod method : aClass.getMethods()) { - if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { - final String description = "Enum declaration without enum constants cannot have abstract methods"; - final TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); - } } - return null; - } - - public static HighlightInfo checkSelectStaticClassFromParameterizedType(final PsiElement resolved, final PsiJavaCodeReferenceElement ref) { - if (resolved instanceof PsiClass && ((PsiClass) resolved).hasModifierProperty(PsiModifier.STATIC)) { - final PsiElement qualifier = ref.getQualifier(); - if (qualifier instanceof PsiJavaCodeReferenceElement) { - final PsiReferenceParameterList parameterList = ((PsiJavaCodeReferenceElement) qualifier).getParameterList(); - if (parameterList != null && parameterList.getTypeArguments().length > 0) { - final String message = JavaErrorBundle.message("generics.select.static.class.from.parameterized.type", HighlightUtil.formatClass((PsiClass) resolved)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parameterList).descriptionAndTooltip(message).create(); - } - } - } - return null; - } - public static HighlightInfo checkCannotInheritFromTypeParameter(final PsiClass superClass, final PsiJavaCodeReferenceElement toHighlight) { - if (superClass instanceof PsiTypeParameter) { - String description = JavaErrorBundle.message("class.cannot.inherit.from.its.type.parameter"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(toHighlight).descriptionAndTooltip(description).create(); - } - return null; - } - - /** - * http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.8 - */ - public static HighlightInfo checkRawOnParameterizedType(@Nonnull PsiJavaCodeReferenceElement parent, PsiElement resolved) { - PsiReferenceParameterList list = parent.getParameterList(); - if (list == null || list.getTypeArguments().length > 0) { - return null; + public static HighlightInfo checkEnumWithoutConstantsCantHaveAbstractMethods(final PsiClass aClass) { + if (!aClass.isEnum()) { + return null; + } + for (PsiField field : aClass.getFields()) { + if (field instanceof PsiEnumConstant) { + return null; + } + } + for (PsiMethod method : aClass.getMethods()) { + if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { + final String description = "Enum declaration without enum constants cannot have abstract methods"; + final TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); + } + } + return null; } - final PsiElement qualifier = parent.getQualifier(); - if (qualifier instanceof PsiJavaCodeReferenceElement && - ((PsiJavaCodeReferenceElement) qualifier).getTypeParameters().length > 0 && - resolved instanceof PsiTypeParameterListOwner && - ((PsiTypeParameterListOwner) resolved).hasTypeParameters() && - !((PsiTypeParameterListOwner) resolved).hasModifierProperty(PsiModifier.STATIC)) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parent).descriptionAndTooltip("Improper formed type; some type parameters are missing").create(); + + public static HighlightInfo checkSelectStaticClassFromParameterizedType( + final PsiElement resolved, + final PsiJavaCodeReferenceElement ref + ) { + if (resolved instanceof PsiClass && ((PsiClass)resolved).hasModifierProperty(PsiModifier.STATIC)) { + final PsiElement qualifier = ref.getQualifier(); + if (qualifier instanceof PsiJavaCodeReferenceElement) { + final PsiReferenceParameterList parameterList = ((PsiJavaCodeReferenceElement)qualifier).getParameterList(); + if (parameterList != null && parameterList.getTypeArguments().length > 0) { + final String message = JavaErrorBundle.message( + "generics.select.static.class.from.parameterized.type", + HighlightUtil.formatClass((PsiClass)resolved) + ); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(parameterList) + .descriptionAndTooltip(message) + .create(); + } + } + } + return null; } - return null; - } - public static HighlightInfo checkCannotPassInner(PsiJavaCodeReferenceElement ref) { - if (ref.getParent() instanceof PsiTypeElement) { - final PsiClass psiClass = PsiTreeUtil.getParentOfType(ref, PsiClass.class); - if (psiClass == null) { + public static HighlightInfo checkCannotInheritFromTypeParameter( + final PsiClass superClass, + final PsiJavaCodeReferenceElement toHighlight + ) { + if (superClass instanceof PsiTypeParameter) { + String description = JavaErrorBundle.message("class.cannot.inherit.from.its.type.parameter"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(toHighlight) + .descriptionAndTooltip(description) + .create(); + } return null; - } - if (PsiTreeUtil.isAncestor(psiClass.getExtendsList(), ref, false) || PsiTreeUtil.isAncestor(psiClass.getImplementsList(), ref, false)) { - final PsiElement qualifier = ref.getQualifier(); - if (qualifier instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement) qualifier).resolve() == psiClass) { - final PsiJavaCodeReferenceElement referenceElement = PsiTreeUtil.getParentOfType(ref, PsiJavaCodeReferenceElement.class); - if (referenceElement == null) { - return null; - } - final PsiElement typeClass = referenceElement.resolve(); - if (!(typeClass instanceof PsiClass)) { - return null; - } - final PsiElement resolve = ref.resolve(); - final PsiClass containingClass = resolve != null ? ((PsiClass) resolve).getContainingClass() : null; - if (containingClass == null) { + } + + /** + * http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.8 + */ + public static HighlightInfo checkRawOnParameterizedType(@Nonnull PsiJavaCodeReferenceElement parent, PsiElement resolved) { + PsiReferenceParameterList list = parent.getParameterList(); + if (list == null || list.getTypeArguments().length > 0) { return null; - } - if (psiClass.isInheritor(containingClass, true) || - unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance((PsiClass) typeClass, ((PsiClass) resolve).getExtendsList()) || - unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance((PsiClass) typeClass, ((PsiClass) resolve).getImplementsList())) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(((PsiClass) resolve).getName() + " is not accessible in current context").range(ref) + } + final PsiElement qualifier = parent.getQualifier(); + if (qualifier instanceof PsiJavaCodeReferenceElement && + ((PsiJavaCodeReferenceElement)qualifier).getTypeParameters().length > 0 && + resolved instanceof PsiTypeParameterListOwner && + ((PsiTypeParameterListOwner)resolved).hasTypeParameters() && + !((PsiTypeParameterListOwner)resolved).hasModifierProperty(PsiModifier.STATIC)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(parent) + .descriptionAndTooltip("Improper formed type; some type parameters are missing") .create(); - } } - } - } - return null; - } - - private static boolean unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance(PsiClass containingClass, PsiReferenceList referenceList) { - if (referenceList != null) { - for (PsiJavaCodeReferenceElement referenceElement : referenceList.getReferenceElements()) { - if (!referenceElement.isQualified()) { - final PsiElement superClass = referenceElement.resolve(); - if (superClass instanceof PsiClass) { - final PsiClass superContainingClass = ((PsiClass) superClass).getContainingClass(); - if (superContainingClass != null && - InheritanceUtil.isInheritorOrSelf(containingClass, superContainingClass, true) && - !PsiTreeUtil.isAncestor(superContainingClass, containingClass, true)) { - return true; - } - } - } - } - } - return false; - } - - private static void registerVariableParameterizedTypeFixes(@Nullable HighlightInfo highlightInfo, - @Nonnull PsiVariable variable, - @Nonnull PsiReferenceParameterList parameterList, - @Nonnull JavaSdkVersion version) { - PsiType type = variable.getType(); - if (!(type instanceof PsiClassType) || highlightInfo == null) { - return; + return null; } - if (DumbService.getInstance(variable.getProject()).isDumb()) { - return; + public static HighlightInfo checkCannotPassInner(PsiJavaCodeReferenceElement ref) { + if (ref.getParent() instanceof PsiTypeElement) { + final PsiClass psiClass = PsiTreeUtil.getParentOfType(ref, PsiClass.class); + if (psiClass == null) { + return null; + } + if (PsiTreeUtil.isAncestor(psiClass.getExtendsList(), ref, false) || PsiTreeUtil.isAncestor( + psiClass.getImplementsList(), + ref, + false + )) { + final PsiElement qualifier = ref.getQualifier(); + if (qualifier instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement)qualifier).resolve() == psiClass) { + final PsiJavaCodeReferenceElement referenceElement = + PsiTreeUtil.getParentOfType(ref, PsiJavaCodeReferenceElement.class); + if (referenceElement == null) { + return null; + } + final PsiElement typeClass = referenceElement.resolve(); + if (!(typeClass instanceof PsiClass)) { + return null; + } + final PsiElement resolve = ref.resolve(); + final PsiClass containingClass = resolve != null ? ((PsiClass)resolve).getContainingClass() : null; + if (containingClass == null) { + return null; + } + if (psiClass.isInheritor(containingClass, true) || + unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance( + (PsiClass)typeClass, + ((PsiClass)resolve).getExtendsList() + ) || + unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance( + (PsiClass)typeClass, + ((PsiClass)resolve).getImplementsList() + )) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .descriptionAndTooltip(((PsiClass)resolve).getName() + " is not accessible in current context") + .range(ref) + .create(); + } + } + } + } + return null; } - String shortName = ((PsiClassType) type).getClassName(); - PsiManager manager = parameterList.getManager(); - final JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); - PsiShortNamesCache shortNamesCache = PsiShortNamesCache.getInstance(parameterList.getProject()); - PsiClass[] classes = shortNamesCache.getClassesByName(shortName, GlobalSearchScope.allScope(manager.getProject())); - PsiElementFactory factory = facade.getElementFactory(); - for (PsiClass aClass : classes) { - if (checkReferenceTypeArgumentList(aClass, parameterList, PsiSubstitutor.EMPTY, false, version) == null) { - PsiType[] actualTypeParameters = parameterList.getTypeArguments(); - PsiTypeParameter[] classTypeParameters = aClass.getTypeParameters(); - Map map = new HashMap<>(); - for (int j = 0; j < classTypeParameters.length; j++) { - PsiTypeParameter classTypeParameter = classTypeParameters[j]; - PsiType actualTypeParameter = actualTypeParameters[j]; - map.put(classTypeParameter, actualTypeParameter); - } - PsiSubstitutor substitutor = factory.createSubstitutor(map); - PsiType suggestedType = factory.createType(aClass, substitutor); - HighlightUtil.registerChangeVariableTypeFixes(variable, suggestedType, variable.getInitializer(), highlightInfo); - } - } - } - - public static HighlightInfo checkInferredIntersections(PsiSubstitutor substitutor, TextRange ref) { - for (Map.Entry typeEntry : substitutor.getSubstitutionMap().entrySet()) { - final String parameterName = typeEntry.getKey().getName(); - final PsiType type = typeEntry.getValue(); - if (type instanceof PsiIntersectionType) { - final String conflictingConjunctsMessage = ((PsiIntersectionType) type).getConflictingConjunctsMessage(); - if (conflictingConjunctsMessage != null) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip("Type parameter " + parameterName + " has incompatible upper bounds: " + - conflictingConjunctsMessage).range(ref).create(); - } - } - } - return null; - } - - public static HighlightInfo areSupersAccessible(@Nonnull PsiClass aClass) { - return areSupersAccessible(aClass, aClass.getResolveScope(), HighlightNamesUtil.getClassDeclarationTextRange(aClass), true); - } - - public static HighlightInfo areSupersAccessible(@Nonnull PsiClass aClass, PsiReferenceExpression ref) { - final GlobalSearchScope resolveScope = ref.getResolveScope(); - final HighlightInfo info = areSupersAccessible(aClass, resolveScope, ref.getTextRange(), false); - if (info != null) { - return info; + private static boolean unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance( + PsiClass containingClass, + PsiReferenceList referenceList + ) { + if (referenceList != null) { + for (PsiJavaCodeReferenceElement referenceElement : referenceList.getReferenceElements()) { + if (!referenceElement.isQualified()) { + final PsiElement superClass = referenceElement.resolve(); + if (superClass instanceof PsiClass) { + final PsiClass superContainingClass = ((PsiClass)superClass).getContainingClass(); + if (superContainingClass != null + && InheritanceUtil.isInheritorOrSelf(containingClass, superContainingClass, true) + && !PsiTreeUtil.isAncestor(superContainingClass, containingClass, true)) { + return true; + } + } + } + } + } + return false; + } + + private static void registerVariableParameterizedTypeFixes( + @Nullable HighlightInfo highlightInfo, + @Nonnull PsiVariable variable, + @Nonnull PsiReferenceParameterList parameterList, + @Nonnull JavaSdkVersion version + ) { + PsiType type = variable.getType(); + if (!(type instanceof PsiClassType) || highlightInfo == null) { + return; + } + + if (DumbService.getInstance(variable.getProject()).isDumb()) { + return; + } + + String shortName = ((PsiClassType)type).getClassName(); + PsiManager manager = parameterList.getManager(); + final JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); + PsiShortNamesCache shortNamesCache = PsiShortNamesCache.getInstance(parameterList.getProject()); + PsiClass[] classes = shortNamesCache.getClassesByName(shortName, GlobalSearchScope.allScope(manager.getProject())); + PsiElementFactory factory = facade.getElementFactory(); + for (PsiClass aClass : classes) { + if (checkReferenceTypeArgumentList(aClass, parameterList, PsiSubstitutor.EMPTY, false, version) == null) { + PsiType[] actualTypeParameters = parameterList.getTypeArguments(); + PsiTypeParameter[] classTypeParameters = aClass.getTypeParameters(); + Map map = new HashMap<>(); + for (int j = 0; j < classTypeParameters.length; j++) { + PsiTypeParameter classTypeParameter = classTypeParameters[j]; + PsiType actualTypeParameter = actualTypeParameters[j]; + map.put(classTypeParameter, actualTypeParameter); + } + PsiSubstitutor substitutor = factory.createSubstitutor(map); + PsiType suggestedType = factory.createType(aClass, substitutor); + HighlightUtil.registerChangeVariableTypeFixes(variable, suggestedType, variable.getInitializer(), highlightInfo); + } + } } - String message = null; - final PsiElement parent = ref.getParent(); - if (parent instanceof PsiMethodCallExpression) { - final JavaResolveResult resolveResult = ((PsiMethodCallExpression) parent).resolveMethodGenerics(); - final PsiMethod method = (PsiMethod) resolveResult.getElement(); - if (method != null) { - final HashSet classes = new HashSet<>(); - final JavaPsiFacade facade = JavaPsiFacade.getInstance(aClass.getProject()); - final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); - - message = isSuperTypeAccessible(substitutor.substitute(method.getReturnType()), classes, false, resolveScope, facade); - if (message == null) { - for (PsiType type : method.getSignature(substitutor).getParameterTypes()) { - - message = isSuperTypeAccessible(type, classes, false, resolveScope, facade); - if (message != null) { - break; - } - } - } - } - } else { - final PsiElement resolve = ref.resolve(); - if (resolve instanceof PsiField) { - message = isSuperTypeAccessible(((PsiField) resolve).getType(), new HashSet<>(), false, resolveScope, JavaPsiFacade.getInstance(aClass.getProject())); - } + public static HighlightInfo checkInferredIntersections(PsiSubstitutor substitutor, TextRange ref) { + for (Map.Entry typeEntry : substitutor.getSubstitutionMap().entrySet()) { + final String parameterName = typeEntry.getKey().getName(); + final PsiType type = typeEntry.getValue(); + if (type instanceof PsiIntersectionType) { + final String conflictingConjunctsMessage = ((PsiIntersectionType)type).getConflictingConjunctsMessage(); + if (conflictingConjunctsMessage != null) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .descriptionAndTooltip("Type parameter " + parameterName + " has incompatible upper bounds: " + + conflictingConjunctsMessage) + .range(ref) + .create(); + } + } + } + return null; } - if (message != null) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(message).range(ref.getTextRange()).create(); + public static HighlightInfo areSupersAccessible(@Nonnull PsiClass aClass) { + return areSupersAccessible(aClass, aClass.getResolveScope(), HighlightNamesUtil.getClassDeclarationTextRange(aClass), true); } + public static HighlightInfo areSupersAccessible(@Nonnull PsiClass aClass, PsiReferenceExpression ref) { + final GlobalSearchScope resolveScope = ref.getResolveScope(); + final HighlightInfo info = areSupersAccessible(aClass, resolveScope, ref.getTextRange(), false); + if (info != null) { + return info; + } - return null; - } + String message = null; + final PsiElement parent = ref.getParent(); + if (parent instanceof PsiMethodCallExpression) { + final JavaResolveResult resolveResult = ((PsiMethodCallExpression)parent).resolveMethodGenerics(); + final PsiMethod method = (PsiMethod)resolveResult.getElement(); + if (method != null) { + final HashSet classes = new HashSet<>(); + final JavaPsiFacade facade = JavaPsiFacade.getInstance(aClass.getProject()); + final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); + + message = isSuperTypeAccessible(substitutor.substitute(method.getReturnType()), classes, false, resolveScope, facade); + if (message == null) { + for (PsiType type : method.getSignature(substitutor).getParameterTypes()) { + + message = isSuperTypeAccessible(type, classes, false, resolveScope, facade); + if (message != null) { + break; + } + } + } + } + } + else { + final PsiElement resolve = ref.resolve(); + if (resolve instanceof PsiField) { + message = isSuperTypeAccessible( + ((PsiField)resolve).getType(), + new HashSet<>(), + false, + resolveScope, + JavaPsiFacade.getInstance(aClass.getProject()) + ); + } + } + + if (message != null) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .descriptionAndTooltip(message) + .range(ref.getTextRange()) + .create(); + } - private static HighlightInfo areSupersAccessible(@Nonnull PsiClass aClass, GlobalSearchScope resolveScope, TextRange range, boolean checkParameters) { - final JavaPsiFacade factory = JavaPsiFacade.getInstance(aClass.getProject()); - for (PsiClassType superType : aClass.getSuperTypes()) { - final String notAccessibleErrorMessage = isSuperTypeAccessible(superType, new HashSet<>(), checkParameters, resolveScope, factory); - if (notAccessibleErrorMessage != null) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(notAccessibleErrorMessage).range(range).create(); - } - } - return null; - } - - @Nullable - private static String isSuperTypeAccessible(PsiType superType, HashSet classes, boolean checkParameters, GlobalSearchScope resolveScope, JavaPsiFacade factory) { - final PsiClass aClass = PsiUtil.resolveClassInType(superType); - if (aClass != null && classes.add(aClass)) { - VirtualFile vFile = PsiUtilCore.getVirtualFile(aClass); - if (vFile == null) { return null; - } - FileIndexFacade index = FileIndexFacade.getInstance(aClass.getProject()); - if (!index.isInSource(vFile) && !index.isInLibraryClasses(vFile)) { + } + + private static HighlightInfo areSupersAccessible( + @Nonnull PsiClass aClass, + GlobalSearchScope resolveScope, + TextRange range, + boolean checkParameters + ) { + final JavaPsiFacade factory = JavaPsiFacade.getInstance(aClass.getProject()); + for (PsiClassType superType : aClass.getSuperTypes()) { + final String notAccessibleErrorMessage = + isSuperTypeAccessible(superType, new HashSet<>(), checkParameters, resolveScope, factory); + if (notAccessibleErrorMessage != null) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .descriptionAndTooltip(notAccessibleErrorMessage) + .range(range) + .create(); + } + } return null; - } + } - final String qualifiedName = aClass.getQualifiedName(); - if (qualifiedName != null && factory.findClass(qualifiedName, resolveScope) == null) { - return "Cannot access " + HighlightUtil.formatClass(aClass); - } + @Nullable + private static String isSuperTypeAccessible( + PsiType superType, + HashSet classes, + boolean checkParameters, + GlobalSearchScope resolveScope, + JavaPsiFacade factory + ) { + final PsiClass aClass = PsiUtil.resolveClassInType(superType); + if (aClass != null && classes.add(aClass)) { + VirtualFile vFile = PsiUtilCore.getVirtualFile(aClass); + if (vFile == null) { + return null; + } + FileIndexFacade index = FileIndexFacade.getInstance(aClass.getProject()); + if (!index.isInSource(vFile) && !index.isInLibraryClasses(vFile)) { + return null; + } - if (checkParameters) { - boolean isInLibrary = !index.isInContent(vFile); - if (superType instanceof PsiClassType) { - for (PsiType psiType : ((PsiClassType) superType).getParameters()) { - final String notAccessibleMessage = isSuperTypeAccessible(psiType, classes, true, resolveScope, factory); - if (notAccessibleMessage != null) { - return notAccessibleMessage; + final String qualifiedName = aClass.getQualifiedName(); + if (qualifiedName != null && factory.findClass(qualifiedName, resolveScope) == null) { + return "Cannot access " + HighlightUtil.formatClass(aClass); } - } - } - for (PsiClassType type : aClass.getSuperTypes()) { - final String notAccessibleMessage = isSuperTypeAccessible(type, classes, !isInLibrary, resolveScope, factory); - if (notAccessibleMessage != null) { - return notAccessibleMessage; - } + if (checkParameters) { + boolean isInLibrary = !index.isInContent(vFile); + if (superType instanceof PsiClassType) { + for (PsiType psiType : ((PsiClassType)superType).getParameters()) { + final String notAccessibleMessage = isSuperTypeAccessible(psiType, classes, true, resolveScope, factory); + if (notAccessibleMessage != null) { + return notAccessibleMessage; + } + } + } + + for (PsiClassType type : aClass.getSuperTypes()) { + final String notAccessibleMessage = isSuperTypeAccessible(type, classes, !isInLibrary, resolveScope, factory); + if (notAccessibleMessage != null) { + return notAccessibleMessage; + } + } + } } - } + return null; } - return null; - } - - public static HighlightInfo checkTypeParameterOverrideEquivalentMethods(PsiClass aClass, LanguageLevel level) { - if (aClass instanceof PsiTypeParameter && level.isAtLeast(LanguageLevel.JDK_1_7)) { - final PsiReferenceList extendsList = aClass.getExtendsList(); - if (extendsList != null && extendsList.getReferenceElements().length > 1) { - //todo suppress erased methods which come from the same class - final Collection result = checkOverrideEquivalentMethods(aClass); - if (result != null && !result.isEmpty()) { - return result.iterator().next(); - } - } + + public static HighlightInfo checkTypeParameterOverrideEquivalentMethods(PsiClass aClass, LanguageLevel level) { + if (aClass instanceof PsiTypeParameter && level.isAtLeast(LanguageLevel.JDK_1_7)) { + final PsiReferenceList extendsList = aClass.getExtendsList(); + if (extendsList != null && extendsList.getReferenceElements().length > 1) { + //todo suppress erased methods which come from the same class + final Collection result = checkOverrideEquivalentMethods(aClass); + if (result != null && !result.isEmpty()) { + return result.iterator().next(); + } + } + } + return null; } - return null; - } } - diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightClassUtil.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightClassUtil.java index 467f41da7b..32fd6b28cd 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightClassUtil.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightClassUtil.java @@ -51,1025 +51,1188 @@ import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; public class HighlightClassUtil { - - /** - * new ref(...) or new ref(..) { ... } where ref is abstract class - */ - @Nullable - public static HighlightInfo checkAbstractInstantiation(@Nonnull PsiJavaCodeReferenceElement ref) { - PsiElement parent = ref.getParent(); - HighlightInfo highlightInfo = null; - if (parent instanceof PsiAnonymousClass && parent.getParent() instanceof PsiNewExpression && !PsiUtilCore - .hasErrorElementChild(parent.getParent())) { - PsiAnonymousClass aClass = (PsiAnonymousClass) parent; - highlightInfo = checkClassWithAbstractMethods(aClass, ref.getTextRange()); - } - return highlightInfo; - } - - @Nullable - private static HighlightInfo checkClassWithAbstractMethods(PsiClass aClass, TextRange range) { - return checkClassWithAbstractMethods(aClass, aClass, range); - } - - @Nullable - public static HighlightInfo checkClassWithAbstractMethods(PsiClass aClass, - PsiElement implementsFixElement, - TextRange range) { - PsiMethod abstractMethod = ClassUtil.getAnyAbstractMethod(aClass); - - if (abstractMethod == null) { - return null; + /** + * new ref(...) or new ref(..) { ... } where ref is abstract class + */ + @Nullable + public static HighlightInfo checkAbstractInstantiation(@Nonnull PsiJavaCodeReferenceElement ref) { + PsiElement parent = ref.getParent(); + HighlightInfo highlightInfo = null; + if (parent instanceof PsiAnonymousClass && parent.getParent() instanceof PsiNewExpression && !PsiUtilCore + .hasErrorElementChild(parent.getParent())) { + PsiAnonymousClass aClass = (PsiAnonymousClass)parent; + highlightInfo = checkClassWithAbstractMethods(aClass, ref.getTextRange()); + } + return highlightInfo; } - final PsiClass superClass = abstractMethod.getContainingClass(); - if (superClass == null) { - return null; + @Nullable + private static HighlightInfo checkClassWithAbstractMethods(PsiClass aClass, TextRange range) { + return checkClassWithAbstractMethods(aClass, aClass, range); } - String baseClassName = HighlightUtil.formatClass(aClass, false); - String methodName = JavaHighlightUtil.formatMethod(abstractMethod); - String message = JavaErrorBundle.message(aClass instanceof PsiEnumConstantInitializer || - implementsFixElement instanceof PsiEnumConstant ? "enum.constant.should.implement.method" : "class" + - ".must.be.abstract", baseClassName, methodName, HighlightUtil.formatClass(superClass, false)); - - HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range) - .descriptionAndTooltip(message).create(); - final PsiMethod anyMethodToImplement = ClassUtil.getAnyMethodToImplement(aClass); - if (anyMethodToImplement != null) { - if (!anyMethodToImplement.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) || JavaPsiFacade.getInstance - (aClass.getProject()).arePackagesTheSame(aClass, superClass)) { - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createImplementMethodsFix - (implementsFixElement)); - } else { - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createModifierListFix - (anyMethodToImplement, PsiModifier.PROTECTED, true, true)); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createModifierListFix - (anyMethodToImplement, PsiModifier.PUBLIC, true, true)); - } - } - if (!(aClass instanceof PsiAnonymousClass) && HighlightUtil.getIncompatibleModifier(PsiModifier.ABSTRACT, - aClass.getModifierList()) == null) { - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createModifierListFix(aClass, - PsiModifier.ABSTRACT, true, false)); - } - return errorResult; - } - - @Nullable - public static HighlightInfo checkClassMustBeAbstract(final PsiClass aClass, final TextRange textRange) { - if (aClass.hasModifierProperty(PsiModifier.ABSTRACT) || aClass.getRBrace() == null || aClass.isEnum() && - hasEnumConstants(aClass)) { - return null; - } - return checkClassWithAbstractMethods(aClass, textRange); - } - - @Nullable - public static HighlightInfo checkInstantiationOfAbstractClass(PsiClass aClass, @Nonnull PsiElement highlightElement) { - HighlightInfo errorResult = null; - if (aClass != null && aClass.hasModifierProperty(PsiModifier.ABSTRACT) && (!(highlightElement instanceof - PsiNewExpression) || !(((PsiNewExpression) highlightElement).getType() instanceof PsiArrayType))) { - String baseClassName = aClass.getName(); - String message = JavaErrorBundle.message("abstract.cannot.be.instantiated", baseClassName); - errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(highlightElement) - .descriptionAndTooltip(message).create(); - final PsiMethod anyAbstractMethod = ClassUtil.getAnyAbstractMethod(aClass); - if (!aClass.isInterface() && anyAbstractMethod == null) { - // suggest to make not abstract only if possible - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createModifierListFix(aClass, - PsiModifier.ABSTRACT, false, false)); - } - if (anyAbstractMethod != null && highlightElement instanceof PsiNewExpression && ((PsiNewExpression) - highlightElement).getClassReference() != null) { - QuickFixAction.registerQuickFixAction(errorResult, - QuickFixFactory.getInstance().createImplementAbstractClassMethodsFix(highlightElement)); - } - } - return errorResult; - } + @Nullable + public static HighlightInfo checkClassWithAbstractMethods( + PsiClass aClass, + PsiElement implementsFixElement, + TextRange range + ) { + PsiMethod abstractMethod = ClassUtil.getAnyAbstractMethod(aClass); - private static boolean hasEnumConstants(PsiClass aClass) { - PsiField[] fields = aClass.getFields(); - for (PsiField field : fields) { - if (field instanceof PsiEnumConstant) { - return true; - } - } - return false; - } + if (abstractMethod == null) { + return null; + } - @Nullable - public static HighlightInfo checkDuplicateTopLevelClass(PsiClass aClass) { - if (!(aClass.getParent() instanceof PsiFile)) { - return null; - } - String qualifiedName = aClass.getQualifiedName(); - if (qualifiedName == null) { - return null; - } - int numOfClassesToFind = 2; - if (qualifiedName.contains("$")) { - qualifiedName = qualifiedName.replaceAll("\\$", "."); - numOfClassesToFind = 1; - } - PsiManager manager = aClass.getManager(); - Module module = ModuleUtilCore.findModuleForPsiElement(aClass); - if (module == null) { - return null; - } + final PsiClass superClass = abstractMethod.getContainingClass(); + if (superClass == null) { + return null; + } - PsiClass[] classes = JavaPsiFacade.getInstance(aClass.getProject()).findClasses(qualifiedName, - GlobalSearchScope.moduleScope(module)); - if (classes.length < numOfClassesToFind) { - return null; + String baseClassName = HighlightUtil.formatClass(aClass, false); + String methodName = JavaHighlightUtil.formatMethod(abstractMethod); + String message = JavaErrorBundle.message( + aClass instanceof PsiEnumConstantInitializer || implementsFixElement instanceof PsiEnumConstant + ? "enum.constant.should.implement.method" + : "class.must.be.abstract", + baseClassName, + methodName, + HighlightUtil.formatClass(superClass, false) + ); + + HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range) + .descriptionAndTooltip(message).create(); + final PsiMethod anyMethodToImplement = ClassUtil.getAnyMethodToImplement(aClass); + if (anyMethodToImplement != null) { + if (!anyMethodToImplement.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) + || JavaPsiFacade.getInstance(aClass.getProject()).arePackagesTheSame(aClass, superClass)) { + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createImplementMethodsFix(implementsFixElement) + ); + } + else { + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createModifierListFix(anyMethodToImplement, PsiModifier.PROTECTED, true, true) + ); + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createModifierListFix(anyMethodToImplement, PsiModifier.PUBLIC, true, true) + ); + } + } + if (!(aClass instanceof PsiAnonymousClass) + && HighlightUtil.getIncompatibleModifier(PsiModifier.ABSTRACT, aClass.getModifierList()) == null) { + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createModifierListFix(aClass, PsiModifier.ABSTRACT, true, false) + ); + } + return errorResult; } - String dupFileName = null; - for (PsiClass dupClass : classes) { - // do not use equals - if (dupClass != aClass) { - VirtualFile file = dupClass.getContainingFile().getVirtualFile(); - if (file != null && manager.isInProject(dupClass)) { - dupFileName = FileUtil.toSystemDependentName(file.getPath()); - break; - } - } + + @Nullable + public static HighlightInfo checkClassMustBeAbstract(final PsiClass aClass, final TextRange textRange) { + if (aClass.hasModifierProperty(PsiModifier.ABSTRACT) || aClass.getRBrace() == null || aClass.isEnum() && + hasEnumConstants(aClass)) { + return null; + } + return checkClassWithAbstractMethods(aClass, textRange); + } + + @Nullable + public static HighlightInfo checkInstantiationOfAbstractClass(PsiClass aClass, @Nonnull PsiElement highlightElement) { + HighlightInfo errorResult = null; + if (aClass != null && aClass.hasModifierProperty(PsiModifier.ABSTRACT) && (!(highlightElement instanceof + PsiNewExpression) || !(((PsiNewExpression)highlightElement).getType() instanceof PsiArrayType))) { + String baseClassName = aClass.getName(); + String message = JavaErrorBundle.message("abstract.cannot.be.instantiated", baseClassName); + errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(highlightElement) + .descriptionAndTooltip(message) + .create(); + final PsiMethod anyAbstractMethod = ClassUtil.getAnyAbstractMethod(aClass); + if (!aClass.isInterface() && anyAbstractMethod == null) { + // suggest to make not abstract only if possible + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createModifierListFix(aClass, PsiModifier.ABSTRACT, false, false) + ); + } + if (anyAbstractMethod != null && highlightElement instanceof PsiNewExpression && ((PsiNewExpression) + highlightElement).getClassReference() != null) { + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createImplementAbstractClassMethodsFix(highlightElement) + ); + } + } + return errorResult; } - if (dupFileName == null) { - return null; + + private static boolean hasEnumConstants(PsiClass aClass) { + PsiField[] fields = aClass.getFields(); + for (PsiField field : fields) { + if (field instanceof PsiEnumConstant) { + return true; + } + } + return false; } - String message = JavaErrorBundle.message("duplicate.class.in.other.file", dupFileName); - TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(message) - .create(); - } + @Nullable + public static HighlightInfo checkDuplicateTopLevelClass(PsiClass aClass) { + if (!(aClass.getParent() instanceof PsiFile)) { + return null; + } + String qualifiedName = aClass.getQualifiedName(); + if (qualifiedName == null) { + return null; + } + int numOfClassesToFind = 2; + if (qualifiedName.contains("$")) { + qualifiedName = qualifiedName.replaceAll("\\$", "."); + numOfClassesToFind = 1; + } + PsiManager manager = aClass.getManager(); + Module module = ModuleUtilCore.findModuleForPsiElement(aClass); + if (module == null) { + return null; + } + + PsiClass[] classes = JavaPsiFacade.getInstance(aClass.getProject()) + .findClasses(qualifiedName, GlobalSearchScope.moduleScope(module)); + if (classes.length < numOfClassesToFind) { + return null; + } + String dupFileName = null; + for (PsiClass dupClass : classes) { + // do not use equals + if (dupClass != aClass) { + VirtualFile file = dupClass.getContainingFile().getVirtualFile(); + if (file != null && manager.isInProject(dupClass)) { + dupFileName = FileUtil.toSystemDependentName(file.getPath()); + break; + } + } + } + if (dupFileName == null) { + return null; + } + String message = JavaErrorBundle.message("duplicate.class.in.other.file", dupFileName); + TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - @Nullable - public static HighlightInfo checkDuplicateNestedClass(PsiClass aClass) { - if (aClass == null) { - return null; - } - PsiElement parent = aClass; - if (aClass.getParent() instanceof PsiDeclarationStatement) { - parent = aClass.getParent(); - } - String name = aClass.getName(); - if (name == null) { - return null; - } - boolean duplicateFound = false; - boolean checkSiblings = true; - while (parent != null) { - if (parent instanceof PsiFile) { - break; - } - PsiElement element = checkSiblings ? parent.getPrevSibling() : null; - if (element == null) { - element = parent.getParent(); - // JLS 14.3: - // The name of a local class C may not be redeclared - // as a local class of the directly enclosing method, constructor, or initializer block within the - // scope of C - // , or a compile-time error occurs. - // However, a local class declaration may be shadowed (?6.3.1) - // anywhere inside a class declaration nested within the local class declaration's scope. - if (element instanceof PsiMethod || element instanceof PsiClass || - element instanceof PsiCodeBlock && element.getParent() instanceof PsiClassInitializer) { - checkSiblings = false; - } - } - parent = element; - - if (element instanceof PsiDeclarationStatement) { - element = PsiTreeUtil.getChildOfType(element, PsiClass.class); - } - if (element instanceof PsiClass && name.equals(((PsiClass) element).getName())) { - duplicateFound = true; - break; - } + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(textRange) + .descriptionAndTooltip(message) + .create(); } - if (duplicateFound) { - String message = JavaErrorBundle.message("duplicate.class", name); - TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip - (message).create(); - } - return null; - } - - @Nullable - public static HighlightInfo checkPublicClassInRightFile(PsiClass aClass) { - PsiFile containingFile = aClass.getContainingFile(); - if (aClass.getParent() != containingFile || !aClass.hasModifierProperty(PsiModifier.PUBLIC) || !(containingFile instanceof PsiJavaFile)) { - return null; - } - PsiJavaFile file = (PsiJavaFile) containingFile; - VirtualFile virtualFile = file.getVirtualFile(); - if (virtualFile == null || aClass.getName().equals(virtualFile.getNameWithoutExtension())) { - return null; - } - String message = JavaErrorBundle.message("public.class.should.be.named.after.file", aClass.getName()); - TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR). - range(aClass, range.getStartOffset(), range.getEndOffset()). - descriptionAndTooltip(message).create(); - PsiModifierList psiModifierList = aClass.getModifierList(); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createModifierListFix(psiModifierList, - PsiModifier.PUBLIC, false, false)); - PsiClass[] classes = file.getClasses(); - if (classes.length > 1) { - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createMoveClassToSeparateFileFix - (aClass)); + @Nullable + public static HighlightInfo checkDuplicateNestedClass(PsiClass aClass) { + if (aClass == null) { + return null; + } + PsiElement parent = aClass; + if (aClass.getParent() instanceof PsiDeclarationStatement) { + parent = aClass.getParent(); + } + String name = aClass.getName(); + if (name == null) { + return null; + } + boolean duplicateFound = false; + boolean checkSiblings = true; + while (parent != null) { + if (parent instanceof PsiFile) { + break; + } + PsiElement element = checkSiblings ? parent.getPrevSibling() : null; + if (element == null) { + element = parent.getParent(); + // JLS 14.3: + // The name of a local class C may not be redeclared + // as a local class of the directly enclosing method, constructor, or initializer block within the + // scope of C + // , or a compile-time error occurs. + // However, a local class declaration may be shadowed (?6.3.1) + // anywhere inside a class declaration nested within the local class declaration's scope. + if (element instanceof PsiMethod || element instanceof PsiClass || + element instanceof PsiCodeBlock && element.getParent() instanceof PsiClassInitializer) { + checkSiblings = false; + } + } + parent = element; + + if (element instanceof PsiDeclarationStatement) { + element = PsiTreeUtil.getChildOfType(element, PsiClass.class); + } + if (element instanceof PsiClass && name.equals(((PsiClass)element).getName())) { + duplicateFound = true; + break; + } + } + + if (duplicateFound) { + String message = JavaErrorBundle.message("duplicate.class", name); + TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip + (message).create(); + } + return null; } - for (PsiClass otherClass : classes) { - if (!otherClass.getManager().areElementsEquivalent(otherClass, aClass) && - otherClass.hasModifierProperty(PsiModifier.PUBLIC) && - otherClass.getName().equals(virtualFile.getNameWithoutExtension())) { + + @Nullable + public static HighlightInfo checkPublicClassInRightFile(PsiClass aClass) { + PsiFile containingFile = aClass.getContainingFile(); + if (aClass.getParent() != containingFile || !aClass.hasModifierProperty(PsiModifier.PUBLIC) || !(containingFile instanceof PsiJavaFile)) { + return null; + } + PsiJavaFile file = (PsiJavaFile)containingFile; + VirtualFile virtualFile = file.getVirtualFile(); + if (virtualFile == null || aClass.getName().equals(virtualFile.getNameWithoutExtension())) { + return null; + } + String message = JavaErrorBundle.message("public.class.should.be.named.after.file", aClass.getName()); + TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); + HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR). + range(aClass, range.getStartOffset(), range.getEndOffset()). + descriptionAndTooltip(message).create(); + PsiModifierList psiModifierList = aClass.getModifierList(); + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createModifierListFix(psiModifierList, PsiModifier.PUBLIC, false, false) + ); + PsiClass[] classes = file.getClasses(); + if (classes.length > 1) { + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createMoveClassToSeparateFileFix(aClass) + ); + } + for (PsiClass otherClass : classes) { + if (!otherClass.getManager().areElementsEquivalent(otherClass, aClass) + && otherClass.hasModifierProperty(PsiModifier.PUBLIC) + && otherClass.getName().equals(virtualFile.getNameWithoutExtension())) { + return errorResult; + } + } + QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createRenameFileFix(aClass.getName() + + JavaFileType.DOT_DEFAULT_EXTENSION)); + QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createRenameElementFix(aClass)); return errorResult; - } - } - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createRenameFileFix(aClass.getName() + - JavaFileType.DOT_DEFAULT_EXTENSION)); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createRenameElementFix(aClass)); - return errorResult; - } - - @Nullable - public static HighlightInfo checkClassAndPackageConflict(@Nonnull PsiClass aClass) { - String name = aClass.getQualifiedName(); - - if (JavaClassNames.DEFAULT_PACKAGE.equals(name)) { - String message = JavaErrorBundle.message("class.clashes.with.package", name); - TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip(message) - .create(); } - PsiElement file = aClass.getParent(); - if (file instanceof PsiJavaFile && !((PsiJavaFile) file).getPackageName().isEmpty()) { - PsiElement directory = file.getParent(); - if (directory instanceof PsiDirectory) { - String simpleName = aClass.getName(); - PsiDirectory subDirectory = ((PsiDirectory) directory).findSubdirectory(simpleName); - if (subDirectory != null && simpleName.equals(subDirectory.getName())) { - String message = JavaErrorBundle.message("class.clashes.with.package", name); - TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip - (message).create(); - } - } - } + @Nullable + public static HighlightInfo checkClassAndPackageConflict(@Nonnull PsiClass aClass) { + String name = aClass.getQualifiedName(); - return null; - } + if (JavaClassNames.DEFAULT_PACKAGE.equals(name)) { + String message = JavaErrorBundle.message("class.clashes.with.package", name); + TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(range) + .descriptionAndTooltip(message) + .create(); + } - @Nullable - private static HighlightInfo checkStaticFieldDeclarationInInnerClass(@Nonnull PsiKeyword keyword) { - if (getEnclosingStaticClass(keyword, PsiField.class) == null) { - return null; - } + PsiElement file = aClass.getParent(); + if (file instanceof PsiJavaFile && !((PsiJavaFile)file).getPackageName().isEmpty()) { + PsiElement directory = file.getParent(); + if (directory instanceof PsiDirectory) { + String simpleName = aClass.getName(); + PsiDirectory subDirectory = ((PsiDirectory)directory).findSubdirectory(simpleName); + if (subDirectory != null && simpleName.equals(subDirectory.getName())) { + String message = JavaErrorBundle.message("class.clashes.with.package", name); + TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(range) + .descriptionAndTooltip(message) + .create(); + } + } + } - PsiField field = (PsiField) keyword.getParent().getParent(); - if (PsiUtilCore.hasErrorElementChild(field) || PsiUtil.isCompileTimeConstant(field)) { - return null; + return null; } - String message = JavaErrorBundle.message("static.declaration.in.inner.class"); - HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(keyword) - .descriptionAndTooltip(message).create(); + @Nullable + private static HighlightInfo checkStaticFieldDeclarationInInnerClass(@Nonnull PsiKeyword keyword) { + if (getEnclosingStaticClass(keyword, PsiField.class) == null) { + return null; + } + + PsiField field = (PsiField)keyword.getParent().getParent(); + if (PsiUtilCore.hasErrorElementChild(field) || PsiUtil.isCompileTimeConstant(field)) { + return null; + } - QuickFixAction.registerQuickFixAction(result, QuickFixFactory.getInstance().createModifierListFix(field, - PsiModifier.STATIC, false, false)); + String message = JavaErrorBundle.message("static.declaration.in.inner.class"); + HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(keyword) + .descriptionAndTooltip(message) + .create(); + + QuickFixAction.registerQuickFixAction( + result, + QuickFixFactory.getInstance().createModifierListFix(field, PsiModifier.STATIC, false, false) + ); + + PsiClass aClass = field.getContainingClass(); + if (aClass != null) { + QuickFixAction.registerQuickFixAction( + result, + QuickFixFactory.getInstance().createModifierListFix(aClass, PsiModifier.STATIC, true, false) + ); + } - PsiClass aClass = field.getContainingClass(); - if (aClass != null) { - QuickFixAction.registerQuickFixAction(result, QuickFixFactory.getInstance().createModifierListFix(aClass, - PsiModifier.STATIC, true, false)); + return result; } - return result; - } + @Nullable + private static HighlightInfo checkStaticMethodDeclarationInInnerClass(PsiKeyword keyword, LanguageLevel languageLevel) { + if (languageLevel.isAtLeast(LanguageLevel.JDK_16)) { + return null; + } - @Nullable - private static HighlightInfo checkStaticMethodDeclarationInInnerClass(PsiKeyword keyword, LanguageLevel languageLevel) { - if (languageLevel.isAtLeast(LanguageLevel.JDK_16)) { - return null; - } + if (getEnclosingStaticClass(keyword, PsiMethod.class) == null) { + return null; + } + PsiMethod method = (PsiMethod)keyword.getParent().getParent(); + if (PsiUtilCore.hasErrorElementChild(method)) { + return null; + } + String message = JavaErrorBundle.message("static.declaration.in.inner.class"); + HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(keyword) + .descriptionAndTooltip(message) + .create(); + QuickFixAction.registerQuickFixAction( + result, + QuickFixFactory.getInstance().createModifierListFix(method, PsiModifier.STATIC, false, false) + ); + QuickFixAction.registerQuickFixAction( + result, + QuickFixFactory.getInstance().createModifierListFix( + (PsiClass)keyword.getParent().getParent().getParent(), + PsiModifier.STATIC, + true, + false + ) + ); + return result; + } + + @Nullable + private static HighlightInfo checkStaticInitializerDeclarationInInnerClass(PsiKeyword keyword) { + if (getEnclosingStaticClass(keyword, PsiClassInitializer.class) == null) { + return null; + } + PsiClassInitializer initializer = (PsiClassInitializer)keyword.getParent().getParent(); + if (PsiUtilCore.hasErrorElementChild(initializer)) { + return null; + } + String message = JavaErrorBundle.message("static.declaration.in.inner.class"); + HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(keyword) + .descriptionAndTooltip(message) + .create(); + QuickFixAction.registerQuickFixAction( + result, + QuickFixFactory.getInstance().createModifierListFix(initializer, PsiModifier.STATIC, false, false) + ); + PsiClass owner = (PsiClass)keyword.getParent().getParent().getParent(); + QuickFixAction.registerQuickFixAction( + result, + QuickFixFactory.getInstance().createModifierListFix(owner, PsiModifier.STATIC, true, false) + ); + return result; + } + + private static PsiElement getEnclosingStaticClass(@Nonnull PsiKeyword keyword, @Nonnull Class parentClass) { + return new PsiMatcherImpl(keyword) + .dot(PsiMatchers.hasText(PsiModifier.STATIC)) + .parent(PsiMatchers.hasClass(PsiModifierList.class)) + .parent(PsiMatchers.hasClass(parentClass)) + .parent(PsiMatchers.hasClass(PsiClass.class)) + .dot(JavaMatchers.hasModifier(PsiModifier.STATIC, false)) + .parent(PsiMatchers.hasClass(PsiClass.class, PsiDeclarationStatement.class, PsiNewExpression.class, PsiEnumConstant.class)) + .getElement(); + } + + @Nullable + private static HighlightInfo checkStaticClassDeclarationInInnerClass(PsiKeyword keyword) { + // keyword points to 'class' or 'interface' or 'enum' + if (new PsiMatcherImpl(keyword) + .parent(PsiMatchers.hasClass(PsiClass.class)) + .dot(JavaMatchers.hasModifier(PsiModifier.STATIC, true)) + .parent(PsiMatchers.hasClass(PsiClass.class)) + .dot(JavaMatchers.hasModifier(PsiModifier.STATIC, false)) + .parent(PsiMatchers.hasClass(PsiClass.class, PsiDeclarationStatement.class, PsiNewExpression.class, PsiEnumConstant.class)) + .getElement() == null) { + return null; + } - if (getEnclosingStaticClass(keyword, PsiMethod.class) == null) { - return null; - } - PsiMethod method = (PsiMethod)keyword.getParent().getParent(); - if (PsiUtilCore.hasErrorElementChild(method)) { - return null; - } - String message = JavaErrorBundle.message("static.declaration.in.inner.class"); - HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(keyword) - .descriptionAndTooltip(message).create(); - QuickFixAction.registerQuickFixAction(result, QuickFixFactory.getInstance().createModifierListFix(method, - PsiModifier.STATIC, false, false)); - QuickFixAction.registerQuickFixAction(result, QuickFixFactory.getInstance().createModifierListFix((PsiClass)keyword - .getParent().getParent().getParent(), PsiModifier.STATIC, true, false)); - return result; - } - - @Nullable - private static HighlightInfo checkStaticInitializerDeclarationInInnerClass(PsiKeyword keyword) { - if (getEnclosingStaticClass(keyword, PsiClassInitializer.class) == null) { - return null; - } - PsiClassInitializer initializer = (PsiClassInitializer) keyword.getParent().getParent(); - if (PsiUtilCore.hasErrorElementChild(initializer)) { - return null; - } - String message = JavaErrorBundle.message("static.declaration.in.inner.class"); - HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(keyword) - .descriptionAndTooltip(message).create(); - QuickFixAction.registerQuickFixAction(result, QuickFixFactory.getInstance().createModifierListFix(initializer, - PsiModifier.STATIC, false, false)); - PsiClass owner = (PsiClass) keyword.getParent().getParent().getParent(); - QuickFixAction.registerQuickFixAction(result, QuickFixFactory.getInstance().createModifierListFix(owner, - PsiModifier.STATIC, true, false)); - return result; - } - - private static PsiElement getEnclosingStaticClass(@Nonnull PsiKeyword keyword, @Nonnull Class parentClass) { - return new PsiMatcherImpl(keyword).dot(PsiMatchers.hasText(PsiModifier.STATIC)).parent(PsiMatchers.hasClass - (PsiModifierList.class)).parent(PsiMatchers.hasClass(parentClass)).parent(PsiMatchers.hasClass - (PsiClass.class)).dot(JavaMatchers.hasModifier(PsiModifier.STATIC, false)).parent(PsiMatchers.hasClass - (PsiClass.class, PsiDeclarationStatement.class, PsiNewExpression.class, - PsiEnumConstant.class)).getElement(); - } - - @Nullable - private static HighlightInfo checkStaticClassDeclarationInInnerClass(PsiKeyword keyword) { - // keyword points to 'class' or 'interface' or 'enum' - if (new PsiMatcherImpl(keyword).parent(PsiMatchers.hasClass(PsiClass.class)).dot(JavaMatchers.hasModifier - (PsiModifier.STATIC, true)).parent(PsiMatchers.hasClass(PsiClass.class)).dot(JavaMatchers.hasModifier - (PsiModifier.STATIC, false)).parent(PsiMatchers.hasClass(PsiClass.class, - PsiDeclarationStatement.class, PsiNewExpression.class, PsiEnumConstant.class)).getElement() == null) { - return null; - } + PsiClass aClass = (PsiClass)keyword.getParent(); + if (PsiUtilCore.hasErrorElementChild(aClass)) { + return null; + } - PsiClass aClass = (PsiClass) keyword.getParent(); - if (PsiUtilCore.hasErrorElementChild(aClass)) { - return null; + // highlight 'static' keyword if any, or class or interface if not + PsiElement context = null; + PsiModifierList modifierList = aClass.getModifierList(); + if (modifierList != null) { + for (PsiElement element : modifierList.getChildren()) { + if (Comparing.equal(element.getText(), PsiModifier.STATIC)) { + context = element; + break; + } + } + } + TextRange range = context != null ? context.getTextRange() : HighlightNamesUtil.getClassDeclarationTextRange + (aClass); + String message = JavaErrorBundle.message("static.declaration.in.inner.class"); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(range) + .descriptionAndTooltip(message) + .create(); + if (context != keyword) { + QuickFixAction.registerQuickFixAction( + info, + QuickFixFactory.getInstance().createModifierListFix(aClass, PsiModifier.STATIC, false, false) + ); + } + PsiClass containingClass = aClass.getContainingClass(); + if (containingClass != null) { + QuickFixAction.registerQuickFixAction( + info, + QuickFixFactory.getInstance().createModifierListFix(containingClass, PsiModifier.STATIC, true, false) + ); + } + return info; } - // highlight 'static' keyword if any, or class or interface if not - PsiElement context = null; - PsiModifierList modifierList = aClass.getModifierList(); - if (modifierList != null) { - for (PsiElement element : modifierList.getChildren()) { - if (Comparing.equal(element.getText(), PsiModifier.STATIC)) { - context = element; - break; + @Nullable + public static HighlightInfo checkStaticDeclarationInInnerClass(PsiKeyword keyword, LanguageLevel languageLevel) { + HighlightInfo errorResult = checkStaticFieldDeclarationInInnerClass(keyword); + if (errorResult != null) { + return errorResult; } - } - } - TextRange range = context != null ? context.getTextRange() : HighlightNamesUtil.getClassDeclarationTextRange - (aClass); - String message = JavaErrorBundle.message("static.declaration.in.inner.class"); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range) - .descriptionAndTooltip(message).create(); - if (context != keyword) { - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createModifierListFix(aClass, - PsiModifier.STATIC, false, false)); - } - PsiClass containingClass = aClass.getContainingClass(); - if (containingClass != null) { - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createModifierListFix(containingClass, - PsiModifier.STATIC, true, false)); - } - return info; - } - - @Nullable - public static HighlightInfo checkStaticDeclarationInInnerClass(PsiKeyword keyword, LanguageLevel languageLevel) { - HighlightInfo errorResult = checkStaticFieldDeclarationInInnerClass(keyword); - if (errorResult != null) { - return errorResult; - } - errorResult = checkStaticMethodDeclarationInInnerClass(keyword, languageLevel); - if (errorResult != null) { - return errorResult; - } - errorResult = checkStaticClassDeclarationInInnerClass(keyword); - if (errorResult != null) { - return errorResult; - } - errorResult = checkStaticInitializerDeclarationInInnerClass(keyword); - if (errorResult != null) { - return errorResult; - } - return null; - } - - @Nullable - public static HighlightInfo checkExtendsAllowed(PsiReferenceList list) { - if (list.getParent() instanceof PsiClass) { - PsiClass aClass = (PsiClass) list.getParent(); - if (aClass.isEnum()) { - boolean isExtends = list.equals(aClass.getExtendsList()); - if (isExtends) { - String description = JavaErrorBundle.message("extends.after.enum"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list).descriptionAndTooltip - (description).create(); - } - } - } - return null; - } - - @Nullable - public static HighlightInfo checkImplementsAllowed(PsiReferenceList list) { - if (list.getParent() instanceof PsiClass) { - PsiClass aClass = (PsiClass) list.getParent(); - if (aClass.isInterface()) { - boolean isImplements = list.equals(aClass.getImplementsList()); - if (isImplements) { - String description = JavaErrorBundle.message("implements.after.interface"); - HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list) - .descriptionAndTooltip(description).create(); - final PsiClassType[] referencedTypes = list.getReferencedTypes(); - if (referencedTypes.length > 0) { - QuickFixAction.registerQuickFixAction(result, - QuickFixFactory.getInstance().createChangeExtendsToImplementsFix(aClass, referencedTypes[0])); - } - return result; - } - } - } - return null; - } - - @Nullable - public static HighlightInfo checkExtendsClassAndImplementsInterface(PsiReferenceList referenceList, - JavaResolveResult resolveResult, - PsiJavaCodeReferenceElement ref) { - PsiClass aClass = (PsiClass) referenceList.getParent(); - boolean isImplements = referenceList.equals(aClass.getImplementsList()); - boolean isInterface = aClass.isInterface(); - if (isInterface && isImplements) { - return null; - } - boolean mustBeInterface = isImplements || isInterface; - HighlightInfo errorResult = null; - PsiClass extendFrom = (PsiClass) resolveResult.getElement(); - if (extendFrom.isInterface() != mustBeInterface) { - String message = JavaErrorBundle.message(mustBeInterface ? "interface.expected" : "no.interface" + - ".expected"); - errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(ref).descriptionAndTooltip - (message).create(); - PsiClassType type = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(ref); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createChangeExtendsToImplementsFix - (aClass, type)); - } - return errorResult; - } - - @Nullable - public static HighlightInfo checkCannotInheritFromFinal(PsiClass superClass, PsiElement elementToHighlight) { - HighlightInfo errorResult = null; - if (superClass.hasModifierProperty(PsiModifier.FINAL) || superClass.isEnum()) { - String message = JavaErrorBundle.message("inheritance.from.final.class", superClass.getQualifiedName()); - errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(elementToHighlight) - .descriptionAndTooltip(message).create(); - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createModifierListFix(superClass, - PsiModifier.FINAL, false, false)); - } - return errorResult; - } - - @Nullable - public static HighlightInfo checkAnonymousInheritFinal(PsiNewExpression expression) { - PsiAnonymousClass aClass = PsiTreeUtil.getChildOfType(expression, PsiAnonymousClass.class); - if (aClass == null) { - return null; - } - PsiClassType baseClassReference = aClass.getBaseClassType(); - PsiClass baseClass = baseClassReference.resolve(); - if (baseClass == null) { - return null; - } - return checkCannotInheritFromFinal(baseClass, aClass.getBaseClassReference()); - } - - @Nullable - private static String checkDefaultConstructorThrowsException(PsiMethod constructor, - @Nonnull PsiClassType[] handledExceptions) { - PsiClassType[] referencedTypes = constructor.getThrowsList().getReferencedTypes(); - List exceptions = new ArrayList(); - for (PsiClassType referencedType : referencedTypes) { - if (!ExceptionUtil.isUncheckedException(referencedType) && !ExceptionUtil.isHandledBy(referencedType, - handledExceptions)) { - exceptions.add(referencedType); - } - } - if (!exceptions.isEmpty()) { - return HighlightUtil.getUnhandledExceptionsDescriptor(exceptions); - } - return null; - } - - @Nullable - public static HighlightInfo checkClassDoesNotCallSuperConstructorOrHandleExceptions(@Nonnull PsiClass aClass, - RefCountHolder refCountHolder, - @Nonnull PsiResolveHelper resolveHelper) { - if (aClass.isEnum()) { - return null; - } - // check only no-ctr classes. Problem with specific constructor will be highlighted inside it - if (aClass.getConstructors().length != 0) { - return null; + errorResult = checkStaticMethodDeclarationInInnerClass(keyword, languageLevel); + if (errorResult != null) { + return errorResult; + } + errorResult = checkStaticClassDeclarationInInnerClass(keyword); + if (errorResult != null) { + return errorResult; + } + errorResult = checkStaticInitializerDeclarationInInnerClass(keyword); + if (errorResult != null) { + return errorResult; + } + return null; } - // find no-args base class ctr - TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - return checkBaseClassDefaultConstructorProblem(aClass, refCountHolder, resolveHelper, textRange, - PsiClassType.EMPTY_ARRAY); - } - - public static HighlightInfo checkBaseClassDefaultConstructorProblem(@Nonnull PsiClass aClass, - RefCountHolder refCountHolder, - @Nonnull PsiResolveHelper resolveHelper, - @Nonnull TextRange range, - @Nonnull PsiClassType[] handledExceptions) { - if (aClass instanceof PsiAnonymousClass) { - return null; + + @Nullable + public static HighlightInfo checkExtendsAllowed(PsiReferenceList list) { + if (list.getParent() instanceof PsiClass) { + PsiClass aClass = (PsiClass)list.getParent(); + if (aClass.isEnum()) { + boolean isExtends = list.equals(aClass.getExtendsList()); + if (isExtends) { + String description = JavaErrorBundle.message("extends.after.enum"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(list) + .descriptionAndTooltip(description) + .create(); + } + } + } + return null; } - PsiClass baseClass = aClass.getSuperClass(); - if (baseClass == null) { - return null; + + @Nullable + public static HighlightInfo checkImplementsAllowed(PsiReferenceList list) { + if (list.getParent() instanceof PsiClass) { + PsiClass aClass = (PsiClass)list.getParent(); + if (aClass.isInterface()) { + boolean isImplements = list.equals(aClass.getImplementsList()); + if (isImplements) { + String description = JavaErrorBundle.message("implements.after.interface"); + HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(list) + .descriptionAndTooltip(description) + .create(); + final PsiClassType[] referencedTypes = list.getReferencedTypes(); + if (referencedTypes.length > 0) { + QuickFixAction.registerQuickFixAction( + result, + QuickFixFactory.getInstance().createChangeExtendsToImplementsFix(aClass, referencedTypes[0]) + ); + } + return result; + } + } + } + return null; } - PsiMethod[] constructors = baseClass.getConstructors(); - if (constructors.length == 0) { - return null; + + @Nullable + public static HighlightInfo checkExtendsClassAndImplementsInterface( + PsiReferenceList referenceList, + JavaResolveResult resolveResult, + PsiJavaCodeReferenceElement ref + ) { + PsiClass aClass = (PsiClass)referenceList.getParent(); + boolean isImplements = referenceList.equals(aClass.getImplementsList()); + boolean isInterface = aClass.isInterface(); + if (isInterface && isImplements) { + return null; + } + boolean mustBeInterface = isImplements || isInterface; + HighlightInfo errorResult = null; + PsiClass extendFrom = (PsiClass)resolveResult.getElement(); + if (extendFrom.isInterface() != mustBeInterface) { + String message = JavaErrorBundle.message(mustBeInterface ? "interface.expected" : "no.interface" + + ".expected"); + errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(ref) + .descriptionAndTooltip(message) + .create(); + PsiClassType type = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(ref); + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createChangeExtendsToImplementsFix(aClass, type) + ); + } + return errorResult; } - for (PsiMethod constructor : constructors) { - if (resolveHelper.isAccessible(constructor, aClass, null)) { - if (constructor.getParameterList().getParametersCount() == 0 || constructor.getParameterList() - .getParametersCount() == 1 && constructor.isVarArgs()) { - // it is an error if base ctr throws exceptions - String description = checkDefaultConstructorThrowsException(constructor, handledExceptions); - if (description != null) { - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range) - .descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(info, - QuickFixFactory.getInstance().createCreateConstructorMatchingSuperFix(aClass)); - return info; - } - if (refCountHolder != null) { - refCountHolder.registerLocallyReferenced(constructor); - } - return null; + @Nullable + public static HighlightInfo checkCannotInheritFromFinal(PsiClass superClass, PsiElement elementToHighlight) { + HighlightInfo errorResult = null; + if (superClass.hasModifierProperty(PsiModifier.FINAL) || superClass.isEnum()) { + String message = JavaErrorBundle.message("inheritance.from.final.class", superClass.getQualifiedName()); + errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(elementToHighlight) + .descriptionAndTooltip(message) + .create(); + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createModifierListFix(superClass, PsiModifier.FINAL, false, false) + ); } - } + return errorResult; } - String description = JavaErrorBundle.message("no.default.constructor.available", - HighlightUtil.formatClass(baseClass)); + @Nullable + public static HighlightInfo checkAnonymousInheritFinal(PsiNewExpression expression) { + PsiAnonymousClass aClass = PsiTreeUtil.getChildOfType(expression, PsiAnonymousClass.class); + if (aClass == null) { + return null; + } + PsiClassType baseClassReference = aClass.getBaseClassType(); + PsiClass baseClass = baseClassReference.resolve(); + if (baseClass == null) { + return null; + } + return checkCannotInheritFromFinal(baseClass, aClass.getBaseClassReference()); + } + + @Nullable + private static String checkDefaultConstructorThrowsException( + PsiMethod constructor, + @Nonnull PsiClassType[] handledExceptions + ) { + PsiClassType[] referencedTypes = constructor.getThrowsList().getReferencedTypes(); + List exceptions = new ArrayList(); + for (PsiClassType referencedType : referencedTypes) { + if (!ExceptionUtil.isUncheckedException(referencedType) + && !ExceptionUtil.isHandledBy(referencedType, handledExceptions)) { + exceptions.add(referencedType); + } + } + if (!exceptions.isEmpty()) { + return HighlightUtil.getUnhandledExceptionsDescriptor(exceptions); + } + return null; + } - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range) - .descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createCreateConstructorMatchingSuperFix(aClass)); + @Nullable + public static HighlightInfo checkClassDoesNotCallSuperConstructorOrHandleExceptions( + @Nonnull PsiClass aClass, + RefCountHolder refCountHolder, + @Nonnull PsiResolveHelper resolveHelper + ) { + if (aClass.isEnum()) { + return null; + } + // check only no-ctr classes. Problem with specific constructor will be highlighted inside it + if (aClass.getConstructors().length != 0) { + return null; + } + // find no-args base class ctr + TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); + return checkBaseClassDefaultConstructorProblem(aClass, refCountHolder, resolveHelper, textRange, PsiClassType.EMPTY_ARRAY); + } + + public static HighlightInfo checkBaseClassDefaultConstructorProblem( + @Nonnull PsiClass aClass, + RefCountHolder refCountHolder, + @Nonnull PsiResolveHelper resolveHelper, + @Nonnull TextRange range, + @Nonnull PsiClassType[] handledExceptions + ) { + if (aClass instanceof PsiAnonymousClass) { + return null; + } + PsiClass baseClass = aClass.getSuperClass(); + if (baseClass == null) { + return null; + } + PsiMethod[] constructors = baseClass.getConstructors(); + if (constructors.length == 0) { + return null; + } - return info; - } + for (PsiMethod constructor : constructors) { + if (resolveHelper.isAccessible(constructor, aClass, null)) { + if (constructor.getParameterList().getParametersCount() == 0 || constructor.getParameterList() + .getParametersCount() == 1 && constructor.isVarArgs()) { + // it is an error if base ctr throws exceptions + String description = checkDefaultConstructorThrowsException(constructor, handledExceptions); + if (description != null) { + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(range) + .descriptionAndTooltip(description) + .create(); + QuickFixAction.registerQuickFixAction( + info, + QuickFixFactory.getInstance().createCreateConstructorMatchingSuperFix(aClass) + ); + return info; + } + if (refCountHolder != null) { + refCountHolder.registerLocallyReferenced(constructor); + } + return null; + } + } + } - @Nullable - public static HighlightInfo checkInterfaceCannotBeLocal(PsiClass aClass) { - if (PsiUtil.isLocalClass(aClass)) { - TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - String description = JavaErrorBundle.message("interface.cannot.be.local"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip - (description).create(); - } - return null; - } - - @Nullable - public static HighlightInfo checkCyclicInheritance(PsiClass aClass) { - PsiClass circularClass = getCircularClass(aClass, new HashSet()); - if (circularClass != null) { - String description = JavaErrorBundle.message("cyclic.inheritance", - HighlightUtil.formatClass(circularClass)); - TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip - (description).create(); + String description = JavaErrorBundle.message( + "no.default.constructor.available", + HighlightUtil.formatClass(baseClass) + ); + + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(range) + .descriptionAndTooltip(description) + .create(); + QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createCreateConstructorMatchingSuperFix(aClass)); + + return info; + } + + @Nullable + public static HighlightInfo checkInterfaceCannotBeLocal(PsiClass aClass) { + if (PsiUtil.isLocalClass(aClass)) { + TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); + String description = JavaErrorBundle.message("interface.cannot.be.local"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(range) + .descriptionAndTooltip(description) + .create(); + } + return null; } - return null; - } - @Nullable - public static PsiClass getCircularClass(PsiClass aClass, Collection usedClasses) { - if (usedClasses.contains(aClass)) { - return aClass; + @Nullable + public static HighlightInfo checkCyclicInheritance(PsiClass aClass) { + PsiClass circularClass = getCircularClass(aClass, new HashSet()); + if (circularClass != null) { + String description = JavaErrorBundle.message( + "cyclic.inheritance", + HighlightUtil.formatClass(circularClass) + ); + TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(range) + .descriptionAndTooltip(description) + .create(); + } + return null; } - try { - usedClasses.add(aClass); - PsiClass[] superTypes = aClass.getSupers(); - for (PsiElement superType : superTypes) { - while (superType instanceof PsiClass) { - if (!JavaClassNames.JAVA_LANG_OBJECT.equals(((PsiClass) superType).getQualifiedName())) { - PsiClass circularClass = getCircularClass((PsiClass) superType, usedClasses); - if (circularClass != null) { - return circularClass; + + @Nullable + public static PsiClass getCircularClass(PsiClass aClass, Collection usedClasses) { + if (usedClasses.contains(aClass)) { + return aClass; + } + try { + usedClasses.add(aClass); + PsiClass[] superTypes = aClass.getSupers(); + for (PsiElement superType : superTypes) { + while (superType instanceof PsiClass) { + if (!JavaClassNames.JAVA_LANG_OBJECT.equals(((PsiClass)superType).getQualifiedName())) { + PsiClass circularClass = getCircularClass((PsiClass)superType, usedClasses); + if (circularClass != null) { + return circularClass; + } + } + // check class qualifier + superType = superType.getParent(); + } } - } - // check class qualifier - superType = superType.getParent(); } - } - } finally { - usedClasses.remove(aClass); - } - return null; - } - - @Nullable - public static HighlightInfo checkExtendsDuplicate(PsiJavaCodeReferenceElement element, - PsiElement resolved, - @Nonnull PsiFile containingFile) { - if (!(element.getParent() instanceof PsiReferenceList)) { - return null; - } - PsiReferenceList list = (PsiReferenceList) element.getParent(); - if (!(list.getParent() instanceof PsiClass)) { - return null; - } - if (!(resolved instanceof PsiClass)) { - return null; - } - PsiClass aClass = (PsiClass) resolved; - PsiClassType[] referencedTypes = list.getReferencedTypes(); - int dupCount = 0; - PsiManager manager = containingFile.getManager(); - for (PsiClassType referencedType : referencedTypes) { - PsiClass resolvedElement = referencedType.resolve(); - if (resolvedElement != null && manager.areElementsEquivalent(resolvedElement, aClass)) { - dupCount++; - } - } - if (dupCount > 1) { - String description = JavaErrorBundle.message("duplicate.class", HighlightUtil.formatClass(aClass)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip - (description).create(); - } - return null; - } - - @Nullable - public static HighlightInfo checkClassAlreadyImported(PsiClass aClass, PsiElement elementToHighlight) { - PsiFile file = aClass.getContainingFile(); - if (!(file instanceof PsiJavaFile)) { - return null; - } - PsiJavaFile javaFile = (PsiJavaFile) file; - // check only top-level classes conflicts - if (aClass.getParent() != javaFile) { - return null; - } - PsiImportList importList = javaFile.getImportList(); - if (importList == null) { - return null; - } - PsiImportStatementBase[] importStatements = importList.getAllImportStatements(); - for (PsiImportStatementBase importStatement : importStatements) { - if (importStatement.isOnDemand()) { - continue; - } - PsiElement resolved = importStatement.resolve(); - if (resolved instanceof PsiClass && !resolved.equals(aClass) && Comparing.equal(aClass.getName(), - ((PsiClass) resolved).getName(), true)) { - String description = JavaErrorBundle.message("class.already.imported", - HighlightUtil.formatClass(aClass, false)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(elementToHighlight) - .descriptionAndTooltip(description).create(); - } - } - return null; - } - - @Nullable - public static HighlightInfo checkClassExtendsOnlyOneClass(PsiReferenceList list) { - PsiClassType[] referencedTypes = list.getReferencedTypes(); - PsiElement parent = list.getParent(); - if (!(parent instanceof PsiClass)) { - return null; + finally { + usedClasses.remove(aClass); + } + return null; } - PsiClass aClass = (PsiClass) parent; - if (!aClass.isInterface() && referencedTypes.length > 1 && aClass.getExtendsList() == list) { - String description = JavaErrorBundle.message("class.cannot.extend.multiple.classes"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list).descriptionAndTooltip - (description).create(); + @Nullable + public static HighlightInfo checkExtendsDuplicate( + PsiJavaCodeReferenceElement element, + PsiElement resolved, + @Nonnull PsiFile containingFile + ) { + if (!(element.getParent() instanceof PsiReferenceList)) { + return null; + } + PsiReferenceList list = (PsiReferenceList)element.getParent(); + if (!(list.getParent() instanceof PsiClass)) { + return null; + } + if (!(resolved instanceof PsiClass)) { + return null; + } + PsiClass aClass = (PsiClass)resolved; + PsiClassType[] referencedTypes = list.getReferencedTypes(); + int dupCount = 0; + PsiManager manager = containingFile.getManager(); + for (PsiClassType referencedType : referencedTypes) { + PsiClass resolvedElement = referencedType.resolve(); + if (resolvedElement != null && manager.areElementsEquivalent(resolvedElement, aClass)) { + dupCount++; + } + } + if (dupCount > 1) { + String description = JavaErrorBundle.message("duplicate.class", HighlightUtil.formatClass(aClass)); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(element) + .descriptionAndTooltip(description) + .create(); + } + return null; } - return null; - } - - @Nullable - public static HighlightInfo checkThingNotAllowedInInterface(PsiElement element, PsiClass aClass) { - if (aClass == null || !aClass.isInterface()) { - return null; - } - String description = JavaErrorBundle.message("not.allowed.in.interface"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip - (description).create(); - } - - @Nullable - public static HighlightInfo checkQualifiedNew(PsiNewExpression expression, PsiType type, PsiClass aClass) { - PsiExpression qualifier = expression.getQualifier(); - if (qualifier == null) { - return null; - } - if (type instanceof PsiArrayType) { - String description = JavaErrorBundle.message("invalid.qualified.new"); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression) - .descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createRemoveNewQualifierFix(expression, - null)); - return info; - } - HighlightInfo info = null; - if (aClass != null) { - if (aClass.hasModifierProperty(PsiModifier.STATIC)) { - String description = JavaErrorBundle.message("qualified.new.of.static.class"); - info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip - (description).create(); - if (!aClass.isEnum()) { - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createModifierListFix(aClass, - PsiModifier.STATIC, false, false)); - } - - } else if (aClass instanceof PsiAnonymousClass) { - final PsiClass baseClass = PsiUtil.resolveClassInType(((PsiAnonymousClass) aClass).getBaseClassType()); - if (baseClass != null && baseClass.isInterface()) { - info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression) - .descriptionAndTooltip("Anonymous class implements interface; cannot have qualifier for " + "new").create(); - } - } - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createRemoveNewQualifierFix(expression, - aClass)); - } - return info; - } - - - /** - * class c extends foreign.inner {} - * - * @param extendRef points to the class in the extends list - * @param resolved extendRef resolved - */ - @Nullable - public static HighlightInfo checkClassExtendsForeignInnerClass(final PsiJavaCodeReferenceElement extendRef, - final PsiElement resolved) { - PsiElement parent = extendRef.getParent(); - if (!(parent instanceof PsiReferenceList)) { - return null; - } - PsiElement grand = parent.getParent(); - if (!(grand instanceof PsiClass)) { - return null; - } - final PsiClass aClass = (PsiClass) grand; - final PsiClass containerClass; - if (aClass instanceof PsiTypeParameter) { - final PsiTypeParameterListOwner owner = ((PsiTypeParameter) aClass).getOwner(); - if (!(owner instanceof PsiClass)) { + @Nullable + public static HighlightInfo checkClassAlreadyImported(PsiClass aClass, PsiElement elementToHighlight) { + PsiFile file = aClass.getContainingFile(); + if (!(file instanceof PsiJavaFile)) { + return null; + } + PsiJavaFile javaFile = (PsiJavaFile)file; + // check only top-level classes conflicts + if (aClass.getParent() != javaFile) { + return null; + } + PsiImportList importList = javaFile.getImportList(); + if (importList == null) { + return null; + } + PsiImportStatementBase[] importStatements = importList.getAllImportStatements(); + for (PsiImportStatementBase importStatement : importStatements) { + if (importStatement.isOnDemand()) { + continue; + } + PsiElement resolved = importStatement.resolve(); + if (resolved instanceof PsiClass && !resolved.equals(aClass) + && Comparing.equal(aClass.getName(), ((PsiClass)resolved).getName(), true)) { + String description = JavaErrorBundle.message( + "class.already.imported", + HighlightUtil.formatClass(aClass, false) + ); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(elementToHighlight) + .descriptionAndTooltip(description) + .create(); + } + } return null; - } - containerClass = (PsiClass) owner; - } else { - containerClass = aClass; - } - if (aClass.getExtendsList() != parent && aClass.getImplementsList() != parent) { - return null; - } - if (!(resolved instanceof PsiClass)) { - String description = JavaErrorBundle.message("class.name.expected"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(extendRef).descriptionAndTooltip - (description).create(); - } - final HighlightInfo[] infos = new HighlightInfo[1]; - extendRef.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitElement(PsiElement element) { - if (infos[0] != null) { - return; - } - super.visitElement(element); - } - - @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - super.visitReferenceElement(reference); - final PsiElement resolve = reference.resolve(); - if (resolve instanceof PsiClass) { - final PsiClass base = (PsiClass) resolve; - final PsiClass baseClass = base.getContainingClass(); - if (baseClass != null && base.hasModifierProperty(PsiModifier.PRIVATE) && baseClass == - containerClass) { - String description = JavaErrorBundle.message("private.symbol", - HighlightUtil.formatClass(base), HighlightUtil.formatClass(baseClass)); - infos[0] = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(extendRef) - .descriptionAndTooltip(description).create(); - return; - } - - // must be inner class - if (!PsiUtil.isInnerClass(base)) { - return; - } - - if (resolve == resolved && baseClass != null && (!PsiTreeUtil.isAncestor(baseClass, extendRef, - true) || aClass.hasModifierProperty(PsiModifier.STATIC)) && - !InheritanceUtil.hasEnclosingInstanceInScope(baseClass, extendRef, - !aClass.hasModifierProperty(PsiModifier.STATIC), - true) && !qualifiedNewCalledInConstructors(aClass)) { - String description = JavaErrorBundle.message("no.enclosing.instance.in.scope", - HighlightUtil.formatClass(baseClass)); - infos[0] = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(extendRef) - .descriptionAndTooltip(description).create(); - } - } - } - }); - - return infos[0]; - } - - /** - * 15.9 Class Instance Creation Expressions | 15.9.2 Determining Enclosing Instances - */ - private static boolean qualifiedNewCalledInConstructors(final PsiClass aClass) { - PsiMethod[] constructors = aClass.getConstructors(); - if (constructors.length == 0) { - return false; - } - for (PsiMethod constructor : constructors) { - PsiCodeBlock body = constructor.getBody(); - if (body == null) { - return false; - } - PsiStatement[] statements = body.getStatements(); - if (statements.length == 0) { - return false; - } - PsiStatement firstStatement = statements[0]; - if (!(firstStatement instanceof PsiExpressionStatement)) { - return false; - } - PsiExpression expression = ((PsiExpressionStatement) firstStatement).getExpression(); - if (!RefactoringChangeUtil.isSuperOrThisMethodCall(expression)) { - return false; - } - PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) expression; - if (PsiKeyword.THIS.equals(methodCallExpression.getMethodExpression().getReferenceName())) { - continue; - } - PsiReferenceExpression referenceExpression = methodCallExpression.getMethodExpression(); - PsiExpression qualifierExpression = PsiUtil.skipParenthesizedExprDown(referenceExpression - .getQualifierExpression()); - //If the class instance creation expression is qualified, then the immediately - //enclosing instance of i is the object that is the value of the Primary expression or the ExpressionName, - //otherwise aClass needs to be a member of a class enclosing the class in which the class instance - // creation expression appears - //already excluded by InheritanceUtil.hasEnclosingInstanceInScope - if (qualifierExpression == null) { - return false; - } - } - return true; - } - - @Nullable - public static HighlightInfo checkCreateInnerClassFromStaticContext(PsiNewExpression expression, - PsiType type, - PsiClass aClass) { - if (type == null || type instanceof PsiArrayType || type instanceof PsiPrimitiveType) { - return null; } - if (aClass == null) { - return null; - } - if (aClass instanceof PsiAnonymousClass) { - aClass = ((PsiAnonymousClass) aClass).getBaseClassType().resolve(); - if (aClass == null) { + + @Nullable + public static HighlightInfo checkClassExtendsOnlyOneClass(PsiReferenceList list) { + PsiClassType[] referencedTypes = list.getReferencedTypes(); + PsiElement parent = list.getParent(); + if (!(parent instanceof PsiClass)) { + return null; + } + + PsiClass aClass = (PsiClass)parent; + if (!aClass.isInterface() && referencedTypes.length > 1 && aClass.getExtendsList() == list) { + String description = JavaErrorBundle.message("class.cannot.extend.multiple.classes"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(list) + .descriptionAndTooltip(description) + .create(); + } + return null; - } } - PsiExpression qualifier = expression.getQualifier(); - return checkCreateInnerClassFromStaticContext(expression, qualifier, aClass); - } - - @Nullable - public static HighlightInfo checkCreateInnerClassFromStaticContext(PsiElement element, - @Nullable PsiExpression qualifier, - PsiClass aClass) { - PsiElement placeToSearchEnclosingFrom; - if (qualifier != null) { - PsiType qType = qualifier.getType(); - placeToSearchEnclosingFrom = PsiUtil.resolveClassInType(qType); - } else { - placeToSearchEnclosingFrom = element; - } - return checkCreateInnerClassFromStaticContext(element, placeToSearchEnclosingFrom, aClass); - } - - @Nullable - public static HighlightInfo checkCreateInnerClassFromStaticContext(PsiElement element, - PsiElement placeToSearchEnclosingFrom, - PsiClass aClass) { - if (aClass == null || !PsiUtil.isInnerClass(aClass)) { - return null; - } - PsiClass outerClass = aClass.getContainingClass(); - if (outerClass == null) { - return null; - } + @Nullable + public static HighlightInfo checkThingNotAllowedInInterface(PsiElement element, PsiClass aClass) { + if (aClass == null || !aClass.isInterface()) { + return null; + } + String description = JavaErrorBundle.message("not.allowed.in.interface"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(element) + .descriptionAndTooltip(description) + .create(); + } + + @Nullable + public static HighlightInfo checkQualifiedNew(PsiNewExpression expression, PsiType type, PsiClass aClass) { + PsiExpression qualifier = expression.getQualifier(); + if (qualifier == null) { + return null; + } + if (type instanceof PsiArrayType) { + String description = JavaErrorBundle.message("invalid.qualified.new"); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(description) + .create(); + QuickFixAction.registerQuickFixAction( + info, + QuickFixFactory.getInstance().createRemoveNewQualifierFix(expression, null) + ); + return info; + } + HighlightInfo info = null; + if (aClass != null) { + if (aClass.hasModifierProperty(PsiModifier.STATIC)) { + String description = JavaErrorBundle.message("qualified.new.of.static.class"); + info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(description) + .create(); + if (!aClass.isEnum()) { + QuickFixAction.registerQuickFixAction( + info, + QuickFixFactory.getInstance().createModifierListFix(aClass, PsiModifier.STATIC, false, false) + ); + } - if (outerClass instanceof PsiSyntheticClass || InheritanceUtil.hasEnclosingInstanceInScope(outerClass, placeToSearchEnclosingFrom, true, false)) { - return null; - } - return reportIllegalEnclosingUsage(placeToSearchEnclosingFrom, aClass, outerClass, element); - } + } + else if (aClass instanceof PsiAnonymousClass) { + final PsiClass baseClass = PsiUtil.resolveClassInType(((PsiAnonymousClass)aClass).getBaseClassType()); + if (baseClass != null && baseClass.isInterface()) { + info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip("Anonymous class implements interface; cannot have qualifier for " + "new") + .create(); + } + } + QuickFixAction.registerQuickFixAction( + info, + QuickFixFactory.getInstance().createRemoveNewQualifierFix(expression, aClass) + ); + } + return info; + } + + + /** + * class c extends foreign.inner {} + * + * @param extendRef points to the class in the extends list + * @param resolved extendRef resolved + */ + @Nullable + public static HighlightInfo checkClassExtendsForeignInnerClass( + final PsiJavaCodeReferenceElement extendRef, + final PsiElement resolved + ) { + PsiElement parent = extendRef.getParent(); + if (!(parent instanceof PsiReferenceList)) { + return null; + } + PsiElement grand = parent.getParent(); + if (!(grand instanceof PsiClass)) { + return null; + } + final PsiClass aClass = (PsiClass)grand; + final PsiClass containerClass; + if (aClass instanceof PsiTypeParameter) { + final PsiTypeParameterListOwner owner = ((PsiTypeParameter)aClass).getOwner(); + if (!(owner instanceof PsiClass)) { + return null; + } + containerClass = (PsiClass)owner; + } + else { + containerClass = aClass; + } + if (aClass.getExtendsList() != parent && aClass.getImplementsList() != parent) { + return null; + } + if (!(resolved instanceof PsiClass)) { + String description = JavaErrorBundle.message("class.name.expected"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(extendRef) + .descriptionAndTooltip(description) + .create(); + } + final HighlightInfo[] infos = new HighlightInfo[1]; + extendRef.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (infos[0] != null) { + return; + } + super.visitElement(element); + } + + @Override + public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { + super.visitReferenceElement(reference); + final PsiElement resolve = reference.resolve(); + if (resolve instanceof PsiClass) { + final PsiClass base = (PsiClass)resolve; + final PsiClass baseClass = base.getContainingClass(); + if (baseClass != null && base.hasModifierProperty(PsiModifier.PRIVATE) && baseClass == + containerClass) { + String description = JavaErrorBundle.message( + "private.symbol", + HighlightUtil.formatClass(base), + HighlightUtil.formatClass(baseClass) + ); + infos[0] = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(extendRef) + .descriptionAndTooltip(description) + .create(); + return; + } + + // must be inner class + if (!PsiUtil.isInnerClass(base)) { + return; + } + + if (resolve == resolved && baseClass != null + && (!PsiTreeUtil.isAncestor(baseClass, extendRef, true) || aClass.hasModifierProperty(PsiModifier.STATIC)) + && !InheritanceUtil.hasEnclosingInstanceInScope(baseClass, extendRef, !aClass.hasModifierProperty(PsiModifier.STATIC), true) + && !qualifiedNewCalledInConstructors(aClass)) { + String description = JavaErrorBundle.message( + "no.enclosing.instance.in.scope", + HighlightUtil.formatClass(baseClass) + ); + infos[0] = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(extendRef) + .descriptionAndTooltip(description) + .create(); + } + } + } + }); - @Nullable - public static HighlightInfo checkSuperQualifierType(@Nonnull Project project, @Nonnull PsiMethodCallExpression superCall) { - if (!RefactoringChangeUtil.isSuperMethodCall(superCall)) { - return null; + return infos[0]; } - PsiMethod ctr = PsiTreeUtil.getParentOfType(superCall, PsiMethod.class, true, PsiMember.class); - if (ctr == null) { - return null; + + /** + * 15.9 Class Instance Creation Expressions | 15.9.2 Determining Enclosing Instances + */ + private static boolean qualifiedNewCalledInConstructors(final PsiClass aClass) { + PsiMethod[] constructors = aClass.getConstructors(); + if (constructors.length == 0) { + return false; + } + for (PsiMethod constructor : constructors) { + PsiCodeBlock body = constructor.getBody(); + if (body == null) { + return false; + } + PsiStatement[] statements = body.getStatements(); + if (statements.length == 0) { + return false; + } + PsiStatement firstStatement = statements[0]; + if (!(firstStatement instanceof PsiExpressionStatement)) { + return false; + } + PsiExpression expression = ((PsiExpressionStatement)firstStatement).getExpression(); + if (!RefactoringChangeUtil.isSuperOrThisMethodCall(expression)) { + return false; + } + PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression; + if (PsiKeyword.THIS.equals(methodCallExpression.getMethodExpression().getReferenceName())) { + continue; + } + PsiReferenceExpression referenceExpression = methodCallExpression.getMethodExpression(); + PsiExpression qualifierExpression = PsiUtil.skipParenthesizedExprDown(referenceExpression + .getQualifierExpression()); + //If the class instance creation expression is qualified, then the immediately + //enclosing instance of i is the object that is the value of the Primary expression or the ExpressionName, + //otherwise aClass needs to be a member of a class enclosing the class in which the class instance + // creation expression appears + //already excluded by InheritanceUtil.hasEnclosingInstanceInScope + if (qualifierExpression == null) { + return false; + } + } + return true; } - final PsiClass aClass = ctr.getContainingClass(); - if (aClass == null) { - return null; + + @Nullable + public static HighlightInfo checkCreateInnerClassFromStaticContext( + PsiNewExpression expression, + PsiType type, + PsiClass aClass + ) { + if (type == null || type instanceof PsiArrayType || type instanceof PsiPrimitiveType) { + return null; + } + if (aClass == null) { + return null; + } + if (aClass instanceof PsiAnonymousClass) { + aClass = ((PsiAnonymousClass)aClass).getBaseClassType().resolve(); + if (aClass == null) { + return null; + } + } + + PsiExpression qualifier = expression.getQualifier(); + return checkCreateInnerClassFromStaticContext(expression, qualifier, aClass); } - PsiClass targetClass = aClass.getSuperClass(); - if (targetClass == null) { - return null; + + @Nullable + public static HighlightInfo checkCreateInnerClassFromStaticContext( + PsiElement element, + @Nullable PsiExpression qualifier, + PsiClass aClass + ) { + PsiElement placeToSearchEnclosingFrom; + if (qualifier != null) { + PsiType qType = qualifier.getType(); + placeToSearchEnclosingFrom = PsiUtil.resolveClassInType(qType); + } + else { + placeToSearchEnclosingFrom = element; + } + return checkCreateInnerClassFromStaticContext(element, placeToSearchEnclosingFrom, aClass); } - PsiExpression qualifier = superCall.getMethodExpression().getQualifierExpression(); - if (qualifier != null) { - if (PsiUtil.isInnerClass(targetClass)) { - PsiClass outerClass = targetClass.getContainingClass(); - if (outerClass != null) { - PsiClassType outerType = JavaPsiFacade.getInstance(project).getElementFactory().createType - (outerClass); - return HighlightUtil.checkAssignability(outerType, null, qualifier, qualifier); - } - } else { - String description = "'" + HighlightUtil.formatClass(targetClass) + "' is not an inner class"; - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(qualifier).descriptionAndTooltip - (description).create(); - } + + @Nullable + public static HighlightInfo checkCreateInnerClassFromStaticContext( + PsiElement element, + PsiElement placeToSearchEnclosingFrom, + PsiClass aClass + ) { + if (aClass == null || !PsiUtil.isInnerClass(aClass)) { + return null; + } + PsiClass outerClass = aClass.getContainingClass(); + if (outerClass == null) { + return null; + } + + if (outerClass instanceof PsiSyntheticClass + || InheritanceUtil.hasEnclosingInstanceInScope(outerClass, placeToSearchEnclosingFrom, true, false)) { + return null; + } + return reportIllegalEnclosingUsage(placeToSearchEnclosingFrom, aClass, outerClass, element); } - return null; - } - - @Nullable - public static HighlightInfo reportIllegalEnclosingUsage(PsiElement place, - @Nullable PsiClass aClass, - PsiClass outerClass, - PsiElement elementToHighlight) { - if (outerClass != null && !PsiTreeUtil.isContextAncestor(outerClass, place, false)) { - String description = JavaErrorBundle.message("is.not.an.enclosing.class", - HighlightUtil.formatClass(outerClass)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(elementToHighlight) - .descriptionAndTooltip(description).create(); + + @Nullable + public static HighlightInfo checkSuperQualifierType(@Nonnull Project project, @Nonnull PsiMethodCallExpression superCall) { + if (!RefactoringChangeUtil.isSuperMethodCall(superCall)) { + return null; + } + PsiMethod ctr = PsiTreeUtil.getParentOfType(superCall, PsiMethod.class, true, PsiMember.class); + if (ctr == null) { + return null; + } + final PsiClass aClass = ctr.getContainingClass(); + if (aClass == null) { + return null; + } + PsiClass targetClass = aClass.getSuperClass(); + if (targetClass == null) { + return null; + } + PsiExpression qualifier = superCall.getMethodExpression().getQualifierExpression(); + if (qualifier != null) { + if (PsiUtil.isInnerClass(targetClass)) { + PsiClass outerClass = targetClass.getContainingClass(); + if (outerClass != null) { + PsiClassType outerType = JavaPsiFacade.getInstance(project).getElementFactory().createType(outerClass); + return HighlightUtil.checkAssignability(outerType, null, qualifier, qualifier); + } + } + else { + String description = "'" + HighlightUtil.formatClass(targetClass) + "' is not an inner class"; + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(qualifier) + .descriptionAndTooltip(description) + .create(); + } + } + return null; } - PsiModifierListOwner staticParent = PsiUtil.getEnclosingStaticElement(place, outerClass); - if (staticParent != null) { - String element = outerClass == null ? "" : HighlightUtil.formatClass(outerClass) + "." + - (place instanceof PsiSuperExpression ? PsiKeyword.SUPER : PsiKeyword.THIS); - String description = JavaErrorBundle.message("cannot.be.referenced.from.static.context", element); - HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range - (elementToHighlight).descriptionAndTooltip(description).create(); - // make context not static or referenced class static - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance().createModifierListFix(staticParent, - PsiModifier.STATIC, false, false)); - if (aClass != null && HighlightUtil.getIncompatibleModifier(PsiModifier.STATIC, - aClass.getModifierList()) == null) { - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance() - .createModifierListFix(aClass, PsiModifier.STATIC, true, false)); - } - return highlightInfo; + + @Nullable + public static HighlightInfo reportIllegalEnclosingUsage( + PsiElement place, + @Nullable PsiClass aClass, + PsiClass outerClass, + PsiElement elementToHighlight + ) { + if (outerClass != null && !PsiTreeUtil.isContextAncestor(outerClass, place, false)) { + String description = JavaErrorBundle.message( + "is.not.an.enclosing.class", + HighlightUtil.formatClass(outerClass) + ); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(elementToHighlight) + .descriptionAndTooltip(description) + .create(); + } + PsiModifierListOwner staticParent = PsiUtil.getEnclosingStaticElement(place, outerClass); + if (staticParent != null) { + String element = outerClass == null ? "" : HighlightUtil.formatClass(outerClass) + "." + + (place instanceof PsiSuperExpression ? PsiKeyword.SUPER : PsiKeyword.THIS); + String description = JavaErrorBundle.message("cannot.be.referenced.from.static.context", element); + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(elementToHighlight) + .descriptionAndTooltip(description) + .create(); + // make context not static or referenced class static + QuickFixAction.registerQuickFixAction( + highlightInfo, + QuickFixFactory.getInstance().createModifierListFix(staticParent, PsiModifier.STATIC, false, false) + ); + if (aClass != null + && HighlightUtil.getIncompatibleModifier(PsiModifier.STATIC, aClass.getModifierList()) == null) { + QuickFixAction.registerQuickFixAction( + highlightInfo, + QuickFixFactory.getInstance().createModifierListFix(aClass, PsiModifier.STATIC, true, false) + ); + } + return highlightInfo; + } + return null; } - return null; - } } diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/quickfix/QualifySuperArgumentFix.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/quickfix/QualifySuperArgumentFix.java index b992e3557a..f054caa4cb 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/quickfix/QualifySuperArgumentFix.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/quickfix/QualifySuperArgumentFix.java @@ -33,42 +33,46 @@ import jakarta.annotation.Nonnull; public class QualifySuperArgumentFix extends QualifyThisOrSuperArgumentFix { - public QualifySuperArgumentFix(@Nonnull PsiExpression expression, @Nonnull PsiClass psiClass) { - super(expression, psiClass); - } + public QualifySuperArgumentFix(@Nonnull PsiExpression expression, @Nonnull PsiClass psiClass) { + super(expression, psiClass); + } - @Override - protected String getQualifierText() { - return "super"; - } + @Override + protected String getQualifierText() { + return "super"; + } - @Override - protected PsiExpression getQualifier(PsiManager manager) { - return RefactoringChangeUtil.createSuperExpression(manager, myPsiClass); - } + @Override + protected PsiExpression getQualifier(PsiManager manager) { + return RefactoringChangeUtil.createSuperExpression(manager, myPsiClass); + } - public static void registerQuickFixAction(@Nonnull PsiSuperExpression expr, HighlightInfo highlightInfo) { - LOG.assertTrue(expr.getQualifier() == null); - final PsiClass containingClass = PsiTreeUtil.getParentOfType(expr, PsiClass.class); - if (containingClass != null && containingClass.isInterface()) { - final PsiMethodCallExpression callExpression = PsiTreeUtil.getParentOfType(expr, - PsiMethodCallExpression.class); - if (callExpression != null) { - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(callExpression.getProject()); - for (PsiClass superClass : containingClass.getSupers()) { - if (superClass.isInterface()) { - final PsiMethodCallExpression copy = (PsiMethodCallExpression) callExpression.copy(); - final PsiExpression superQualifierCopy = copy.getMethodExpression().getQualifierExpression(); - LOG.assertTrue(superQualifierCopy != null); - superQualifierCopy.delete(); - if (((PsiMethodCallExpression) elementFactory.createExpressionFromText(copy.getText(), - superClass)).resolveMethod() != null) { - QuickFixAction.registerQuickFixAction(highlightInfo, new QualifySuperArgumentFix(expr, - superClass)); + public static void registerQuickFixAction(@Nonnull PsiSuperExpression expr, HighlightInfo highlightInfo) { + LOG.assertTrue(expr.getQualifier() == null); + final PsiClass containingClass = PsiTreeUtil.getParentOfType(expr, PsiClass.class); + if (containingClass != null && containingClass.isInterface()) { + final PsiMethodCallExpression callExpression = PsiTreeUtil.getParentOfType( + expr, + PsiMethodCallExpression.class + ); + if (callExpression != null) { + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(callExpression.getProject()); + for (PsiClass superClass : containingClass.getSupers()) { + if (superClass.isInterface()) { + final PsiMethodCallExpression copy = (PsiMethodCallExpression)callExpression.copy(); + final PsiExpression superQualifierCopy = copy.getMethodExpression().getQualifierExpression(); + LOG.assertTrue(superQualifierCopy != null); + superQualifierCopy.delete(); + if (((PsiMethodCallExpression)elementFactory.createExpressionFromText(copy.getText(), superClass)) + .resolveMethod() != null) { + QuickFixAction.registerQuickFixAction(highlightInfo, new QualifySuperArgumentFix( + expr, + superClass + )); + } + } + } } - } } - } } - } } From c3a9afa8c2f070c10b0d9980776e40d1a799cfa1 Mon Sep 17 00:00:00 2001 From: UNV Date: Fri, 2 May 2025 06:40:48 +0300 Subject: [PATCH 2/4] Refactoring and localizing users of EP_NAME (part 3). --- .../impl/analysis/HighlightClassUtil.java | 498 ++++---- .../impl/analysis/HighlightMethodUtil.java | 31 +- .../daemon/impl/analysis/HighlightUtil.java | 1129 +++++++++-------- .../impl/analysis/HighlightVisitorImpl.java | 38 +- .../quickfix/QualifySuperArgumentFix.java | 27 +- 5 files changed, 898 insertions(+), 825 deletions(-) diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightClassUtil.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightClassUtil.java index 32fd6b28cd..40f247e34f 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightClassUtil.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/analysis/HighlightClassUtil.java @@ -28,12 +28,13 @@ import com.intellij.java.language.LanguageLevel; import com.intellij.java.language.impl.JavaFileType; import com.intellij.java.language.impl.codeInsight.ExceptionUtil; -import com.intellij.java.language.impl.codeInsight.daemon.JavaErrorBundle; import com.intellij.java.language.impl.refactoring.util.RefactoringChangeUtil; 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.RequiredReadAction; import consulo.document.util.TextRange; +import consulo.java.language.impl.localize.JavaErrorLocalize; import consulo.java.language.module.util.JavaClassNames; import consulo.language.editor.intention.QuickFixAction; import consulo.language.editor.rawHighlight.HighlightInfo; @@ -43,34 +44,30 @@ import consulo.language.psi.util.PsiMatcherImpl; import consulo.language.psi.util.PsiTreeUtil; import consulo.language.util.ModuleUtilCore; +import consulo.localize.LocalizeValue; import consulo.module.Module; import consulo.project.Project; import consulo.util.io.FileUtil; import consulo.util.lang.Comparing; import consulo.virtualFileSystem.VirtualFile; - import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; +import java.util.*; public class HighlightClassUtil { /** * new ref(...) or new ref(..) { ... } where ref is abstract class */ @Nullable + @RequiredReadAction public static HighlightInfo checkAbstractInstantiation(@Nonnull PsiJavaCodeReferenceElement ref) { - PsiElement parent = ref.getParent(); - HighlightInfo highlightInfo = null; - if (parent instanceof PsiAnonymousClass && parent.getParent() instanceof PsiNewExpression && !PsiUtilCore - .hasErrorElementChild(parent.getParent())) { - PsiAnonymousClass aClass = (PsiAnonymousClass)parent; - highlightInfo = checkClassWithAbstractMethods(aClass, ref.getTextRange()); - } - return highlightInfo; + if (ref.getParent() instanceof PsiAnonymousClass anonymousClass + && anonymousClass.getParent() instanceof PsiNewExpression newExpr + && !PsiUtilCore.hasErrorElementChild(newExpr)) { + return checkClassWithAbstractMethods(anonymousClass, ref.getTextRange()); + } + return null; } @Nullable @@ -90,25 +87,21 @@ public static HighlightInfo checkClassWithAbstractMethods( return null; } - final PsiClass superClass = abstractMethod.getContainingClass(); + PsiClass superClass = abstractMethod.getContainingClass(); if (superClass == null) { return null; } String baseClassName = HighlightUtil.formatClass(aClass, false); String methodName = JavaHighlightUtil.formatMethod(abstractMethod); - String message = JavaErrorBundle.message( - aClass instanceof PsiEnumConstantInitializer || implementsFixElement instanceof PsiEnumConstant - ? "enum.constant.should.implement.method" - : "class.must.be.abstract", - baseClassName, - methodName, - HighlightUtil.formatClass(superClass, false) - ); + String c = HighlightUtil.formatClass(superClass, false); + LocalizeValue message = aClass instanceof PsiEnumConstantInitializer || implementsFixElement instanceof PsiEnumConstant + ? JavaErrorLocalize.enumConstantShouldImplementMethod(baseClassName, methodName, c) + : JavaErrorLocalize.classMustBeAbstract(baseClassName, methodName, c); HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range) .descriptionAndTooltip(message).create(); - final PsiMethod anyMethodToImplement = ClassUtil.getAnyMethodToImplement(aClass); + PsiMethod anyMethodToImplement = ClassUtil.getAnyMethodToImplement(aClass); if (anyMethodToImplement != null) { if (!anyMethodToImplement.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) || JavaPsiFacade.getInstance(aClass.getProject()).arePackagesTheSame(aClass, superClass)) { @@ -139,26 +132,25 @@ public static HighlightInfo checkClassWithAbstractMethods( } @Nullable - public static HighlightInfo checkClassMustBeAbstract(final PsiClass aClass, final TextRange textRange) { - if (aClass.hasModifierProperty(PsiModifier.ABSTRACT) || aClass.getRBrace() == null || aClass.isEnum() && - hasEnumConstants(aClass)) { + public static HighlightInfo checkClassMustBeAbstract(PsiClass aClass, TextRange textRange) { + if (aClass.isAbstract() || aClass.getRBrace() == null || aClass.isEnum() && hasEnumConstants(aClass)) { return null; } return checkClassWithAbstractMethods(aClass, textRange); } @Nullable + @RequiredReadAction public static HighlightInfo checkInstantiationOfAbstractClass(PsiClass aClass, @Nonnull PsiElement highlightElement) { HighlightInfo errorResult = null; - if (aClass != null && aClass.hasModifierProperty(PsiModifier.ABSTRACT) && (!(highlightElement instanceof - PsiNewExpression) || !(((PsiNewExpression)highlightElement).getType() instanceof PsiArrayType))) { + if (aClass != null && aClass.isAbstract() + && !(highlightElement instanceof PsiNewExpression newExpr && newExpr.getType() instanceof PsiArrayType)) { String baseClassName = aClass.getName(); - String message = JavaErrorBundle.message("abstract.cannot.be.instantiated", baseClassName); errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(highlightElement) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.abstractCannotBeInstantiated(baseClassName)) .create(); - final PsiMethod anyAbstractMethod = ClassUtil.getAnyAbstractMethod(aClass); + PsiMethod anyAbstractMethod = ClassUtil.getAnyAbstractMethod(aClass); if (!aClass.isInterface() && anyAbstractMethod == null) { // suggest to make not abstract only if possible QuickFixAction.registerQuickFixAction( @@ -166,8 +158,7 @@ public static HighlightInfo checkInstantiationOfAbstractClass(PsiClass aClass, @ QuickFixFactory.getInstance().createModifierListFix(aClass, PsiModifier.ABSTRACT, false, false) ); } - if (anyAbstractMethod != null && highlightElement instanceof PsiNewExpression && ((PsiNewExpression) - highlightElement).getClassReference() != null) { + if (anyAbstractMethod != null && highlightElement instanceof PsiNewExpression newExpr && newExpr.getClassReference() != null) { QuickFixAction.registerQuickFixAction( errorResult, QuickFixFactory.getInstance().createImplementAbstractClassMethodsFix(highlightElement) @@ -188,6 +179,7 @@ private static boolean hasEnumConstants(PsiClass aClass) { } @Nullable + @RequiredReadAction public static HighlightInfo checkDuplicateTopLevelClass(PsiClass aClass) { if (!(aClass.getParent() instanceof PsiFile)) { return null; @@ -226,16 +218,15 @@ public static HighlightInfo checkDuplicateTopLevelClass(PsiClass aClass) { if (dupFileName == null) { return null; } - String message = JavaErrorBundle.message("duplicate.class.in.other.file", dupFileName); - TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(textRange) - .descriptionAndTooltip(message) + .range(HighlightNamesUtil.getClassDeclarationTextRange(aClass)) + .descriptionAndTooltip(JavaErrorLocalize.duplicateClassInOtherFile(dupFileName)) .create(); } @Nullable + @RequiredReadAction public static HighlightInfo checkDuplicateNestedClass(PsiClass aClass) { if (aClass == null) { return null; @@ -274,25 +265,27 @@ public static HighlightInfo checkDuplicateNestedClass(PsiClass aClass) { if (element instanceof PsiDeclarationStatement) { element = PsiTreeUtil.getChildOfType(element, PsiClass.class); } - if (element instanceof PsiClass && name.equals(((PsiClass)element).getName())) { + if (element instanceof PsiClass psiClass && name.equals(psiClass.getName())) { duplicateFound = true; break; } } if (duplicateFound) { - String message = JavaErrorBundle.message("duplicate.class", name); TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip - (message).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(textRange) + .descriptionAndTooltip(JavaErrorLocalize.duplicateClass(name)) + .create(); } return null; } @Nullable + @RequiredReadAction public static HighlightInfo checkPublicClassInRightFile(PsiClass aClass) { PsiFile containingFile = aClass.getContainingFile(); - if (aClass.getParent() != containingFile || !aClass.hasModifierProperty(PsiModifier.PUBLIC) || !(containingFile instanceof PsiJavaFile)) { + if (aClass.getParent() != containingFile || !aClass.isPublic() || !(containingFile instanceof PsiJavaFile)) { return null; } PsiJavaFile file = (PsiJavaFile)containingFile; @@ -300,16 +293,19 @@ public static HighlightInfo checkPublicClassInRightFile(PsiClass aClass) { if (virtualFile == null || aClass.getName().equals(virtualFile.getNameWithoutExtension())) { return null; } - String message = JavaErrorBundle.message("public.class.should.be.named.after.file", aClass.getName()); TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR). - range(aClass, range.getStartOffset(), range.getEndOffset()). - descriptionAndTooltip(message).create(); PsiModifierList psiModifierList = aClass.getModifierList(); - QuickFixAction.registerQuickFixAction( - errorResult, - QuickFixFactory.getInstance().createModifierListFix(psiModifierList, PsiModifier.PUBLIC, false, false) - ); + HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(aClass, range.getStartOffset(), range.getEndOffset()) + .descriptionAndTooltip(JavaErrorLocalize.publicClassShouldBeNamedAfterFile(aClass.getName())) + .registerFix( + QuickFixFactory.getInstance().createModifierListFix(psiModifierList, PsiModifier.PUBLIC, false, false), + null, + null, + null, + null + ) + .create(); PsiClass[] classes = file.getClasses(); if (classes.length > 1) { QuickFixAction.registerQuickFixAction( @@ -319,44 +315,41 @@ public static HighlightInfo checkPublicClassInRightFile(PsiClass aClass) { } for (PsiClass otherClass : classes) { if (!otherClass.getManager().areElementsEquivalent(otherClass, aClass) - && otherClass.hasModifierProperty(PsiModifier.PUBLIC) + && otherClass.isPublic() && otherClass.getName().equals(virtualFile.getNameWithoutExtension())) { return errorResult; } } - QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createRenameFileFix(aClass.getName() + - JavaFileType.DOT_DEFAULT_EXTENSION)); + QuickFixAction.registerQuickFixAction( + errorResult, + QuickFixFactory.getInstance().createRenameFileFix(aClass.getName() + JavaFileType.DOT_DEFAULT_EXTENSION) + ); QuickFixAction.registerQuickFixAction(errorResult, QuickFixFactory.getInstance().createRenameElementFix(aClass)); return errorResult; } @Nullable + @RequiredReadAction public static HighlightInfo checkClassAndPackageConflict(@Nonnull PsiClass aClass) { String name = aClass.getQualifiedName(); if (JavaClassNames.DEFAULT_PACKAGE.equals(name)) { - String message = JavaErrorBundle.message("class.clashes.with.package", name); - TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(range) - .descriptionAndTooltip(message) + .range(HighlightNamesUtil.getClassDeclarationTextRange(aClass)) + .descriptionAndTooltip(JavaErrorLocalize.classClashesWithPackage(name)) .create(); } PsiElement file = aClass.getParent(); - if (file instanceof PsiJavaFile && !((PsiJavaFile)file).getPackageName().isEmpty()) { - PsiElement directory = file.getParent(); - if (directory instanceof PsiDirectory) { - String simpleName = aClass.getName(); - PsiDirectory subDirectory = ((PsiDirectory)directory).findSubdirectory(simpleName); - if (subDirectory != null && simpleName.equals(subDirectory.getName())) { - String message = JavaErrorBundle.message("class.clashes.with.package", name); - TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(range) - .descriptionAndTooltip(message) - .create(); - } + if (file instanceof PsiJavaFile javaFile && !javaFile.getPackageName().isEmpty() + && file.getParent() instanceof PsiDirectory directory) { + String simpleName = aClass.getName(); + PsiDirectory subDirectory = directory.findSubdirectory(simpleName); + if (subDirectory != null && simpleName.equals(subDirectory.getName())) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(HighlightNamesUtil.getClassDeclarationTextRange(aClass)) + .descriptionAndTooltip(JavaErrorLocalize.classClashesWithPackage(name)) + .create(); } } @@ -364,6 +357,7 @@ public static HighlightInfo checkClassAndPackageConflict(@Nonnull PsiClass aClas } @Nullable + @RequiredReadAction private static HighlightInfo checkStaticFieldDeclarationInInnerClass(@Nonnull PsiKeyword keyword) { if (getEnclosingStaticClass(keyword, PsiField.class) == null) { return null; @@ -374,17 +368,18 @@ private static HighlightInfo checkStaticFieldDeclarationInInnerClass(@Nonnull Ps return null; } - String message = JavaErrorBundle.message("static.declaration.in.inner.class"); HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(keyword) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.staticDeclarationInInnerClass()) + .registerFix( + QuickFixFactory.getInstance().createModifierListFix(field, PsiModifier.STATIC, false, false), + null, + null, + null, + null + ) .create(); - QuickFixAction.registerQuickFixAction( - result, - QuickFixFactory.getInstance().createModifierListFix(field, PsiModifier.STATIC, false, false) - ); - PsiClass aClass = field.getContainingClass(); if (aClass != null) { QuickFixAction.registerQuickFixAction( @@ -397,6 +392,7 @@ private static HighlightInfo checkStaticFieldDeclarationInInnerClass(@Nonnull Ps } @Nullable + @RequiredReadAction private static HighlightInfo checkStaticMethodDeclarationInInnerClass(PsiKeyword keyword, LanguageLevel languageLevel) { if (languageLevel.isAtLeast(LanguageLevel.JDK_16)) { return null; @@ -409,28 +405,34 @@ private static HighlightInfo checkStaticMethodDeclarationInInnerClass(PsiKeyword if (PsiUtilCore.hasErrorElementChild(method)) { return null; } - String message = JavaErrorBundle.message("static.declaration.in.inner.class"); - HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(keyword) - .descriptionAndTooltip(message) - .create(); - QuickFixAction.registerQuickFixAction( - result, - QuickFixFactory.getInstance().createModifierListFix(method, PsiModifier.STATIC, false, false) - ); - QuickFixAction.registerQuickFixAction( - result, - QuickFixFactory.getInstance().createModifierListFix( - (PsiClass)keyword.getParent().getParent().getParent(), - PsiModifier.STATIC, - true, - false + .descriptionAndTooltip(JavaErrorLocalize.staticDeclarationInInnerClass()) + .registerFix( + QuickFixFactory.getInstance().createModifierListFix(method, PsiModifier.STATIC, false, false), + null, + null, + null, + null ) - ); - return result; + .registerFix( + QuickFixFactory.getInstance().createModifierListFix( + (PsiClass)keyword.getParent().getParent().getParent(), + PsiModifier.STATIC, + true, + false + ) + , + null, + null, + null, + null + ) + .create(); } @Nullable + @RequiredReadAction private static HighlightInfo checkStaticInitializerDeclarationInInnerClass(PsiKeyword keyword) { if (getEnclosingStaticClass(keyword, PsiClassInitializer.class) == null) { return null; @@ -439,21 +441,25 @@ private static HighlightInfo checkStaticInitializerDeclarationInInnerClass(PsiKe if (PsiUtilCore.hasErrorElementChild(initializer)) { return null; } - String message = JavaErrorBundle.message("static.declaration.in.inner.class"); - HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + PsiClass owner = (PsiClass)keyword.getParent().getParent().getParent(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(keyword) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.staticDeclarationInInnerClass()) + .registerFix( + QuickFixFactory.getInstance().createModifierListFix(initializer, PsiModifier.STATIC, false, false), + null, + null, + null, + null + ) + .registerFix( + QuickFixFactory.getInstance().createModifierListFix(owner, PsiModifier.STATIC, true, false), + null, + null, + null, + null + ) .create(); - QuickFixAction.registerQuickFixAction( - result, - QuickFixFactory.getInstance().createModifierListFix(initializer, PsiModifier.STATIC, false, false) - ); - PsiClass owner = (PsiClass)keyword.getParent().getParent().getParent(); - QuickFixAction.registerQuickFixAction( - result, - QuickFixFactory.getInstance().createModifierListFix(owner, PsiModifier.STATIC, true, false) - ); - return result; } private static PsiElement getEnclosingStaticClass(@Nonnull PsiKeyword keyword, @Nonnull Class parentClass) { @@ -468,6 +474,7 @@ private static PsiElement getEnclosingStaticClass(@Nonnull PsiKeyword keyword, @ } @Nullable + @RequiredReadAction private static HighlightInfo checkStaticClassDeclarationInInnerClass(PsiKeyword keyword) { // keyword points to 'class' or 'interface' or 'enum' if (new PsiMatcherImpl(keyword) @@ -496,12 +503,12 @@ private static HighlightInfo checkStaticClassDeclarationInInnerClass(PsiKeyword } } } - TextRange range = context != null ? context.getTextRange() : HighlightNamesUtil.getClassDeclarationTextRange - (aClass); - String message = JavaErrorBundle.message("static.declaration.in.inner.class"); + TextRange range = context != null + ? context.getTextRange() + : HighlightNamesUtil.getClassDeclarationTextRange(aClass); HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(range) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.staticDeclarationInInnerClass()) .create(); if (context != keyword) { QuickFixAction.registerQuickFixAction( @@ -520,6 +527,7 @@ private static HighlightInfo checkStaticClassDeclarationInInnerClass(PsiKeyword } @Nullable + @RequiredReadAction public static HighlightInfo checkStaticDeclarationInInnerClass(PsiKeyword keyword, LanguageLevel languageLevel) { HighlightInfo errorResult = checkStaticFieldDeclarationInInnerClass(keyword); if (errorResult != null) { @@ -541,36 +549,33 @@ public static HighlightInfo checkStaticDeclarationInInnerClass(PsiKeyword keywor } @Nullable + @RequiredReadAction public static HighlightInfo checkExtendsAllowed(PsiReferenceList list) { - if (list.getParent() instanceof PsiClass) { - PsiClass aClass = (PsiClass)list.getParent(); - if (aClass.isEnum()) { - boolean isExtends = list.equals(aClass.getExtendsList()); - if (isExtends) { - String description = JavaErrorBundle.message("extends.after.enum"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(list) - .descriptionAndTooltip(description) - .create(); - } + if (list.getParent() instanceof PsiClass aClass && aClass.isEnum()) { + boolean isExtends = list.equals(aClass.getExtendsList()); + if (isExtends) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(list) + .descriptionAndTooltip(JavaErrorLocalize.extendsAfterEnum()) + .create(); } } return null; } @Nullable + @RequiredReadAction public static HighlightInfo checkImplementsAllowed(PsiReferenceList list) { if (list.getParent() instanceof PsiClass) { PsiClass aClass = (PsiClass)list.getParent(); if (aClass.isInterface()) { boolean isImplements = list.equals(aClass.getImplementsList()); if (isImplements) { - String description = JavaErrorBundle.message("implements.after.interface"); HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(list) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.implementsAfterInterface()) .create(); - final PsiClassType[] referencedTypes = list.getReferencedTypes(); + PsiClassType[] referencedTypes = list.getReferencedTypes(); if (referencedTypes.length > 0) { QuickFixAction.registerQuickFixAction( result, @@ -585,6 +590,7 @@ public static HighlightInfo checkImplementsAllowed(PsiReferenceList list) { } @Nullable + @RequiredReadAction public static HighlightInfo checkExtendsClassAndImplementsInterface( PsiReferenceList referenceList, JavaResolveResult resolveResult, @@ -597,42 +603,42 @@ public static HighlightInfo checkExtendsClassAndImplementsInterface( return null; } boolean mustBeInterface = isImplements || isInterface; - HighlightInfo errorResult = null; PsiClass extendFrom = (PsiClass)resolveResult.getElement(); if (extendFrom.isInterface() != mustBeInterface) { - String message = JavaErrorBundle.message(mustBeInterface ? "interface.expected" : "no.interface" + - ".expected"); - errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + LocalizeValue message = mustBeInterface + ? JavaErrorLocalize.interfaceExpected() + : JavaErrorLocalize.noInterfaceExpected(); + PsiClassType type = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(ref); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(ref) .descriptionAndTooltip(message) + .registerFix(QuickFixFactory.getInstance().createChangeExtendsToImplementsFix(aClass, type), null, null, null, null) .create(); - PsiClassType type = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(ref); - QuickFixAction.registerQuickFixAction( - errorResult, - QuickFixFactory.getInstance().createChangeExtendsToImplementsFix(aClass, type) - ); } - return errorResult; + return null; } @Nullable + @RequiredReadAction public static HighlightInfo checkCannotInheritFromFinal(PsiClass superClass, PsiElement elementToHighlight) { - HighlightInfo errorResult = null; - if (superClass.hasModifierProperty(PsiModifier.FINAL) || superClass.isEnum()) { - String message = JavaErrorBundle.message("inheritance.from.final.class", superClass.getQualifiedName()); - errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + if (superClass.isFinal() || superClass.isEnum()) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(elementToHighlight) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.inheritanceFromFinalClass(superClass.getQualifiedName())) + .registerFix( + QuickFixFactory.getInstance().createModifierListFix(superClass, PsiModifier.FINAL, false, false), + null, + null, + null, + null + ) .create(); - QuickFixAction.registerQuickFixAction( - errorResult, - QuickFixFactory.getInstance().createModifierListFix(superClass, PsiModifier.FINAL, false, false) - ); } - return errorResult; + return null; } @Nullable + @RequiredReadAction public static HighlightInfo checkAnonymousInheritFinal(PsiNewExpression expression) { PsiAnonymousClass aClass = PsiTreeUtil.getChildOfType(expression, PsiAnonymousClass.class); if (aClass == null) { @@ -647,12 +653,12 @@ public static HighlightInfo checkAnonymousInheritFinal(PsiNewExpression expressi } @Nullable - private static String checkDefaultConstructorThrowsException( + private static LocalizeValue checkDefaultConstructorThrowsException( PsiMethod constructor, @Nonnull PsiClassType[] handledExceptions ) { PsiClassType[] referencedTypes = constructor.getThrowsList().getReferencedTypes(); - List exceptions = new ArrayList(); + List exceptions = new ArrayList<>(); for (PsiClassType referencedType : referencedTypes) { if (!ExceptionUtil.isUncheckedException(referencedType) && !ExceptionUtil.isHandledBy(referencedType, handledExceptions)) { @@ -707,17 +713,19 @@ public static HighlightInfo checkBaseClassDefaultConstructorProblem( if (constructor.getParameterList().getParametersCount() == 0 || constructor.getParameterList() .getParametersCount() == 1 && constructor.isVarArgs()) { // it is an error if base ctr throws exceptions - String description = checkDefaultConstructorThrowsException(constructor, handledExceptions); + LocalizeValue description = checkDefaultConstructorThrowsException(constructor, handledExceptions); if (description != null) { - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(range) .descriptionAndTooltip(description) + .registerFix( + QuickFixFactory.getInstance().createCreateConstructorMatchingSuperFix(aClass), + null, + null, + null, + null + ) .create(); - QuickFixAction.registerQuickFixAction( - info, - QuickFixFactory.getInstance().createCreateConstructorMatchingSuperFix(aClass) - ); - return info; } if (refCountHolder != null) { refCountHolder.registerLocallyReferenced(constructor); @@ -727,28 +735,19 @@ public static HighlightInfo checkBaseClassDefaultConstructorProblem( } } - String description = JavaErrorBundle.message( - "no.default.constructor.available", - HighlightUtil.formatClass(baseClass) - ); - - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(range) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.noDefaultConstructorAvailable(HighlightUtil.formatClass(baseClass))) + .registerFix(QuickFixFactory.getInstance().createCreateConstructorMatchingSuperFix(aClass), null, null, null, null) .create(); - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createCreateConstructorMatchingSuperFix(aClass)); - - return info; } @Nullable public static HighlightInfo checkInterfaceCannotBeLocal(PsiClass aClass) { if (PsiUtil.isLocalClass(aClass)) { - TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); - String description = JavaErrorBundle.message("interface.cannot.be.local"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(range) - .descriptionAndTooltip(description) + .range(HighlightNamesUtil.getClassDeclarationTextRange(aClass)) + .descriptionAndTooltip(JavaErrorLocalize.interfaceCannotBeLocal()) .create(); } return null; @@ -756,16 +755,11 @@ public static HighlightInfo checkInterfaceCannotBeLocal(PsiClass aClass) { @Nullable public static HighlightInfo checkCyclicInheritance(PsiClass aClass) { - PsiClass circularClass = getCircularClass(aClass, new HashSet()); + PsiClass circularClass = getCircularClass(aClass, new HashSet<>()); if (circularClass != null) { - String description = JavaErrorBundle.message( - "cyclic.inheritance", - HighlightUtil.formatClass(circularClass) - ); - TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(range) - .descriptionAndTooltip(description) + .range(HighlightNamesUtil.getClassDeclarationTextRange(aClass)) + .descriptionAndTooltip(JavaErrorLocalize.cyclicInheritance(HighlightUtil.formatClass(circularClass))) .create(); } return null; @@ -799,6 +793,7 @@ public static PsiClass getCircularClass(PsiClass aClass, Collection us } @Nullable + @RequiredReadAction public static HighlightInfo checkExtendsDuplicate( PsiJavaCodeReferenceElement element, PsiElement resolved, @@ -825,16 +820,16 @@ public static HighlightInfo checkExtendsDuplicate( } } if (dupCount > 1) { - String description = JavaErrorBundle.message("duplicate.class", HighlightUtil.formatClass(aClass)); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(element) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.duplicateClass(HighlightUtil.formatClass(aClass))) .create(); } return null; } @Nullable + @RequiredReadAction public static HighlightInfo checkClassAlreadyImported(PsiClass aClass, PsiElement elementToHighlight) { PsiFile file = aClass.getContainingFile(); if (!(file instanceof PsiJavaFile)) { @@ -854,16 +849,11 @@ public static HighlightInfo checkClassAlreadyImported(PsiClass aClass, PsiElemen if (importStatement.isOnDemand()) { continue; } - PsiElement resolved = importStatement.resolve(); - if (resolved instanceof PsiClass && !resolved.equals(aClass) - && Comparing.equal(aClass.getName(), ((PsiClass)resolved).getName(), true)) { - String description = JavaErrorBundle.message( - "class.already.imported", - HighlightUtil.formatClass(aClass, false) - ); + if (importStatement.resolve() instanceof PsiClass importClass && !importClass.equals(aClass) + && Objects.equals(aClass.getName(), importClass.getName())) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(elementToHighlight) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.classAlreadyImported(HighlightUtil.formatClass(aClass, false))) .create(); } } @@ -871,6 +861,7 @@ public static HighlightInfo checkClassAlreadyImported(PsiClass aClass, PsiElemen } @Nullable + @RequiredReadAction public static HighlightInfo checkClassExtendsOnlyOneClass(PsiReferenceList list) { PsiClassType[] referencedTypes = list.getReferencedTypes(); PsiElement parent = list.getParent(); @@ -880,10 +871,9 @@ public static HighlightInfo checkClassExtendsOnlyOneClass(PsiReferenceList list) PsiClass aClass = (PsiClass)parent; if (!aClass.isInterface() && referencedTypes.length > 1 && aClass.getExtendsList() == list) { - String description = JavaErrorBundle.message("class.cannot.extend.multiple.classes"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(list) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.classCannotExtendMultipleClasses()) .create(); } @@ -891,42 +881,37 @@ public static HighlightInfo checkClassExtendsOnlyOneClass(PsiReferenceList list) } @Nullable + @RequiredReadAction public static HighlightInfo checkThingNotAllowedInInterface(PsiElement element, PsiClass aClass) { if (aClass == null || !aClass.isInterface()) { return null; } - String description = JavaErrorBundle.message("not.allowed.in.interface"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(element) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.notAllowedInInterface()) .create(); } @Nullable + @RequiredReadAction public static HighlightInfo checkQualifiedNew(PsiNewExpression expression, PsiType type, PsiClass aClass) { PsiExpression qualifier = expression.getQualifier(); if (qualifier == null) { return null; } if (type instanceof PsiArrayType) { - String description = JavaErrorBundle.message("invalid.qualified.new"); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.invalidQualifiedNew()) + .registerFix(QuickFixFactory.getInstance().createRemoveNewQualifierFix(expression, null), null, null, null, null) .create(); - QuickFixAction.registerQuickFixAction( - info, - QuickFixFactory.getInstance().createRemoveNewQualifierFix(expression, null) - ); - return info; } HighlightInfo info = null; if (aClass != null) { - if (aClass.hasModifierProperty(PsiModifier.STATIC)) { - String description = JavaErrorBundle.message("qualified.new.of.static.class"); + if (aClass.isStatic()) { info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.qualifiedNewOfStaticClass()) .create(); if (!aClass.isEnum()) { QuickFixAction.registerQuickFixAction( @@ -934,10 +919,9 @@ public static HighlightInfo checkQualifiedNew(PsiNewExpression expression, PsiTy QuickFixFactory.getInstance().createModifierListFix(aClass, PsiModifier.STATIC, false, false) ); } - } else if (aClass instanceof PsiAnonymousClass) { - final PsiClass baseClass = PsiUtil.resolveClassInType(((PsiAnonymousClass)aClass).getBaseClassType()); + PsiClass baseClass = PsiUtil.resolveClassInType(((PsiAnonymousClass)aClass).getBaseClassType()); if (baseClass != null && baseClass.isInterface()) { info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) @@ -961,41 +945,33 @@ else if (aClass instanceof PsiAnonymousClass) { * @param resolved extendRef resolved */ @Nullable - public static HighlightInfo checkClassExtendsForeignInnerClass( - final PsiJavaCodeReferenceElement extendRef, - final PsiElement resolved - ) { - PsiElement parent = extendRef.getParent(); - if (!(parent instanceof PsiReferenceList)) { - return null; - } - PsiElement grand = parent.getParent(); - if (!(grand instanceof PsiClass)) { + @RequiredReadAction + public static HighlightInfo checkClassExtendsForeignInnerClass(PsiJavaCodeReferenceElement extendRef, PsiElement resolved) { + if (!(extendRef.getParent() instanceof PsiReferenceList referenceList + && referenceList.getParent() instanceof PsiClass aClass)) { return null; } - final PsiClass aClass = (PsiClass)grand; - final PsiClass containerClass; - if (aClass instanceof PsiTypeParameter) { - final PsiTypeParameterListOwner owner = ((PsiTypeParameter)aClass).getOwner(); - if (!(owner instanceof PsiClass)) { + PsiClass containerClass; + if (aClass instanceof PsiTypeParameter typeParam) { + if (!(typeParam.getOwner() instanceof PsiClass ownerClass)) { return null; } - containerClass = (PsiClass)owner; + containerClass = ownerClass; } else { containerClass = aClass; } - if (aClass.getExtendsList() != parent && aClass.getImplementsList() != parent) { + + if (aClass.getExtendsList() != referenceList && aClass.getImplementsList() != referenceList) { return null; } if (!(resolved instanceof PsiClass)) { - String description = JavaErrorBundle.message("class.name.expected"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(extendRef) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.classNameExpected()) .create(); } - final HighlightInfo[] infos = new HighlightInfo[1]; + HighlightInfo[] infos = new HighlightInfo[1]; extendRef.accept(new JavaRecursiveElementWalkingVisitor() { @Override public void visitElement(PsiElement element) { @@ -1006,22 +982,18 @@ public void visitElement(PsiElement element) { } @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { + @RequiredReadAction + public void visitReferenceElement(@Nonnull PsiJavaCodeReferenceElement reference) { super.visitReferenceElement(reference); - final PsiElement resolve = reference.resolve(); - if (resolve instanceof PsiClass) { - final PsiClass base = (PsiClass)resolve; - final PsiClass baseClass = base.getContainingClass(); - if (baseClass != null && base.hasModifierProperty(PsiModifier.PRIVATE) && baseClass == - containerClass) { - String description = JavaErrorBundle.message( - "private.symbol", - HighlightUtil.formatClass(base), - HighlightUtil.formatClass(baseClass) - ); + if (reference.resolve() instanceof PsiClass base) { + PsiClass baseClass = base.getContainingClass(); + if (baseClass != null && base.isPrivate() && baseClass == containerClass) { infos[0] = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(extendRef) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.privateSymbol( + HighlightUtil.formatClass(base), + HighlightUtil.formatClass(baseClass) + )) .create(); return; } @@ -1031,17 +1003,18 @@ public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { return; } - if (resolve == resolved && baseClass != null - && (!PsiTreeUtil.isAncestor(baseClass, extendRef, true) || aClass.hasModifierProperty(PsiModifier.STATIC)) - && !InheritanceUtil.hasEnclosingInstanceInScope(baseClass, extendRef, !aClass.hasModifierProperty(PsiModifier.STATIC), true) + if (base == resolved && baseClass != null + && (!PsiTreeUtil.isAncestor(baseClass, extendRef, true) || aClass.isStatic()) + && !InheritanceUtil.hasEnclosingInstanceInScope( + baseClass, + extendRef, + !aClass.isStatic(), + true + ) && !qualifiedNewCalledInConstructors(aClass)) { - String description = JavaErrorBundle.message( - "no.enclosing.instance.in.scope", - HighlightUtil.formatClass(baseClass) - ); infos[0] = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(extendRef) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.noEnclosingInstanceInScope(HighlightUtil.formatClass(baseClass))) .create(); } } @@ -1054,7 +1027,7 @@ public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { /** * 15.9 Class Instance Creation Expressions | 15.9.2 Determining Enclosing Instances */ - private static boolean qualifiedNewCalledInConstructors(final PsiClass aClass) { + private static boolean qualifiedNewCalledInConstructors(PsiClass aClass) { PsiMethod[] constructors = aClass.getConstructors(); if (constructors.length == 0) { return false; @@ -1096,6 +1069,7 @@ private static boolean qualifiedNewCalledInConstructors(final PsiClass aClass) { } @Nullable + @RequiredReadAction public static HighlightInfo checkCreateInnerClassFromStaticContext( PsiNewExpression expression, PsiType type, @@ -1107,8 +1081,8 @@ public static HighlightInfo checkCreateInnerClassFromStaticContext( if (aClass == null) { return null; } - if (aClass instanceof PsiAnonymousClass) { - aClass = ((PsiAnonymousClass)aClass).getBaseClassType().resolve(); + if (aClass instanceof PsiAnonymousClass anonymousClass) { + aClass = anonymousClass.getBaseClassType().resolve(); if (aClass == null) { return null; } @@ -1119,6 +1093,7 @@ public static HighlightInfo checkCreateInnerClassFromStaticContext( } @Nullable + @RequiredReadAction public static HighlightInfo checkCreateInnerClassFromStaticContext( PsiElement element, @Nullable PsiExpression qualifier, @@ -1136,6 +1111,7 @@ public static HighlightInfo checkCreateInnerClassFromStaticContext( } @Nullable + @RequiredReadAction public static HighlightInfo checkCreateInnerClassFromStaticContext( PsiElement element, PsiElement placeToSearchEnclosingFrom, @@ -1157,6 +1133,7 @@ public static HighlightInfo checkCreateInnerClassFromStaticContext( } @Nullable + @RequiredReadAction public static HighlightInfo checkSuperQualifierType(@Nonnull Project project, @Nonnull PsiMethodCallExpression superCall) { if (!RefactoringChangeUtil.isSuperMethodCall(superCall)) { return null; @@ -1165,7 +1142,7 @@ public static HighlightInfo checkSuperQualifierType(@Nonnull Project project, @N if (ctr == null) { return null; } - final PsiClass aClass = ctr.getContainingClass(); + PsiClass aClass = ctr.getContainingClass(); if (aClass == null) { return null; } @@ -1194,6 +1171,7 @@ public static HighlightInfo checkSuperQualifierType(@Nonnull Project project, @N } @Nullable + @RequiredReadAction public static HighlightInfo reportIllegalEnclosingUsage( PsiElement place, @Nullable PsiClass aClass, @@ -1201,29 +1179,27 @@ public static HighlightInfo reportIllegalEnclosingUsage( PsiElement elementToHighlight ) { if (outerClass != null && !PsiTreeUtil.isContextAncestor(outerClass, place, false)) { - String description = JavaErrorBundle.message( - "is.not.an.enclosing.class", - HighlightUtil.formatClass(outerClass) - ); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(elementToHighlight) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.isNotAnEnclosingClass(HighlightUtil.formatClass(outerClass))) .create(); } PsiModifierListOwner staticParent = PsiUtil.getEnclosingStaticElement(place, outerClass); if (staticParent != null) { String element = outerClass == null ? "" : HighlightUtil.formatClass(outerClass) + "." + (place instanceof PsiSuperExpression ? PsiKeyword.SUPER : PsiKeyword.THIS); - String description = JavaErrorBundle.message("cannot.be.referenced.from.static.context", element); HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(elementToHighlight) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.cannotBeReferencedFromStaticContext(element)) + // make context not static or referenced class static + .registerFix( + QuickFixFactory.getInstance().createModifierListFix(staticParent, PsiModifier.STATIC, false, false), + null, + null, + null, + null + ) .create(); - // make context not static or referenced class static - QuickFixAction.registerQuickFixAction( - highlightInfo, - QuickFixFactory.getInstance().createModifierListFix(staticParent, PsiModifier.STATIC, false, false) - ); if (aClass != null && HighlightUtil.getIncompatibleModifier(PsiModifier.STATIC, aClass.getModifierList()) == null) { QuickFixAction.registerQuickFixAction( 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 f2f1802cfd..2675e94020 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 @@ -151,24 +151,26 @@ private static HighlightInfo isWeaker( else { textRange = TextRange.EMPTY_RANGE; } - HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + return 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( - method, - PsiUtil.getAccessModifier(superAccessLevel), - true, - false + .registerFix( + QuickFixFactory.getInstance().createModifierListFix( + method, + PsiUtil.getAccessModifier(superAccessLevel), + true, + false + ), + null, + null, + null, + null ) - ); - return highlightInfo; + .create(); } return null; } @@ -1979,10 +1981,11 @@ public static HighlightInfo checkConstructorHandleSuperClassExceptions(PsiMethod 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(); + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(textRange) + .descriptionAndTooltip(HighlightUtil.getUnhandledExceptionsDescriptor(unhandled)) + .create(); for (PsiClassType exception : unhandled) { QuickFixAction.registerQuickFixAction( highlightInfo, 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 a024cb0228..4640860bc0 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 @@ -79,14 +79,13 @@ import consulo.util.lang.ObjectUtil; import consulo.util.lang.Pair; 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.Contract; -import org.jetbrains.annotations.NonNls; import java.util.*; import java.util.regex.Matcher; @@ -220,6 +219,7 @@ private HighlightUtil() { } @Nullable + @RequiredReadAction private static String getIncompatibleModifier( String modifier, @Nullable PsiModifierList modifierList, @@ -245,7 +245,6 @@ private static String getIncompatibleModifier( if (incompatibles == null) { return null; } - PsiElement parent = modifierList.getParent(); boolean level8OrHigher = PsiUtil.isLanguageLevel8OrHigher(modifierList); boolean level9OrHigher = PsiUtil.isLanguageLevel9OrHigher(modifierList); for (@PsiModifier.ModifierConstant String incompatible : incompatibles) { @@ -254,13 +253,13 @@ private static String getIncompatibleModifier( continue; } } - if (parent instanceof PsiMethod) { + if (modifierList.getParent() instanceof PsiMethod method) { if (level9OrHigher && modifier.equals(PsiModifier.PRIVATE) && incompatible.equals(PsiModifier.PUBLIC)) { continue; } if (modifier.equals(PsiModifier.STATIC) && incompatible.equals(PsiModifier.FINAL)) { - PsiClass containingClass = ((PsiMethod)parent).getContainingClass(); + PsiClass containingClass = method.getContainingClass(); if (containingClass == null || !containingClass.isInterface()) { continue; } @@ -281,6 +280,7 @@ private static String getIncompatibleModifier( * make element protected/package-private/public suggestion * for private method in the interface it should add default modifier as well */ + @RequiredReadAction public static void registerAccessQuickFixAction( @Nonnull PsiMember refElement, @Nonnull PsiJavaCodeReferenceElement place, @@ -292,8 +292,8 @@ public static void registerAccessQuickFixAction( } PsiClass accessObjectClass = null; PsiElement qualifier = place.getQualifier(); - if (qualifier instanceof PsiExpression) { - accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass((PsiExpression)qualifier).getElement(); + if (qualifier instanceof PsiExpression qExpr) { + accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass(qExpr).getElement(); } registerReplaceInaccessibleFieldWithGetterSetterFix(refElement, place, accessObjectClass, errorResult); @@ -307,8 +307,8 @@ public static void registerAccessQuickFixAction( PsiClass packageLocalClassInTheMiddle = getPackageLocalClassInTheMiddle(place); if (packageLocalClassInTheMiddle != null) { - IntentionAction fix = - QuickFixFactory.getInstance().createModifierListFix(packageLocalClassInTheMiddle, PsiModifier.PUBLIC, true, true); + IntentionAction fix = QuickFixFactory.getInstance() + .createModifierListFix(packageLocalClassInTheMiddle, PsiModifier.PUBLIC, true, true); QuickFixAction.registerQuickFixAction(errorResult, fix); return; } @@ -322,7 +322,7 @@ public static void registerAccessQuickFixAction( if (refElement.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) { minModifier = PsiModifier.PROTECTED; } - if (refElement.hasModifierProperty(PsiModifier.PROTECTED)) { + if (refElement.isProtected()) { minModifier = PsiModifier.PUBLIC; } PsiClass containingClass = refElement.getContainingClass(); @@ -354,26 +354,23 @@ public static void registerAccessQuickFixAction( } @Nullable + @RequiredReadAction private static PsiClass getPackageLocalClassInTheMiddle(@Nonnull PsiElement place) { - if (place instanceof PsiReferenceExpression) { + if (place instanceof PsiReferenceExpression refExpr) { // check for package-private classes in the middle - PsiReferenceExpression expression = (PsiReferenceExpression)place; while (true) { - PsiElement resolved = expression.resolve(); - if (resolved instanceof PsiField) { - PsiField field = (PsiField)resolved; + if (refExpr.resolve() instanceof PsiField field) { PsiClass aClass = field.getContainingClass(); - if (aClass != null && aClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) && !JavaPsiFacade.getInstance(aClass.getProject()) - .arePackagesTheSame(aClass, place)) { - + if (aClass != null && aClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) + && !JavaPsiFacade.getInstance(aClass.getProject()).arePackagesTheSame(aClass, place)) { return aClass; } } - PsiExpression qualifier = expression.getQualifierExpression(); - if (!(qualifier instanceof PsiReferenceExpression)) { + PsiExpression qualifier = refExpr.getQualifierExpression(); + if (!(qualifier instanceof PsiReferenceExpression qualifierRefExpr)) { break; } - expression = (PsiReferenceExpression)qualifier; + refExpr = qualifierRefExpr; } } return null; @@ -381,6 +378,7 @@ private static PsiClass getPackageLocalClassInTheMiddle(@Nonnull PsiElement plac @Nullable + @RequiredReadAction public static HighlightInfo checkInstanceOfApplicable(@Nonnull PsiInstanceOfExpression expression) { PsiExpression operand = expression.getOperand(); PsiTypeElement typeElement = expression.getCheckType(); @@ -392,16 +390,16 @@ public static HighlightInfo checkInstanceOfApplicable(@Nonnull PsiInstanceOfExpr if (operandType == null) { return null; } - if (TypeConversionUtil.isPrimitiveAndNotNull(operandType) || TypeConversionUtil.isPrimitiveAndNotNull(checkType) || !TypeConversionUtil.areTypesConvertible( - operandType, - checkType - )) { - String message = JavaErrorBundle.message( - "inconvertible.type.cast", - JavaHighlightUtil.formatType(operandType), - JavaHighlightUtil.formatType(checkType) - ); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create(); + if (TypeConversionUtil.isPrimitiveAndNotNull(operandType) + || TypeConversionUtil.isPrimitiveAndNotNull(checkType) + || !TypeConversionUtil.areTypesConvertible(operandType, checkType)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.inconvertibleTypeCast( + JavaHighlightUtil.formatType(operandType), + JavaHighlightUtil.formatType(checkType) + )) + .create(); } return null; } @@ -436,53 +434,56 @@ public static HighlightInfo checkIntersectionInTypeCast( for (int i = 1; i < conjuncts.length; i++) { PsiTypeElement conjunct = conjuncts[i]; PsiType conjType = conjunct.getType(); - if (conjType instanceof PsiClassType) { - PsiClass aClass = ((PsiClassType)conjType).resolve(); + if (conjType instanceof PsiClassType classType) { + PsiClass aClass = classType.resolve(); if (aClass != null && !aClass.isInterface()) { - HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(conjunct) - .descriptionAndTooltip(JavaErrorBundle.message("interface.expected")) + .descriptionAndTooltip(JavaErrorLocalize.interfaceExpected()) + .registerFix( + new FlipIntersectionSidesFix(aClass.getName(), conjList, conjunct, castTypeElement), + null, + null, + null, + null + ) .create(); - QuickFixAction.registerQuickFixAction( - errorResult, - new FlipIntersectionSidesFix(aClass.getName(), conjList, conjunct, castTypeElement), - null - ); - return errorResult; } } else { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(conjunct) - .descriptionAndTooltip("Unexpected type: class is expected") + .descriptionAndTooltip(LocalizeValue.localizeTODO("Unexpected type: class is expected")) .create(); } if (!erasures.add(TypeConversionUtil.erasure(conjType))) { - HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(conjunct) - .descriptionAndTooltip("Repeated interface") + .descriptionAndTooltip(LocalizeValue.localizeTODO("Repeated interface")) + .registerFix(new DeleteRepeatedInterfaceFix(conjunct, conjList), null, null, null, null) .create(); - QuickFixAction.registerQuickFixAction(highlightInfo, new DeleteRepeatedInterfaceFix(conjunct, conjList), null); - return highlightInfo; } } 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; + SimpleReference differentArgumentsMessage = SimpleReference.create(); + PsiClass sameGenericParameterization = InferenceSession.findParameterizationOfTheSameGenericClass( + typeList, + pair -> { + if (!TypesDistinctProver.provablyDistinct(pair.first, pair.second)) { + return true; + } + differentArgumentsMessage.set(pair.first.getPresentableText() + " and " + pair.second.getPresentableText()); + return false; } - differentArgumentsMessage.set(pair.first.getPresentableText() + " and " + pair.second.getPresentableText()); - return false; - }); + ); if (sameGenericParameterization != null) { - String message = - formatClass(sameGenericParameterization) + " cannot be inherited with different arguments: " + differentArgumentsMessage.get(); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(message) + .descriptionAndTooltip(LocalizeValue.localizeTODO( + formatClass(sameGenericParameterization) + " cannot be inherited with different arguments: " + + differentArgumentsMessage.get() + )) .create(); } } @@ -491,7 +492,9 @@ public static HighlightInfo checkIntersectionInTypeCast( return null; } + @RequiredReadAction private static boolean isIntersection(PsiTypeElement castTypeElement, PsiType castType) { + //noinspection SimplifiableIfStatement if (castType instanceof PsiIntersectionType) { return true; } @@ -499,6 +502,7 @@ private static boolean isIntersection(PsiTypeElement castTypeElement, PsiType ca } @Nullable + @RequiredReadAction public static HighlightInfo checkInconvertibleTypeCast(@Nonnull PsiTypeCastExpression expression) { PsiTypeElement castTypeElement = expression.getCastType(); if (castTypeElement == null) { @@ -515,12 +519,13 @@ public static HighlightInfo checkInconvertibleTypeCast(@Nonnull PsiTypeCastExpre if (operandType != null && !TypeConversionUtil.areTypesConvertible(operandType, castType, PsiUtil.getLanguageLevel(expression)) && !RedundantCastUtil.isInPolymorphicCall(expression)) { - String message = JavaErrorBundle.message( - "inconvertible.type.cast", - JavaHighlightUtil.formatType(operandType), - JavaHighlightUtil.formatType(castType) - ); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.inconvertibleTypeCast( + JavaHighlightUtil.formatType(operandType), + JavaHighlightUtil.formatType(castType) + )) + .create(); } @@ -528,23 +533,26 @@ public static HighlightInfo checkInconvertibleTypeCast(@Nonnull PsiTypeCastExpre } @Nullable + @RequiredReadAction public static HighlightInfo checkVariableExpected(@Nonnull PsiExpression expression) { PsiExpression lValue; - if (expression instanceof PsiAssignmentExpression) { - PsiAssignmentExpression assignment = (PsiAssignmentExpression)expression; + if (expression instanceof PsiAssignmentExpression assignment) { lValue = assignment.getLExpression(); } else if (PsiUtil.isIncrementDecrementOperation(expression)) { - lValue = - expression instanceof PsiPostfixExpression ? ((PsiPostfixExpression)expression).getOperand() : ((PsiPrefixExpression)expression).getOperand(); + lValue = expression instanceof PsiPostfixExpression postfixExpr + ? postfixExpr.getOperand() + : ((PsiPrefixExpression)expression).getOperand(); } else { lValue = null; } HighlightInfo errorResult = null; if (lValue != null && !TypeConversionUtil.isLValue(lValue)) { - String description = JavaErrorBundle.message("variable.expected"); - errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(lValue).descriptionAndTooltip(description).create(); + errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(lValue) + .descriptionAndTooltip(JavaErrorLocalize.variableExpected()) + .create(); } return errorResult; @@ -760,12 +768,12 @@ public static HighlightInfo checkReturnStatementType(@Nonnull PsiReturnStatement if (parent instanceof PsiClassInitializer) { break; } - if (parent instanceof PsiLambdaExpression) { - lambda = (PsiLambdaExpression)parent; + if (parent instanceof PsiLambdaExpression parentLambda) { + lambda = parentLambda; break; } - if (parent instanceof PsiMethod) { - method = (PsiMethod)parent; + if (parent instanceof PsiMethod parentMethod) { + method = parentMethod; break; } parent = parent.getParent(); @@ -786,7 +794,7 @@ else if (method == null && !(parent instanceof ServerPageFile)) { else { PsiType returnType = method != null ? method.getReturnType() : null/*JSP page returns void*/; boolean isMethodVoid = returnType == null || PsiType.VOID.equals(returnType); - final PsiExpression returnValue = statement.getReturnValue(); + PsiExpression returnValue = statement.getReturnValue(); if (returnValue != null) { PsiType valueType = RefactoringChangeUtil.getTypeByExpression(returnValue); if (isMethodVoid) { @@ -842,8 +850,8 @@ private static void registerCollectionToArrayFixAction( @Nullable PsiType toType, @Nonnull PsiExpression expression ) { - if (toType instanceof PsiArrayType) { - PsiType arrayComponentType = ((PsiArrayType)toType).getComponentType(); + if (toType instanceof PsiArrayType arrayType) { + PsiType arrayComponentType = arrayType.getComponentType(); if (!(arrayComponentType instanceof PsiPrimitiveType) && !(PsiUtil.resolveClassInType(arrayComponentType) instanceof PsiTypeParameter) && InheritanceUtil.isInheritor(fromType, JavaClassNames.JAVA_UTIL_COLLECTION)) { @@ -851,7 +859,7 @@ private static void registerCollectionToArrayFixAction( if (collectionItemType != null && arrayComponentType.isAssignableFrom(collectionItemType)) { QuickFixAction.registerQuickFixAction( info, - QuickFixFactory.getInstance().createCollectionToArrayFix(expression, (PsiArrayType)toType) + QuickFixFactory.getInstance().createCollectionToArrayFix(expression, arrayType) ); } } @@ -859,16 +867,16 @@ private static void registerCollectionToArrayFixAction( } @Nonnull - public static String getUnhandledExceptionsDescriptor(@Nonnull Collection unhandled) { + public static LocalizeValue getUnhandledExceptionsDescriptor(@Nonnull Collection unhandled) { return getUnhandledExceptionsDescriptor(unhandled, null); } @Nonnull - private static String getUnhandledExceptionsDescriptor(@Nonnull Collection unhandled, @Nullable String source) { + private static LocalizeValue getUnhandledExceptionsDescriptor(@Nonnull Collection unhandled, @Nullable String source) { String exceptions = formatTypes(unhandled); return source != null - ? JavaErrorLocalize.unhandledCloseExceptions(exceptions, unhandled.size(), source).get() - : JavaErrorLocalize.unhandledExceptions(exceptions, unhandled.size()).get(); + ? JavaErrorLocalize.unhandledCloseExceptions(exceptions, unhandled.size(), source) + : JavaErrorLocalize.unhandledExceptions(exceptions, unhandled.size()); } @Nonnull @@ -881,15 +889,16 @@ private static String formatTypes(@Nonnull Collection unhandled) { public static HighlightInfo checkVariableAlreadyDefined(@Nonnull PsiVariable variable) { PsiVariable oldVariable = JavaPsiVariableUtil.findPreviousVariableDeclaration(variable); if (oldVariable != null) { - String description = JavaErrorLocalize.variableAlreadyDefined(variable.getName()).get(); PsiIdentifier identifier = variable.getNameIdentifier(); assert identifier != null : variable; - HighlightInfo highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(identifier).descriptionAndTooltip(description).create(); - if (variable instanceof PsiLocalVariable) { + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(identifier) + .descriptionAndTooltip(JavaErrorLocalize.variableAlreadyDefined(variable.getName())) + .create(); + if (variable instanceof PsiLocalVariable localVar) { QuickFixAction.registerQuickFixAction( highlightInfo, - QuickFixFactory.getInstance().createReuseVariableDeclarationFix((PsiLocalVariable)variable) + QuickFixFactory.getInstance().createReuseVariableDeclarationFix(localVar) ); } return highlightInfo; @@ -898,17 +907,22 @@ public static HighlightInfo checkVariableAlreadyDefined(@Nonnull PsiVariable var } @Nullable + @RequiredReadAction public static HighlightInfo checkUnderscore(@Nonnull PsiIdentifier identifier, @Nonnull LanguageLevel languageLevel) { if ("_".equals(identifier.getText())) { if (languageLevel.isAtLeast(LanguageLevel.JDK_1_9)) { - String text = JavaErrorBundle.message("underscore.identifier.error"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(identifier).descriptionAndTooltip(text).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(identifier) + .descriptionAndTooltip(JavaErrorLocalize.underscoreIdentifierError()) + .create(); } else if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { PsiElement parent = identifier.getParent(); - if (parent instanceof PsiParameter && ((PsiParameter)parent).getDeclarationScope() instanceof PsiLambdaExpression) { - String text = JavaErrorBundle.message("underscore.lambda.identifier"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(identifier).descriptionAndTooltip(text).create(); + if (parent instanceof PsiParameter parameter && parameter.getDeclarationScope() instanceof PsiLambdaExpression) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(identifier) + .descriptionAndTooltip(JavaErrorLocalize.underscoreLambdaIdentifier()) + .create(); } } } @@ -939,6 +953,7 @@ private static String formatField(@Nonnull PsiField field) { } @Nullable + @RequiredReadAction public static HighlightInfo checkUnhandledExceptions(@Nonnull PsiElement element, @Nullable TextRange textRange) { List unhandledExceptions = ExceptionUtil.getUnhandledExceptions(element); if (unhandledExceptions.isEmpty()) { @@ -953,14 +968,16 @@ public static HighlightInfo checkUnhandledExceptions(@Nonnull PsiElement element if (textRange == null) { textRange = element.getTextRange(); } - String description = getUnhandledExceptionsDescriptor(unhandledExceptions); - HighlightInfo errorResult = - HighlightInfo.newHighlightInfo(highlightType).range(textRange).descriptionAndTooltip(description).create(); + HighlightInfo errorResult = HighlightInfo.newHighlightInfo(highlightType) + .range(textRange) + .descriptionAndTooltip(getUnhandledExceptionsDescriptor(unhandledExceptions)) + .create(); registerUnhandledExceptionFixes(element, errorResult, unhandledExceptions); return errorResult; } @Nullable + @RequiredReadAction public static HighlightInfo checkUnhandledCloserExceptions(@Nonnull PsiResourceListElement resource) { List unhandled = ExceptionUtil.getUnhandledCloserExceptions(resource, null); if (unhandled.isEmpty()) { @@ -972,8 +989,10 @@ public static HighlightInfo checkUnhandledCloserExceptions(@Nonnull PsiResourceL return null; } - String description = getUnhandledExceptionsDescriptor(unhandled, "auto-closeable resource"); - HighlightInfo highlight = HighlightInfo.newHighlightInfo(highlightType).range(resource).descriptionAndTooltip(description).create(); + HighlightInfo highlight = HighlightInfo.newHighlightInfo(highlightType) + .range(resource) + .descriptionAndTooltip(getUnhandledExceptionsDescriptor(unhandled, "auto-closeable resource")) + .create(); registerUnhandledExceptionFixes(resource, highlight, unhandled); return highlight; } @@ -1008,11 +1027,14 @@ private static HighlightInfoType getUnhandledExceptionHighlightType(PsiElement e } @Nullable + @RequiredReadAction public static HighlightInfo checkBreakOutsideLoop(@Nonnull PsiBreakStatement statement) { if (statement.getLabelIdentifier() == null) { if (new PsiMatcherImpl(statement).ancestor(EnclosingLoopOrSwitchMatcherExpression.INSTANCE).getElement() == null) { - String description = JavaErrorBundle.message("break.outside.switch.or.loop"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(description).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(statement) + .descriptionAndTooltip(JavaErrorLocalize.breakOutsideSwitchOrLoop()) + .create(); } } else { @@ -1023,11 +1045,14 @@ public static HighlightInfo checkBreakOutsideLoop(@Nonnull PsiBreakStatement sta @Nullable + @RequiredReadAction public static HighlightInfo checkContinueOutsideLoop(@Nonnull PsiContinueStatement statement) { if (statement.getLabelIdentifier() == null) { if (new PsiMatcherImpl(statement).ancestor(EnclosingLoopMatcherExpression.INSTANCE).getElement() == null) { - String description = JavaErrorBundle.message("continue.outside.loop"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(description).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(statement) + .descriptionAndTooltip(JavaErrorLocalize.continueOutsideLoop()) + .create(); } } else { @@ -1035,23 +1060,29 @@ public static HighlightInfo checkContinueOutsideLoop(@Nonnull PsiContinueStateme if (exitedStatement == null) { return null; } - if (!(exitedStatement instanceof PsiForStatement) && !(exitedStatement instanceof PsiWhileStatement) && !(exitedStatement instanceof PsiDoWhileStatement) && !(exitedStatement instanceof - PsiForeachStatement)) { - String description = JavaErrorBundle.message("not.loop.label", statement.getLabelIdentifier().getText()); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(description).create(); + if (!(exitedStatement instanceof PsiForStatement) + && !(exitedStatement instanceof PsiWhileStatement) + && !(exitedStatement instanceof PsiDoWhileStatement) + && !(exitedStatement instanceof PsiForeachStatement)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(statement) + .descriptionAndTooltip(JavaErrorLocalize.notLoopLabel(statement.getLabelIdentifier().getText())) + .create(); } } return null; } @Nullable + @RequiredReadAction public static HighlightInfo checkIllegalModifierCombination(@Nonnull PsiKeyword keyword, @Nonnull PsiModifierList modifierList) { @PsiModifier.ModifierConstant String modifier = keyword.getText(); String incompatible = getIncompatibleModifier(modifier, modifierList); if (incompatible != null) { - String message = JavaErrorBundle.message("incompatible.modifiers", modifier, incompatible); - HighlightInfo highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(keyword).descriptionAndTooltip(message).create(); + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(keyword) + .descriptionAndTooltip(JavaErrorLocalize.incompatibleModifiers(modifier, incompatible)) + .create(); QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance() .createModifierListFix(modifierList, modifier, false, false)); return highlightInfo; @@ -1065,8 +1096,8 @@ private static Map> getIncompatibleModifierMap(@Nullable Psi if (modifierListOwner == null || PsiUtilCore.hasErrorElementChild(modifierListOwner)) { return null; } - if (modifierListOwner instanceof PsiClass) { - return ((PsiClass)modifierListOwner).isInterface() ? ourInterfaceIncompatibleModifiers : ourClassIncompatibleModifiers; + if (modifierListOwner instanceof PsiClass psiClass) { + return psiClass.isInterface() ? ourInterfaceIncompatibleModifiers : ourClassIncompatibleModifiers; } if (modifierListOwner instanceof PsiMethod) { return ourMethodIncompatibleModifiers; @@ -1087,12 +1118,14 @@ private static Map> getIncompatibleModifierMap(@Nullable Psi } @Nullable + @RequiredReadAction public static String getIncompatibleModifier(String modifier, @Nonnull PsiModifierList modifierList) { Map> incompatibleModifierMap = getIncompatibleModifierMap(modifierList.getParent()); return incompatibleModifierMap != null ? getIncompatibleModifier(modifier, modifierList, incompatibleModifierMap) : null; } @Nullable + @RequiredReadAction public static HighlightInfo checkNotAllowedModifier(@Nonnull PsiKeyword keyword, @Nonnull PsiModifierList modifierList) { PsiElement modifierOwner = modifierList.getParent(); Map> incompatibleModifierMap = getIncompatibleModifierMap(modifierOwner); @@ -1103,30 +1136,31 @@ public static HighlightInfo checkNotAllowedModifier(@Nonnull PsiKeyword keyword, @PsiModifier.ModifierConstant String modifier = keyword.getText(); Set incompatibles = incompatibleModifierMap.get(modifier); PsiElement modifierOwnerParent = - modifierOwner instanceof PsiMember ? ((PsiMember)modifierOwner).getContainingClass() : modifierOwner.getParent(); + modifierOwner instanceof PsiMember member ? member.getContainingClass() : modifierOwner.getParent(); if (modifierOwnerParent == null) { modifierOwnerParent = modifierOwner.getParent(); } boolean isAllowed = true; - if (modifierOwner instanceof PsiClass) { - PsiClass aClass = (PsiClass)modifierOwner; + if (modifierOwner instanceof PsiClass aClass) { if (aClass.isInterface()) { - if (PsiModifier.STATIC.equals(modifier) || PsiModifier.PRIVATE.equals(modifier) || PsiModifier.PROTECTED.equals(modifier) || PsiModifier.PACKAGE_LOCAL - .equals(modifier)) { + if (PsiModifier.STATIC.equals(modifier) + || PsiModifier.PRIVATE.equals(modifier) + || PsiModifier.PROTECTED.equals(modifier) + || PsiModifier.PACKAGE_LOCAL.equals(modifier)) { isAllowed = modifierOwnerParent instanceof PsiClass; } } else { if (PsiModifier.PUBLIC.equals(modifier)) { - isAllowed = - modifierOwnerParent instanceof PsiJavaFile || modifierOwnerParent instanceof PsiClass && (modifierOwnerParent instanceof PsiSyntheticClass || ((PsiClass) - modifierOwnerParent).getQualifiedName() != null); + isAllowed = modifierOwnerParent instanceof PsiJavaFile + || modifierOwnerParent instanceof PsiClass psiClass + && (psiClass instanceof PsiSyntheticClass || psiClass.getQualifiedName() != null); } else if (PsiModifier.STATIC.equals(modifier) || PsiModifier.PRIVATE.equals(modifier) || PsiModifier.PROTECTED.equals(modifier) || PsiModifier.PACKAGE_LOCAL.equals(modifier)) { - isAllowed = modifierOwnerParent instanceof PsiClass && ((PsiClass)modifierOwnerParent).getQualifiedName() != null + isAllowed = modifierOwnerParent instanceof PsiClass psiClass && psiClass.getQualifiedName() != null || FileTypeUtils.isInServerPageFile(modifierOwnerParent); } @@ -1139,30 +1173,26 @@ else if (PsiModifier.STATIC.equals(modifier) } } } - else if (modifierOwner instanceof PsiMethod) { - PsiMethod method = (PsiMethod)modifierOwner; + else if (modifierOwner instanceof PsiMethod method) { isAllowed = !(method.isConstructor() && ourConstructorNotAllowedModifiers.contains(modifier)); PsiClass containingClass = method.getContainingClass(); - if ((method.hasModifierProperty(PsiModifier.PUBLIC) || method.hasModifierProperty(PsiModifier.PROTECTED)) && method.isConstructor() && containingClass != null && containingClass - .isEnum()) { + if ((method.isPublic() || method.isProtected()) && method.isConstructor() + && containingClass != null && containingClass.isEnum()) { isAllowed = false; } if (PsiModifier.PRIVATE.equals(modifier)) { - isAllowed &= - modifierOwnerParent instanceof PsiClass && (!((PsiClass)modifierOwnerParent).isInterface() || PsiUtil.isLanguageLevel9OrHigher( - modifierOwner) && !((PsiClass) - modifierOwnerParent).isAnnotationType()); + isAllowed &= modifierOwnerParent instanceof PsiClass modifierClass && (!modifierClass.isInterface() + || PsiUtil.isLanguageLevel9OrHigher(modifierOwner) && !modifierClass.isAnnotationType()); } else if (PsiModifier.STRICTFP.equals(modifier)) { - isAllowed &= - modifierOwnerParent instanceof PsiClass && (!((PsiClass)modifierOwnerParent).isInterface() || PsiUtil.isLanguageLevel8OrHigher( - modifierOwner)); + isAllowed &= modifierOwnerParent instanceof PsiClass modifierClass + && (!modifierClass.isInterface() || PsiUtil.isLanguageLevel8OrHigher(modifierOwner)); } else if (PsiModifier.PROTECTED.equals(modifier) || PsiModifier.TRANSIENT.equals(modifier) || PsiModifier.SYNCHRONIZED.equals(modifier)) { - isAllowed &= modifierOwnerParent instanceof PsiClass && !((PsiClass)modifierOwnerParent).isInterface(); + isAllowed &= modifierOwnerParent instanceof PsiClass modifierClass && !modifierClass.isInterface(); } if (containingClass != null && containingClass.isInterface()) { @@ -1175,10 +1205,12 @@ else if (PsiModifier.PROTECTED.equals(modifier) } } else if (modifierOwner instanceof PsiField) { - if (PsiModifier.PRIVATE.equals(modifier) || PsiModifier.PROTECTED.equals(modifier) || PsiModifier.TRANSIENT.equals(modifier) || PsiModifier.STRICTFP - .equals(modifier) || PsiModifier - .SYNCHRONIZED.equals(modifier)) { - isAllowed = modifierOwnerParent instanceof PsiClass && !((PsiClass)modifierOwnerParent).isInterface(); + if (PsiModifier.PRIVATE.equals(modifier) + || PsiModifier.PROTECTED.equals(modifier) + || PsiModifier.TRANSIENT.equals(modifier) + || PsiModifier.STRICTFP.equals(modifier) + || PsiModifier.SYNCHRONIZED.equals(modifier)) { + isAllowed = modifierOwnerParent instanceof PsiClass modifierClass && !modifierClass.isInterface(); } } else if (modifierOwner instanceof PsiClassInitializer) { @@ -1193,18 +1225,18 @@ else if (modifierOwner instanceof PsiReceiverParameter) { isAllowed &= incompatibles != null; if (!isAllowed) { - String message = JavaErrorBundle.message("modifier.not.allowed", modifier); - HighlightInfo highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(keyword).descriptionAndTooltip(message).create(); - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance() - .createModifierListFix(modifierList, modifier, false, false)); - return highlightInfo; + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(keyword) + .descriptionAndTooltip(JavaErrorLocalize.modifierNotAllowed(modifier)) + .registerFix(QuickFixFactory.getInstance().createModifierListFix(modifierList, modifier, false, false), null, null, null, null) + .create(); } return null; } @Nullable + @RequiredReadAction public static HighlightInfo checkLiteralExpressionParsingError( @Nonnull PsiLiteralExpression expression, LanguageLevel level, @@ -1253,32 +1285,28 @@ public static HighlightInfo checkLiteralExpressionParsingError( } } - PsiElement parent = expression.getParent(); if (type == JavaTokenType.INTEGER_LITERAL) { String cleanText = StringUtil.replace(text, "_", ""); //literal 2147483648 may appear only as the operand of the unary negation operator -. - if (!(cleanText.equals(PsiLiteralUtil._2_IN_31) && - parent instanceof PsiPrefixExpression && - ((PsiPrefixExpression)parent).getOperationTokenType() == JavaTokenType.MINUS)) { + if (!(cleanText.equals(PsiLiteralUtil._2_IN_31) + && expression.getParent() instanceof PsiPrefixExpression prefixExpr + && prefixExpr.getOperationTokenType() == JavaTokenType.MINUS)) { if (cleanText.equals(PsiLiteralUtil.HEX_PREFIX)) { - String message = JavaErrorBundle.message("hexadecimal.numbers.must.contain.at.least.one.hexadecimal.digit"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.hexadecimalNumbersMustContainAtLeastOneHexadecimalDigit()) .create(); } if (cleanText.equals(PsiLiteralUtil.BIN_PREFIX)) { - String message = JavaErrorBundle.message("binary.numbers.must.contain.at.least.one.hexadecimal.digit"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.binaryNumbersMustContainAtLeastOneHexadecimalDigit()) .create(); } if (value == null || cleanText.equals(PsiLiteralUtil._2_IN_31)) { - String message = JavaErrorBundle.message("integer.number.too.large"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.integerNumberTooLarge()) .create(); } } @@ -1286,36 +1314,35 @@ public static HighlightInfo checkLiteralExpressionParsingError( else if (type == JavaTokenType.LONG_LITERAL) { String cleanText = StringUtil.replace(StringUtil.trimEnd(text, 'l'), "_", ""); //literal 9223372036854775808L may appear only as the operand of the unary negation operator -. - if (!(cleanText.equals(PsiLiteralUtil._2_IN_63) && - parent instanceof PsiPrefixExpression && - ((PsiPrefixExpression)parent).getOperationTokenType() == JavaTokenType.MINUS)) { + if (!(cleanText.equals(PsiLiteralUtil._2_IN_63) + && expression.getParent() instanceof PsiPrefixExpression prefixExpr + && prefixExpr.getOperationTokenType() == JavaTokenType.MINUS)) { if (cleanText.equals(PsiLiteralUtil.HEX_PREFIX)) { - String message = JavaErrorBundle.message("hexadecimal.numbers.must.contain.at.least.one.hexadecimal.digit"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.hexadecimalNumbersMustContainAtLeastOneHexadecimalDigit()) .create(); } if (cleanText.equals(PsiLiteralUtil.BIN_PREFIX)) { - String message = JavaErrorBundle.message("binary.numbers.must.contain.at.least.one.hexadecimal.digit"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.binaryNumbersMustContainAtLeastOneHexadecimalDigit()) .create(); } if (value == null || cleanText.equals(PsiLiteralUtil._2_IN_63)) { - String message = JavaErrorBundle.message("long.number.too.large"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.longNumberTooLarge()) .create(); } } } else if (isFP) { if (value == null) { - String message = JavaErrorBundle.message("malformed.floating.point.literal"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.malformedFloatingPointLiteral().get()) + .create(); } } else if (type == JavaTokenType.CHARACTER_LITERAL) { @@ -1324,35 +1351,32 @@ else if (type == JavaTokenType.CHARACTER_LITERAL) { return null; } if (!StringUtil.endsWithChar(text, '\'') || text.length() == 1) { - String message = JavaErrorBundle.message("unclosed.char.literal"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.unclosedCharLiteral()) .create(); } text = text.substring(1, text.length() - 1); CharSequence chars = CodeInsightUtilCore.parseStringCharacters(text, null); if (chars == null) { - String message = JavaErrorBundle.message("illegal.escape.character.in.character.literal"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.illegalEscapeCharacterInCharacterLiteral()) .create(); } int length = chars.length(); if (length > 1) { - String message = JavaErrorBundle.message("too.many.characters.in.character.literal"); - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create(); - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createConvertToStringLiteralAction()); - return info; + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.tooManyCharactersInCharacterLiteral()) + .registerFix(QuickFixFactory.getInstance().createConvertToStringLiteralAction(), null, null, null, null) + .create(); } else if (length == 0) { - String message = JavaErrorBundle.message("empty.character.literal"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.emptyCharacterLiteral()) .create(); } } @@ -1371,70 +1395,63 @@ else if (type == JavaTokenType.STRING_LITERAL || type == JavaTokenType.TEXT_BLOC } if (StringUtil.endsWithChar(text, '\"')) { if (text.length() == 1) { - String message = JavaErrorBundle.message("illegal.line.end.in.string.literal"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.illegalLineEndInStringLiteral()) .create(); } text = text.substring(1, text.length() - 1); } else { - String message = JavaErrorBundle.message("illegal.line.end.in.string.literal"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.illegalLineEndInStringLiteral()) .create(); } if (CodeInsightUtilCore.parseStringCharacters(text, null) == null) { - String message = JavaErrorBundle.message("illegal.escape.character.in.string.literal"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.illegalEscapeCharacterInStringLiteral()) .create(); } } } - else { - if (value == null) { - if (!text.endsWith("\"\"\"")) { - String message = JavaErrorBundle.message("text.block.unclosed"); - int p = expression.getTextRange().getEndOffset(); + else if (value == null) { + if (!text.endsWith("\"\"\"")) { + int p = expression.getTextRange().getEndOffset(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(p, p) + .endOfLine() + .descriptionAndTooltip(JavaErrorLocalize.textBlockUnclosed()) + .create(); + } + else { + StringBuilder chars = new StringBuilder(text.length()); + int[] offsets = new int[text.length() + 1]; + boolean success = CodeInsightUtilCore.parseStringCharacters(text, chars, offsets); + if (!success) { + TextRange textRange = chars.length() < text.length() - 1 + ? new TextRange(offsets[chars.length()], offsets[chars.length() + 1]) + : expression.getTextRange(); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(p, p) - .endOfLine() - .descriptionAndTooltip(message) + .range(expression, textRange) + .descriptionAndTooltip(JavaErrorLocalize.illegalEscapeCharacterInStringLiteral()) .create(); } else { - StringBuilder chars = new StringBuilder(text.length()); - int[] offsets = new int[text.length() + 1]; - boolean success = CodeInsightUtilCore.parseStringCharacters(text, chars, offsets); - if (!success) { - String message = JavaErrorBundle.message("illegal.escape.character.in.string.literal"); - TextRange textRange = chars.length() < text.length() - 1 - ? new TextRange(offsets[chars.length()], offsets[chars.length() + 1]) - : expression.getTextRange(); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(expression, textRange) - .descriptionAndTooltip(message).create(); - } - else { - String message = JavaErrorBundle.message("text.block.new.line"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .range(expression) - .descriptionAndTooltip(message) - .create(); - } + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.textBlockNewLine()) + .create(); } } - else { - if (file != null && containsUnescaped(text, "\\\n")) { - HighlightInfo info = checkFeature(expression, JavaFeature.TEXT_BLOCK_ESCAPES, level, file); - if (info != null) { - return info; - } + } + else { + if (file != null && containsUnescaped(text, "\\\n")) { + HighlightInfo info = checkFeature(expression, JavaFeature.TEXT_BLOCK_ESCAPES, level, file); + if (info != null) { + return info; } } } @@ -1446,35 +1463,46 @@ else if (type == JavaTokenType.STRING_LITERAL || type == JavaTokenType.TEXT_BLOC } } - if (value instanceof Float) { - Float number = (Float)value; + if (value instanceof Float number) { if (number.isInfinite()) { - String message = JavaErrorBundle.message("floating.point.number.too.large"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.floatingPointNumberTooLarge()) + .create(); } - if (number.floatValue() == 0 && !TypeConversionUtil.isFPZero(text)) { - String message = JavaErrorBundle.message("floating.point.number.too.small"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create(); + if (number == 0 && !TypeConversionUtil.isFPZero(text)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.floatingPointNumberTooSmall()) + .create(); } } - else if (value instanceof Double) { - Double number = (Double)value; + else if (value instanceof Double number) { if (number.isInfinite()) { - String message = JavaErrorBundle.message("floating.point.number.too.large"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.floatingPointNumberTooLarge()) + .create(); } - if (number.doubleValue() == 0 && !TypeConversionUtil.isFPZero(text)) { - String message = JavaErrorBundle.message("floating.point.number.too.small"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create(); + if (number == 0 && !TypeConversionUtil.isFPZero(text)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.floatingPointNumberTooSmall()) + .create(); } } return null; } - private static final Pattern FP_LITERAL_PARTS = - Pattern.compile("(?:" + "(?:0x([_\\p{XDigit}]*)\\.?([_\\p{XDigit}]*)p[+-]?([_\\d]*))" + "|" + "(?:([_\\d]*)\\.?([_\\d]*)e?[+-]?([_\\d]*))" + ")" + - "[fd]?"); + private static final Pattern FP_LITERAL_PARTS = Pattern.compile( + "(?:" + + "(?:0x([_\\p{XDigit}]*)\\.?([_\\p{XDigit}]*)p[+-]?([_\\d]*))" + + "|" + + "(?:([_\\d]*)\\.?([_\\d]*)e?[+-]?([_\\d]*))" + + ")" + + "[fd]?" + ); private static boolean containsUnescaped(@Nonnull String text, @Nonnull String subText) { int start = 0; @@ -1494,6 +1522,7 @@ private static boolean containsUnescaped(@Nonnull String text, @Nonnull String s return false; } + @RequiredReadAction private static HighlightInfo checkUnderscores(@Nonnull PsiElement expression, @Nonnull String text, boolean isInt) { String[] parts = ArrayUtil.EMPTY_STRING_ARRAY; @@ -1520,8 +1549,10 @@ private static HighlightInfo checkUnderscores(@Nonnull PsiElement expression, @N for (String part : parts) { if (part != null && (StringUtil.startsWithChar(part, '_') || StringUtil.endsWithChar(part, '_'))) { - String message = JavaErrorBundle.message("illegal.underscore"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.illegalUnderscore()) + .create(); } } @@ -1529,11 +1560,12 @@ private static HighlightInfo checkUnderscores(@Nonnull PsiElement expression, @N } @Nullable + @RequiredReadAction public static HighlightInfo checkMustBeBoolean(@Nonnull PsiExpression expr, PsiType type) { PsiElement parent = expr.getParent(); - if (parent instanceof PsiIfStatement || parent instanceof PsiWhileStatement || parent instanceof PsiForStatement && expr.equals(((PsiForStatement)parent) - .getCondition()) || parent instanceof - PsiDoWhileStatement && expr.equals(((PsiDoWhileStatement)parent).getCondition())) { + if (parent instanceof PsiIfStatement || parent instanceof PsiWhileStatement + || parent instanceof PsiForStatement forStmt && expr.equals(forStmt.getCondition()) + || parent instanceof PsiDoWhileStatement doWhileStmt && expr.equals(doWhileStmt.getCondition())) { if (expr.getNextSibling() instanceof PsiErrorElement) { return null; } @@ -1549,10 +1581,10 @@ public static HighlightInfo checkMustBeBoolean(@Nonnull PsiExpression expr, PsiT ); } } - else if (expr instanceof PsiAssignmentExpression && ((PsiAssignmentExpression)expr).getOperationTokenType() == JavaTokenType.EQ) { + else if (expr instanceof PsiAssignmentExpression assignment && assignment.getOperationTokenType() == JavaTokenType.EQ) { QuickFixAction.registerQuickFixAction( info, - QuickFixFactory.getInstance().createAssignmentToComparisonFix((PsiAssignmentExpression)expr) + QuickFixFactory.getInstance().createAssignmentToComparisonFix(assignment) ); } return info; @@ -1561,7 +1593,6 @@ else if (expr instanceof PsiAssignmentExpression && ((PsiAssignmentExpression)ex return null; } - @Nonnull public static Set collectUnhandledExceptions(@Nonnull PsiTryStatement statement) { Set thrownTypes = new HashSet<>(); @@ -1582,8 +1613,7 @@ public static Set collectUnhandledExceptions(@Nonnull PsiTryStatem @Nonnull @RequiredReadAction public static List checkExceptionThrownInTry(@Nonnull PsiParameter parameter, @Nonnull Set thrownTypes) { - PsiElement declarationScope = parameter.getDeclarationScope(); - if (!(declarationScope instanceof PsiCatchSection)) { + if (!(parameter.getDeclarationScope() instanceof PsiCatchSection)) { return Collections.emptyList(); } @@ -1634,7 +1664,7 @@ private static List checkMultiCatchParameter( for (PsiTypeElement typeElement : typeElements) { PsiType catchType = typeElement.getType(); - if (catchType instanceof PsiClassType && ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)catchType)) { + if (catchType instanceof PsiClassType classType && ExceptionUtil.isUncheckedExceptionOrSuperclass(classType)) { continue; } @@ -1658,19 +1688,18 @@ private static List checkMultiCatchParameter( return highlights; } - @Nonnull + @RequiredReadAction public static Collection checkWithImprovedCatchAnalysis( @Nonnull PsiParameter parameter, @Nonnull Collection thrownInTryStatement, @Nonnull PsiFile containingFile ) { PsiElement scope = parameter.getDeclarationScope(); - if (!(scope instanceof PsiCatchSection)) { + if (!(scope instanceof PsiCatchSection catchSection)) { return Collections.emptyList(); } - PsiCatchSection catchSection = (PsiCatchSection)scope; PsiCatchSection[] allCatchSections = catchSection.getTryStatement().getCatchSections(); int idx = ArrayUtil.find(allCatchSections, catchSection); if (idx <= 0) { @@ -1682,7 +1711,7 @@ public static Collection checkWithImprovedCatchAnalysis( GlobalSearchScope parameterResolveScope = parameter.getResolveScope(); thrownTypes.add(PsiType.getJavaLangError(manager, parameterResolveScope)); thrownTypes.add(PsiType.getJavaLangRuntimeException(manager, parameterResolveScope)); - Collection result = ContainerUtil.newArrayList(); + Collection result = new ArrayList<>(); List parameterTypeElements = PsiUtil.getParameterTypeElements(parameter); boolean isMultiCatch = parameterTypeElements.size() > 1; @@ -1716,10 +1745,9 @@ public static Collection checkWithImprovedCatchAnalysis( // check & warn if (caught.isEmpty()) { - String message = JavaErrorBundle.message("exception.already.caught.warn", formatTypes(caughtCopy), caughtCopy.size()); HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING) .range(catchSection) - .descriptionAndTooltip(message) + .descriptionAndTooltip(JavaErrorLocalize.exceptionAlreadyCaughtWarn(formatTypes(caughtCopy), caughtCopy.size())) .create(); if (isMultiCatch) { QuickFixAction.registerQuickFixAction( @@ -1738,6 +1766,7 @@ public static Collection checkWithImprovedCatchAnalysis( } @Nullable + @RequiredReadAction public static HighlightInfo checkNotAStatement(@Nonnull PsiStatement statement) { if (!PsiUtil.isStatement(statement) && !PsiUtilCore.hasErrorElementChild(statement)) { boolean isDeclarationNotAllowed = false; @@ -1746,14 +1775,17 @@ public static HighlightInfo checkNotAStatement(@Nonnull PsiStatement statement) isDeclarationNotAllowed = parent instanceof PsiIfStatement || parent instanceof PsiLoopStatement; } - String description = JavaErrorBundle.message(isDeclarationNotAllowed ? "declaration.not.allowed" : "not.a.statement"); - HighlightInfo error = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(description).create(); - if (statement instanceof PsiExpressionStatement) { + String description = isDeclarationNotAllowed + ? JavaErrorBundle.message("declaration.not.allowed") + : JavaErrorBundle.message("not.a.statement"); + HighlightInfo error = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(statement) + .descriptionAndTooltip(description) + .create(); + if (statement instanceof PsiExpressionStatement expressionStmt) { QuickFixAction.registerQuickFixAction( error, - QuickFixFactory.getInstance() - .createDeleteSideEffectAwareFix((PsiExpressionStatement)statement) + QuickFixFactory.getInstance().createDeleteSideEffectAwareFix(expressionStmt) ); } return error; @@ -1762,6 +1794,7 @@ public static HighlightInfo checkNotAStatement(@Nonnull PsiStatement statement) } @Nullable + @RequiredReadAction public static HighlightInfo checkSwitchBlockStatements( @Nonnull PsiSwitchBlock switchBlock, @Nonnull LanguageLevel languageLevel, @@ -1771,8 +1804,10 @@ public static HighlightInfo checkSwitchBlockStatements( if (body != null) { PsiElement first = PsiTreeUtil.skipWhitespacesAndCommentsForward(body.getLBrace()); if (first != null && !(first instanceof PsiSwitchLabelStatementBase) && !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(); } PsiElement element = first; @@ -1795,16 +1830,16 @@ public static HighlightInfo checkSwitchBlockStatements( } enhancedLabels = true; } - else if (element instanceof PsiStatement) { + else if (element instanceof PsiStatement statement) { if (enhancedLabels) { - alien = (PsiStatement)element; + alien = statement; break; } classicLabels = true; } - if (!levelChecked && element instanceof PsiSwitchLabelStatementBase) { - PsiExpressionList values = ((PsiSwitchLabelStatementBase)element).getCaseValues(); + if (!levelChecked && element instanceof PsiSwitchLabelStatementBase switchLabelStatementBase) { + PsiExpressionList values = switchLabelStatementBase.getCaseValues(); if (values != null && values.getExpressionCount() > 1) { HighlightInfo info = checkFeature(values, JavaFeature.ENHANCED_SWITCH, languageLevel, file); if (info != null) { @@ -1820,17 +1855,22 @@ else if (element instanceof PsiStatement) { if (enhancedLabels && !(alien instanceof PsiSwitchLabelStatementBase)) { PsiSwitchLabeledRuleStatement previousRule = PsiTreeUtil.getPrevSiblingOfType(alien, PsiSwitchLabeledRuleStatement.class); - String description = JavaErrorBundle.message("statement.must.be.prepended.with.case.label"); - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(alien).descriptionAndTooltip(description).create(); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(alien) + .descriptionAndTooltip(JavaErrorLocalize.statementMustBePrependedWithCaseLabel()) + .create(); if (previousRule != null) { - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance() - .createWrapSwitchRuleStatementsIntoBlockFix(previousRule)); + QuickFixAction.registerQuickFixAction( + info, + QuickFixFactory.getInstance().createWrapSwitchRuleStatementsIntoBlockFix(previousRule) + ); } return info; } - String description = JavaErrorBundle.message("different.case.kinds.in.switch"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(alien).descriptionAndTooltip(description).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(alien) + .descriptionAndTooltip(JavaErrorBundle.message("different.case.kinds.in.switch")) + .create(); } } @@ -1838,6 +1878,7 @@ else if (element instanceof PsiStatement) { } @Nullable + @RequiredReadAction public static HighlightInfo checkSwitchSelectorType(@Nonnull PsiSwitchBlock switchBlock, @Nonnull LanguageLevel level) { PsiExpression expression = switchBlock.getExpression(); if (expression == null) { @@ -1863,14 +1904,17 @@ public static HighlightInfo checkSwitchSelectorType(@Nonnull PsiSwitchBlock swit if (kind == null || requiredLevel != null && !level.isAtLeast(requiredLevel)) { boolean is7 = level.isAtLeast(LanguageLevel.JDK_1_7); - String expected = JavaErrorBundle.message(is7 ? "valid.switch.1_7.selector.types" : "valid.switch.selector.types"); - String message = JavaErrorBundle.message("incompatible.types", expected, JavaHighlightUtil.formatType(type)); - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create(); - if (switchBlock instanceof PsiSwitchStatement) { + LocalizeValue expected = is7 + ? JavaErrorLocalize.validSwitch1_7SelectorTypes() + : JavaErrorLocalize.validSwitchSelectorTypes(); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.incompatibleTypes(expected, JavaHighlightUtil.formatType(type))) + .create(); + if (switchBlock instanceof PsiSwitchStatement switchStmt) { QuickFixAction.registerQuickFixAction( info, - QuickFixFactory.getInstance().createConvertSwitchToIfIntention((PsiSwitchStatement)switchBlock) + QuickFixFactory.getInstance().createConvertSwitchToIfIntention(switchStmt) ); } if (PsiType.LONG.equals(type) || PsiType.FLOAT.equals(type) || PsiType.DOUBLE.equals(type)) { @@ -1889,8 +1933,10 @@ public static HighlightInfo checkSwitchSelectorType(@Nonnull PsiSwitchBlock swit PsiClass member = PsiUtil.resolveClassInClassTypeOnly(type); if (member != null && !PsiUtil.isAccessible(member.getProject(), member, expression, null)) { String className = PsiFormatUtil.formatClass(member, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_FQ_NAME); - String message = JavaErrorBundle.message("inaccessible.type", className); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorLocalize.inaccessibleType(className).get()) + .create(); } return null; @@ -1921,6 +1967,7 @@ private static SelectorKind getSwitchSelectorKind(@Nonnull PsiType type) { } @Nullable + @RequiredReadAction public static HighlightInfo checkPolyadicOperatorApplicable(@Nonnull PsiPolyadicExpression expression) { PsiExpression[] operands = expression.getOperands(); @@ -1931,13 +1978,15 @@ public static HighlightInfo checkPolyadicOperatorApplicable(@Nonnull PsiPolyadic PsiType rType = operand.getType(); if (!TypeConversionUtil.isBinaryOperatorApplicable(operationSign, lType, rType, false)) { PsiJavaToken token = expression.getTokenBeforeOperand(operand); - String message = JavaErrorBundle.message( - "binary.operator.not.applicable", + LocalizeValue message = JavaErrorLocalize.binaryOperatorNotApplicable( token.getText(), JavaHighlightUtil.formatType(lType), JavaHighlightUtil.formatType(rType) ); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(message) + .create(); } lType = TypeConversionUtil.calcTypeForBinaryExpression(lType, rType, operationSign, true); } @@ -1945,23 +1994,24 @@ public static HighlightInfo checkPolyadicOperatorApplicable(@Nonnull PsiPolyadic return null; } - @Nullable + @RequiredReadAction public static HighlightInfo checkUnaryOperatorApplicable(@Nullable PsiJavaToken token, @Nullable PsiExpression expression) { if (token != null && expression != null && !TypeConversionUtil.isUnaryOperatorApplicable(token, expression)) { PsiType type = expression.getType(); if (type == null) { return null; } - String message = JavaErrorBundle.message("unary.operator.not.applicable", token.getText(), JavaHighlightUtil.formatType(type)); PsiElement parentExpr = token.getParent(); - HighlightInfo highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parentExpr).descriptionAndTooltip(message).create(); - if (parentExpr instanceof PsiPrefixExpression && token.getTokenType() == JavaTokenType.EXCL) { + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(parentExpr) + .descriptionAndTooltip(JavaErrorLocalize.unaryOperatorNotApplicable(token.getText(), JavaHighlightUtil.formatType(type))) + .create(); + if (parentExpr instanceof PsiPrefixExpression prefixExpr && token.getTokenType() == JavaTokenType.EXCL) { QuickFixAction.registerQuickFixAction( highlightInfo, - QuickFixFactory.getInstance().createNegationBroadScopeFix((PsiPrefixExpression)parentExpr) + QuickFixFactory.getInstance().createNegationBroadScopeFix(prefixExpr) ); } return highlightInfo; @@ -1970,33 +2020,37 @@ public static HighlightInfo checkUnaryOperatorApplicable(@Nullable PsiJavaToken } @Nullable + @RequiredReadAction public static HighlightInfo checkThisOrSuperExpressionInIllegalContext( @Nonnull PsiExpression expr, @Nullable PsiJavaCodeReferenceElement qualifier, @Nonnull LanguageLevel languageLevel ) { - if (expr instanceof PsiSuperExpression) { - PsiElement parent = expr.getParent(); - if (!(parent instanceof PsiReferenceExpression)) { - // like in 'Object o = super;' - 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(); - } + if (expr instanceof PsiSuperExpression && !(expr.getParent() instanceof PsiReferenceExpression)) { + // like in 'Object o = super;' + int o = expr.getTextRange().getEndOffset(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(o, o + 1) + .descriptionAndTooltip(JavaErrorLocalize.dotExpectedAfterSuperOrThis()) + .create(); } - PsiClass aClass; + PsiClass aClass = null; if (qualifier != null) { PsiElement resolved = qualifier.advancedResolve(true).getElement(); - if (resolved != null && !(resolved instanceof PsiClass)) { - String description = JavaErrorBundle.message("class.expected"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(qualifier).descriptionAndTooltip(description).create(); + if (resolved instanceof PsiClass resolvedClass) { + aClass = resolvedClass; + } + else if (resolved != null) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(qualifier) + .descriptionAndTooltip(JavaErrorLocalize.classExpected()) + .create(); } - aClass = (PsiClass)resolved; } else { aClass = PsiTreeUtil.getParentOfType(expr, PsiClass.class); - if (aClass instanceof PsiAnonymousClass && PsiTreeUtil.isAncestor(((PsiAnonymousClass)aClass).getArgumentList(), expr, false)) { + if (aClass instanceof PsiAnonymousClass anonymousClass && PsiTreeUtil.isAncestor(anonymousClass.getArgumentList(), expr, false)) { aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class, true); } } @@ -2023,36 +2077,35 @@ public static HighlightInfo checkThisOrSuperExpressionInIllegalContext( } } - if (qualifier != null && aClass.isInterface() && expr instanceof PsiSuperExpression && languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { + if (qualifier != null && aClass.isInterface() && expr instanceof PsiSuperExpression + && languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { //15.12.1 for method invocation expressions; 15.13 for method references //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. PsiClass classT = PsiTreeUtil.getParentOfType(expr, PsiClass.class); if (classT != null) { - PsiElement parent = expr.getParent(); - PsiElement resolved = parent instanceof PsiReferenceExpression ? ((PsiReferenceExpression)parent).resolve() : null; + PsiElement resolved = expr.getParent() instanceof PsiReferenceExpression refExpr ? refExpr.resolve() : null; PsiClass containingClass = - ObjectUtil.notNull(resolved instanceof PsiMethod ? ((PsiMethod)resolved).getContainingClass() : null, aClass); + ObjectUtil.notNull(resolved instanceof PsiMethod method ? method.getContainingClass() : null, aClass); for (PsiClass superClass : classT.getSupers()) { if (superClass.isInheritor(containingClass, true)) { String cause = null; if (superClass.isInheritor(aClass, true) && superClass.isInterface()) { cause = "redundant interface " + format(containingClass) + " is extended by "; } - else if (resolved instanceof PsiMethod - && MethodSignatureUtil.findMethodBySuperMethod(superClass, (PsiMethod)resolved, true) != resolved) { - cause = "method " + ((PsiMethod)resolved).getName() + " is overridden in "; + else if (resolved instanceof PsiMethod method + && MethodSignatureUtil.findMethodBySuperMethod(superClass, method, true) != method) { + cause = "method " + method.getName() + " is overridden in "; } if (cause != null) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(qualifier) - .descriptionAndTooltip(JavaErrorBundle.message( - "bad.qualifier.in.super.method.reference", - cause + formatClass(superClass) - )) + .descriptionAndTooltip( + JavaErrorLocalize.badQualifierInSuperMethodReference(cause + formatClass(superClass)) + ) .create(); } } @@ -2061,7 +2114,7 @@ else if (resolved instanceof PsiMethod if (!classT.isInheritor(aClass, false)) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(qualifier) - .descriptionAndTooltip(JavaErrorBundle.message("no.enclosing.instance.in.scope", format(aClass))) + .descriptionAndTooltip(JavaErrorLocalize.noEnclosingInstanceInScope(format(aClass))) .create(); } } @@ -2074,12 +2127,9 @@ else if (resolved instanceof PsiMethod return thisNotFoundInInterfaceInfo(expr); } - if (aClass instanceof PsiAnonymousClass && PsiTreeUtil.isAncestor( - ((PsiAnonymousClass)aClass).getArgumentList(), - expr, - true - )) { - PsiClass parentClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class, true); + if (aClass instanceof PsiAnonymousClass anonymousClass + && PsiTreeUtil.isAncestor(anonymousClass.getArgumentList(), expr, true)) { + PsiClass parentClass = PsiTreeUtil.getParentOfType(anonymousClass, PsiClass.class, true); if (parentClass != null && parentClass.isInterface()) { return thisNotFoundInInterfaceInfo(expr); } @@ -2089,17 +2139,19 @@ else if (resolved instanceof PsiMethod return null; } + @RequiredReadAction public static HighlightInfo checkUnqualifiedSuperInDefaultMethod( @Nonnull LanguageLevel languageLevel, @Nonnull PsiReferenceExpression expr, PsiExpression qualifier ) { - if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && qualifier instanceof PsiSuperExpression) { + if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && qualifier instanceof PsiSuperExpression superExpr) { 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 = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expr).descriptionAndTooltip(description).create(); + if (method != null && method.hasModifierProperty(PsiModifier.DEFAULT) && superExpr.getQualifier() == null) { + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expr) + .descriptionAndTooltip(JavaErrorLocalize.unqualifiedSuperDisallowed()) + .create(); QualifySuperArgumentFix.registerQuickFixAction((PsiSuperExpression)qualifier, info); return info; } @@ -2114,10 +2166,11 @@ private static boolean isInsideDefaultMethod(PsiMethod method, PsiClass aClass) return method != null && method.hasModifierProperty(PsiModifier.DEFAULT); } + @RequiredReadAction private static HighlightInfo thisNotFoundInInterfaceInfo(@Nonnull PsiExpression expr) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expr) - .descriptionAndTooltip("Cannot find symbol variable this") + .descriptionAndTooltip(LocalizeValue.localizeTODO("Cannot find symbol variable this")) .create(); } @@ -2131,10 +2184,10 @@ private static boolean resolvesToImmediateSuperInterface( return false; } PsiType superType = expr.getType(); - if (!(superType instanceof PsiClassType)) { + if (!(superType instanceof PsiClassType classType)) { return false; } - PsiClass superClass = ((PsiClassType)superType).resolve(); + PsiClass superClass = classType.resolve(); return superClass != null && aClass.equals(superClass) && PsiUtil.getEnclosingStaticElement(expr, PsiTreeUtil.getParentOfType(expr, PsiClass.class)) == null; } @@ -2146,16 +2199,17 @@ public static LocalizeValue buildProblemWithStaticDescription(@Nonnull PsiElemen return JavaErrorLocalize.nonStaticSymbolReferencedFromStaticContext(type, name); } + @RequiredReadAction public static void registerStaticProblemQuickFixAction( @Nonnull PsiElement refElement, HighlightInfo errorResult, @Nonnull PsiJavaCodeReferenceElement place ) { - if (refElement instanceof PsiModifierListOwner) { + if (refElement instanceof PsiModifierListOwner modifierListOwner) { QuickFixAction.registerQuickFixAction( errorResult, QuickFixFactory.getInstance().createModifierListFix( - (PsiModifierListOwner)refElement, + modifierListOwner, PsiModifier.STATIC, true, false @@ -2171,10 +2225,10 @@ public static void registerStaticProblemQuickFixAction( .createModifierListFix(staticParent, PsiModifier.STATIC, false, false) ); } - if (place instanceof PsiReferenceExpression && refElement instanceof PsiField) { + if (place instanceof PsiReferenceExpression placeRefExpr && refElement instanceof PsiField) { QuickFixAction.registerQuickFixAction( errorResult, - QuickFixFactory.getInstance().createCreateFieldFromUsageFix((PsiReferenceExpression)place) + QuickFixFactory.getInstance().createCreateFieldFromUsageFix(placeRefExpr) ); } } @@ -2200,11 +2254,13 @@ private static boolean isInstanceReference(@Nonnull PsiJavaCodeReferenceElement } @Nonnull + @RequiredReadAction public static LocalizeValue buildProblemWithAccessDescription(@Nonnull PsiElement reference, @Nonnull JavaResolveResult result) { return buildProblemWithAccessDescription(reference, result, ObjectUtil.notNull(result.getElement())); } @Nonnull + @RequiredReadAction private static LocalizeValue buildProblemWithAccessDescription( @Nonnull PsiElement reference, @Nonnull JavaResolveResult result, @@ -2249,16 +2305,16 @@ private static PsiElement getContainer(PsiModifierListOwner refElement) { return refElement.getParent(); } - private static String getContainerName(PsiModifierListOwner refElement, final PsiSubstitutor substitutor) { - final PsiElement container = getContainer(refElement); + private static String getContainerName(PsiModifierListOwner refElement, PsiSubstitutor substitutor) { + PsiElement container = getContainer(refElement); return container == null ? "?" : HighlightMessageUtil.getSymbolName(container, substitutor); } @Nullable @RequiredReadAction public static HighlightInfo checkValidArrayAccessExpression(@Nonnull PsiArrayAccessExpression arrayAccessExpression) { - final PsiExpression arrayExpression = arrayAccessExpression.getArrayExpression(); - final PsiType arrayExpressionType = arrayExpression.getType(); + PsiExpression arrayExpression = arrayAccessExpression.getArrayExpression(); + PsiType arrayExpressionType = arrayExpression.getType(); if (arrayExpressionType != null && !(arrayExpressionType instanceof PsiArrayType)) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) @@ -2268,7 +2324,7 @@ public static HighlightInfo checkValidArrayAccessExpression(@Nonnull PsiArrayAcc .create(); } - final PsiExpression indexExpression = arrayAccessExpression.getIndexExpression(); + PsiExpression indexExpression = arrayAccessExpression.getIndexExpression(); return indexExpression != null ? checkAssignability(PsiType.INT, indexExpression.getType(), indexExpression, indexExpression) : null; @@ -2276,15 +2332,17 @@ public static HighlightInfo checkValidArrayAccessExpression(@Nonnull PsiArrayAcc @Nullable - public static HighlightInfo checkCatchParameterIsThrowable(@Nonnull final PsiParameter parameter) { + @RequiredReadAction + public static HighlightInfo checkCatchParameterIsThrowable(@Nonnull PsiParameter parameter) { if (parameter.getDeclarationScope() instanceof PsiCatchSection) { - final PsiType type = parameter.getType(); + PsiType type = parameter.getType(); return checkMustBeThrowable(type, parameter, true); } return null; } @Nullable + @RequiredReadAction public static HighlightInfo checkTryResourceIsAutoCloseable(@Nonnull PsiResourceListElement resource) { PsiType type = resource.getType(); if (type == null) { @@ -2327,38 +2385,42 @@ public static HighlightInfo checkResourceVariableIsFinal(@Nonnull PsiResourceExp } } - String text = JavaErrorBundle.message("resource.variable.must.be.final"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(text).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorBundle.message("resource.variable.must.be.final")) + .create(); } - String text = JavaErrorBundle.message("declaration.or.variable.expected"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(text).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(expression) + .descriptionAndTooltip(JavaErrorBundle.message("declaration.or.variable.expected")) + .create(); } @Nonnull - public static Collection checkArrayInitializer(final PsiExpression initializer, PsiType type) { - if (!(initializer instanceof PsiArrayInitializerExpression)) { + @RequiredReadAction + public static Collection checkArrayInitializer(PsiExpression initializer, PsiType type) { + if (!(initializer instanceof PsiArrayInitializerExpression arrayInitializer)) { return Collections.emptyList(); } - if (!(type instanceof PsiArrayType)) { + if (!(type instanceof PsiArrayType arrayType)) { return Collections.emptyList(); } - final PsiType componentType = ((PsiArrayType)type).getComponentType(); - final PsiArrayInitializerExpression arrayInitializer = (PsiArrayInitializerExpression)initializer; + PsiType componentType = arrayType.getComponentType(); boolean arrayTypeFixChecked = false; VariableArrayTypeFix fix = null; - final Collection result = new ArrayList<>(); - final PsiExpression[] initializers = arrayInitializer.getInitializers(); + Collection result = new ArrayList<>(); + PsiExpression[] initializers = arrayInitializer.getInitializers(); for (PsiExpression expression : initializers) { - final HighlightInfo info = checkArrayInitializerCompatibleTypes(expression, componentType); + HighlightInfo info = checkArrayInitializerCompatibleTypes(expression, componentType); if (info != null) { result.add(info); if (!arrayTypeFixChecked) { - final PsiType checkResult = JavaHighlightUtil.sameType(initializers); + PsiType checkResult = JavaHighlightUtil.sameType(initializers); fix = checkResult != null ? VariableArrayTypeFix.createFix(arrayInitializer, checkResult) : null; arrayTypeFixChecked = true; } @@ -2372,11 +2434,13 @@ public static Collection checkArrayInitializer(final PsiExpressio @Nullable @RequiredReadAction - private static HighlightInfo checkArrayInitializerCompatibleTypes(@Nonnull PsiExpression initializer, final PsiType componentType) { + private static HighlightInfo checkArrayInitializerCompatibleTypes(@Nonnull PsiExpression initializer, PsiType componentType) { PsiType initializerType = initializer.getType(); if (initializerType == null) { - String description = JavaErrorBundle.message("illegal.initializer", JavaHighlightUtil.formatType(componentType)); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(initializer).descriptionAndTooltip(description).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(initializer) + .descriptionAndTooltip(JavaErrorBundle.message("illegal.initializer", JavaHighlightUtil.formatType(componentType))) + .create(); } PsiExpression expression = initializer instanceof PsiArrayInitializerExpression ? null : initializer; return checkAssignability(componentType, initializerType, expression, initializer); @@ -2421,8 +2485,7 @@ public static HighlightInfo checkArrayInitializerApplicable(@Nonnull PsiArrayIni * 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; + if (parent instanceof PsiVariable variable) { if (variable.getType() instanceof PsiArrayType) { return null; } @@ -2431,16 +2494,13 @@ else if (parent instanceof PsiNewExpression || parent instanceof PsiArrayInitial return null; } - String description = JavaErrorLocalize.arrayInitializerNotAllowed().get(); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) - .descriptionAndTooltip(description) + .descriptionAndTooltip(JavaErrorLocalize.arrayInitializerNotAllowed()) + .registerFix(QuickFixFactory.getInstance().createAddNewArrayExpressionFix(expression), null, null, null, null) .create(); - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createAddNewArrayExpressionFix(expression)); - return info; } - @Nullable @RequiredReadAction public static HighlightInfo checkCaseStatement(@Nonnull PsiSwitchLabelStatementBase statement) { @@ -2471,10 +2531,9 @@ public static Collection checkSwitchLabelValues(@Nonnull PsiSwitc boolean hasDefaultCase = false; for (PsiStatement st : body.getStatements()) { - if (!(st instanceof PsiSwitchLabelStatementBase)) { + if (!(st instanceof PsiSwitchLabelStatementBase labelStatement)) { continue; } - PsiSwitchLabelStatementBase labelStatement = (PsiSwitchLabelStatementBase)st; boolean defaultCase = labelStatement.isDefaultCase(); if (defaultCase) { @@ -2560,12 +2619,13 @@ public static Collection checkSwitchLabelValues(@Nonnull PsiSwitc } } if (!exhaustive) { - PsiElement range = ObjectUtil.notNull(selectorExpression, switchBlock); 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(); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(ObjectUtil.notNull(selectorExpression, switchBlock)) + .descriptionAndTooltip(message) + .create(); if (!missingConstants.isEmpty()) { QuickFixAction.registerQuickFixAction( info, @@ -2595,7 +2655,7 @@ public static HighlightInfo checkIllegalForwardReferenceToField( return null; } String description = isIllegalForwardReference - ? JavaErrorBundle.message("illegal.forward.reference") + ? JavaErrorLocalize.illegalForwardReference().get() : JavaErrorBundle.message("illegal.self.reference"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) @@ -2731,8 +2791,7 @@ public static HighlightInfo checkIllegalVoidType(@Nonnull PsiKeyword type) { } } - if (typeOwner instanceof PsiMethod) { - PsiMethod method = (PsiMethod)typeOwner; + if (typeOwner instanceof PsiMethod method) { if (method.getReturnTypeElement() == parent && PsiType.VOID.equals(method.getReturnType())) { return null; } @@ -2807,8 +2866,9 @@ else if (resolved instanceof PsiMethod method) { if (method.isStatic()) { return null; } - PsiElement nameElement = - expression instanceof PsiThisExpression ? expression : ((PsiJavaCodeReferenceElement)expression).getReferenceNameElement(); + PsiElement nameElement = expression instanceof PsiThisExpression + ? expression + : ((PsiJavaCodeReferenceElement)expression).getReferenceNameElement(); String name = nameElement == null ? null : nameElement.getText(); if (isSuperCall) { if (referencedClass == null) { @@ -2858,11 +2918,10 @@ else if (resolved instanceof PsiClass aClass) { return null; } } - else if (expression instanceof PsiThisExpression) { - PsiThisExpression thisExpression = (PsiThisExpression)expression; - type = thisExpression.getType(); + else if (expression instanceof PsiThisExpression thisExpr) { + type = thisExpr.getType(); referencedClass = PsiUtil.resolveClassInType(type); - if (thisExpression.getQualifier() != null) { + if (thisExpr.getQualifier() != null) { resolvedName = referencedClass == null ? null : PsiFormatUtil.formatClass(referencedClass, PsiFormatUtilBase.SHOW_NAME) + ".this"; } @@ -2873,6 +2932,7 @@ else if (expression instanceof PsiThisExpression) { else { return null; } + if (referencedClass == null) { return null; } @@ -2882,9 +2942,9 @@ else if (expression instanceof PsiThisExpression) { @Nullable @RequiredReadAction private static HighlightInfo checkReferenceToOurInstanceInsideThisOrSuper( - @Nonnull final PsiElement expression, + @Nonnull PsiElement expression, @Nonnull PsiClass referencedClass, - final String resolvedName, + String resolvedName, @Nonnull PsiFile containingFile ) { if (PsiTreeUtil.getParentOfType(expression, PsiReferenceParameterList.class) != null) { @@ -2894,10 +2954,10 @@ private static HighlightInfo checkReferenceToOurInstanceInsideThisOrSuper( while (element != null) { // check if expression inside super()/this() call if (RefactoringChangeUtil.isSuperOrThisMethodCall(element)) { - PsiElement parentClass = new PsiMatcherImpl(element).parent(PsiMatchers.hasClass(PsiExpressionStatement.class)) + PsiElement parentClass = new PsiMatcherImpl(element) + .parent(PsiMatchers.hasClass(PsiExpressionStatement.class)) .parent(PsiMatchers.hasClass(PsiCodeBlock.class)) - .parent(PsiMatchers - .hasClass(PsiMethod.class)) + .parent(PsiMatchers.hasClass(PsiMethod.class)) .dot(JavaMatchers.isConstructor(true)) .parent(PsiMatchers.hasClass(PsiClass.class)) .getElement(); @@ -2915,8 +2975,8 @@ private static HighlightInfo checkReferenceToOurInstanceInsideThisOrSuper( return null; } // and point to our instance - if (expression instanceof PsiReferenceExpression - && !thisOrSuperReference(((PsiReferenceExpression)expression).getQualifierExpression(), aClass)) { + if (expression instanceof PsiReferenceExpression refExpr + && !thisOrSuperReference(refExpr.getQualifierExpression(), aClass)) { return null; } @@ -2931,12 +2991,12 @@ private static HighlightInfo checkReferenceToOurInstanceInsideThisOrSuper( return null; } - final HighlightInfo highlightInfo = createMemberReferencedError(resolvedName, expression.getTextRange()); + HighlightInfo highlightInfo = createMemberReferencedError(resolvedName, expression.getTextRange()); if (expression instanceof PsiReferenceExpression refExpr && PsiUtil.isInnerClass(aClass)) { - final String referenceName = refExpr.getReferenceName(); - final PsiClass containingClass = aClass.getContainingClass(); + String referenceName = refExpr.getReferenceName(); + PsiClass containingClass = aClass.getContainingClass(); LOG.assertTrue(containingClass != null); - final PsiField fieldInContainingClass = containingClass.findFieldByName(referenceName, true); + PsiField fieldInContainingClass = containingClass.findFieldByName(referenceName, true); if (fieldInContainingClass != null && refExpr.getQualifierExpression() == null) { QuickFixAction.registerQuickFixAction(highlightInfo, new QualifyWithThisFix(containingClass, refExpr)); } @@ -2945,11 +3005,11 @@ private static HighlightInfo checkReferenceToOurInstanceInsideThisOrSuper( return highlightInfo; } - if (element instanceof PsiReferenceExpression) { + if (element instanceof PsiReferenceExpression refExpr) { PsiElement resolve; - if (element instanceof PsiReferenceExpressionImpl refExpr) { + if (element instanceof PsiReferenceExpressionImpl refExprImpl) { JavaResolveResult[] results = JavaResolveUtil.resolveWithContainingFile( - refExpr, + refExprImpl, PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE, true, false, @@ -2958,8 +3018,9 @@ private static HighlightInfo checkReferenceToOurInstanceInsideThisOrSuper( resolve = results.length == 1 ? results[0].getElement() : null; } else { - resolve = ((PsiReferenceExpression)element).resolve(); + resolve = refExpr.resolve(); } + if (resolve instanceof PsiField field && field.isStatic()) { return null; } @@ -2981,6 +3042,7 @@ private static HighlightInfo createMemberReferencedError(String resolvedName, @N } @Nullable + @RequiredReadAction public static HighlightInfo checkImplicitThisReferenceBeforeSuper(@Nonnull PsiClass aClass, @Nonnull JavaSdkVersion javaSdkVersion) { if (javaSdkVersion.isAtLeast(JavaSdkVersion.JDK_1_7)) { return null; @@ -3013,20 +3075,20 @@ public static HighlightInfo checkImplicitThisReferenceBeforeSuper(@Nonnull PsiCl return null; } - private static boolean isSuperCalledInConstructor(@Nonnull final PsiMethod constructor) { - final PsiCodeBlock body = constructor.getBody(); + private static boolean isSuperCalledInConstructor(@Nonnull PsiMethod constructor) { + PsiCodeBlock body = constructor.getBody(); if (body == null) { return false; } - final PsiStatement[] statements = body.getStatements(); + PsiStatement[] statements = body.getStatements(); if (statements.length == 0) { return false; } - final PsiStatement statement = statements[0]; - final PsiElement element = new PsiMatcherImpl(statement).dot(PsiMatchers.hasClass(PsiExpressionStatement.class)) + PsiStatement statement = statements[0]; + PsiElement element = new PsiMatcherImpl(statement) + .dot(PsiMatchers.hasClass(PsiExpressionStatement.class)) .firstChild(PsiMatchers.hasClass(PsiMethodCallExpression.class)) - .firstChild - (PsiMatchers.hasClass(PsiReferenceExpression.class)) + .firstChild(PsiMatchers.hasClass(PsiReferenceExpression.class)) .firstChild(PsiMatchers.hasClass(PsiKeyword.class)) .dot(PsiMatchers.hasText(PsiKeyword.SUPER)) .getElement(); @@ -3108,25 +3170,25 @@ public static HighlightInfo checkUnclosedComment(@Nonnull PsiComment comment) { @Nonnull @RequiredReadAction - public static Collection checkCatchTypeIsDisjoint(@Nonnull final PsiParameter parameter) { + public static Collection checkCatchTypeIsDisjoint(@Nonnull PsiParameter parameter) { if (!(parameter.getType() instanceof PsiDisjunctionType)) { return Collections.emptyList(); } - final Collection result = new ArrayList<>(); - final List typeElements = PsiUtil.getParameterTypeElements(parameter); + Collection result = new ArrayList<>(); + List typeElements = PsiUtil.getParameterTypeElements(parameter); for (int i = 0, size = typeElements.size(); i < size; i++) { - final PsiClass class1 = PsiUtil.resolveClassInClassTypeOnly(typeElements.get(i).getType()); + PsiClass class1 = PsiUtil.resolveClassInClassTypeOnly(typeElements.get(i).getType()); if (class1 == null) { continue; } for (int j = i + 1; j < size; j++) { - final PsiClass class2 = PsiUtil.resolveClassInClassTypeOnly(typeElements.get(j).getType()); + PsiClass class2 = PsiUtil.resolveClassInClassTypeOnly(typeElements.get(j).getType()); if (class2 == null) { continue; } - final boolean sub = InheritanceUtil.isInheritorOrSelf(class1, class2, true); - final boolean sup = InheritanceUtil.isInheritorOrSelf(class2, class1, true); + boolean sub = InheritanceUtil.isInheritorOrSelf(class1, class2, true); + boolean sup = InheritanceUtil.isInheritorOrSelf(class2, class1, true); if (sub || sup) { String name1 = PsiFormatUtil.formatClass(class1, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_FQ_NAME); String name2 = PsiFormatUtil.formatClass(class2, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_FQ_NAME); @@ -3147,47 +3209,51 @@ public static Collection checkCatchTypeIsDisjoint(@Nonnull final @Nonnull @RequiredReadAction - public static Collection checkExceptionAlreadyCaught(@Nonnull final PsiParameter parameter) { - final PsiElement scope = parameter.getDeclarationScope(); - if (!(scope instanceof PsiCatchSection)) { + public static Collection checkExceptionAlreadyCaught(@Nonnull PsiParameter parameter) { + PsiElement scope = parameter.getDeclarationScope(); + if (!(scope instanceof PsiCatchSection catchSection)) { return Collections.emptyList(); } - final PsiCatchSection catchSection = (PsiCatchSection)scope; - final PsiCatchSection[] allCatchSections = catchSection.getTryStatement().getCatchSections(); - final int startFrom = ArrayUtil.find(allCatchSections, catchSection) - 1; + PsiCatchSection[] allCatchSections = catchSection.getTryStatement().getCatchSections(); + int startFrom = ArrayUtil.find(allCatchSections, catchSection) - 1; if (startFrom < 0) { return Collections.emptyList(); } - final List typeElements = PsiUtil.getParameterTypeElements(parameter); - final boolean isInMultiCatch = typeElements.size() > 1; - final Collection result = new ArrayList<>(); + List typeElements = PsiUtil.getParameterTypeElements(parameter); + boolean isInMultiCatch = typeElements.size() > 1; + Collection result = new ArrayList<>(); for (PsiTypeElement typeElement : typeElements) { - final PsiClass catchClass = PsiUtil.resolveClassInClassTypeOnly(typeElement.getType()); + PsiClass catchClass = PsiUtil.resolveClassInClassTypeOnly(typeElement.getType()); if (catchClass == null) { continue; } for (int i = startFrom; i >= 0; i--) { - final PsiCatchSection upperCatchSection = allCatchSections[i]; - final PsiType upperCatchType = upperCatchSection.getCatchType(); + PsiCatchSection upperCatchSection = allCatchSections[i]; + PsiType upperCatchType = upperCatchSection.getCatchType(); - final boolean highlight = upperCatchType instanceof PsiDisjunctionType disjunctionType + boolean highlight = upperCatchType instanceof PsiDisjunctionType disjunctionType ? checkMultipleTypes(catchClass, disjunctionType.getDisjunctions()) : checkSingleType(catchClass, upperCatchType); if (highlight) { - final String className = + String className = PsiFormatUtil.formatClass(catchClass, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_FQ_NAME); - final HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(typeElement) .descriptionAndTooltip(JavaErrorLocalize.exceptionAlreadyCaught(className)) + .registerFix( + QuickFixFactory.getInstance().createMoveCatchUpFix(catchSection, upperCatchSection), + null, + null, + null, + null + ) .create(); result.add(highlightInfo); - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixFactory.getInstance() - .createMoveCatchUpFix(catchSection, upperCatchSection)); if (isInMultiCatch) { QuickFixAction.registerQuickFixAction( highlightInfo, @@ -3204,7 +3270,7 @@ public static Collection checkExceptionAlreadyCaught(@Nonnull fin return result; } - private static boolean checkMultipleTypes(final PsiClass catchClass, @Nonnull final List upperCatchTypes) { + private static boolean checkMultipleTypes(PsiClass catchClass, @Nonnull List upperCatchTypes) { for (int i = upperCatchTypes.size() - 1; i >= 0; i--) { if (checkSingleType(catchClass, upperCatchTypes.get(i))) { return true; @@ -3213,8 +3279,8 @@ private static boolean checkMultipleTypes(final PsiClass catchClass, @Nonnull fi return false; } - private static boolean checkSingleType(final PsiClass catchClass, final PsiType upperCatchType) { - final PsiClass upperCatchClass = PsiUtil.resolveClassInType(upperCatchType); + private static boolean checkSingleType(PsiClass catchClass, PsiType upperCatchType) { + PsiClass upperCatchClass = PsiUtil.resolveClassInType(upperCatchType); return upperCatchClass != null && InheritanceUtil.isInheritorOrSelf(catchClass, upperCatchClass, true); } @@ -3251,10 +3317,9 @@ public static HighlightInfo checkAssertOperatorTypes(@Nonnull PsiExpression expr if (type == null) { return null; } - if (!(expression.getParent() instanceof PsiAssertStatement)) { + if (!(expression.getParent() instanceof PsiAssertStatement assertStatement)) { return null; } - PsiAssertStatement assertStatement = (PsiAssertStatement)expression.getParent(); 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); @@ -3295,7 +3360,7 @@ public static HighlightInfo checkSynchronizedExpressionType( @Nullable @RequiredReadAction - public static HighlightInfo checkConditionalExpressionBranchTypesMatch(@Nonnull final PsiExpression expression, PsiType type) { + public static HighlightInfo checkConditionalExpressionBranchTypesMatch(@Nonnull PsiExpression expression, PsiType type) { PsiElement parent = expression.getParent(); if (!(parent instanceof PsiConditionalExpression conditionalExpr)) { return null; @@ -3304,7 +3369,7 @@ public static HighlightInfo checkConditionalExpressionBranchTypesMatch(@Nonnull if (conditionalExpr.getElseExpression() != expression) { return null; } - final PsiExpression thenExpression = conditionalExpr.getThenExpression(); + PsiExpression thenExpression = conditionalExpr.getThenExpression(); assert thenExpression != null; PsiType thenType = thenExpression.getType(); if (thenType == null || type == null) { @@ -3323,21 +3388,21 @@ public static HighlightInfo checkConditionalExpressionBranchTypesMatch(@Nonnull @SuppressWarnings("StringContatenationInLoop") public static HighlightInfo createIncompatibleTypeHighlightInfo( - final PsiType lType, - final PsiType rType, - @Nonnull final TextRange textRange, + PsiType lType, + PsiType rType, + @Nonnull TextRange textRange, int navigationShift ) { PsiType lType1 = lType; PsiType rType1 = rType; PsiTypeParameter[] lTypeParams = PsiTypeParameter.EMPTY_ARRAY; PsiSubstitutor lTypeSubstitutor = PsiSubstitutor.EMPTY; - if (lType1 instanceof PsiClassType classType) { - PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics(); + if (lType1 instanceof PsiClassType lClassType) { + PsiClassType.ClassResolveResult resolveResult = lClassType.resolveGenerics(); lTypeSubstitutor = resolveResult.getSubstitutor(); PsiClass psiClass = resolveResult.getElement(); - if (psiClass instanceof PsiAnonymousClass) { - lType1 = ((PsiAnonymousClass)psiClass).getBaseClassType(); + if (psiClass instanceof PsiAnonymousClass anonymousClass) { + lType1 = anonymousClass.getBaseClassType(); resolveResult = ((PsiClassType)lType1).resolveGenerics(); lTypeSubstitutor = resolveResult.getSubstitutor(); psiClass = resolveResult.getElement(); @@ -3346,12 +3411,12 @@ public static HighlightInfo createIncompatibleTypeHighlightInfo( } PsiTypeParameter[] rTypeParams = PsiTypeParameter.EMPTY_ARRAY; PsiSubstitutor rTypeSubstitutor = PsiSubstitutor.EMPTY; - if (rType1 instanceof PsiClassType) { - PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)rType1).resolveGenerics(); + if (rType1 instanceof PsiClassType rClassType) { + PsiClassType.ClassResolveResult resolveResult = rClassType.resolveGenerics(); rTypeSubstitutor = resolveResult.getSubstitutor(); PsiClass psiClass = resolveResult.getElement(); - if (psiClass instanceof PsiAnonymousClass) { - rType1 = ((PsiAnonymousClass)psiClass).getBaseClassType(); + if (psiClass instanceof PsiAnonymousClass anonymousClass) { + rType1 = anonymousClass.getBaseClassType(); resolveResult = ((PsiClassType)rType1).resolveGenerics(); rTypeSubstitutor = resolveResult.getSubstitutor(); psiClass = resolveResult.getElement(); @@ -3360,16 +3425,16 @@ public static HighlightInfo createIncompatibleTypeHighlightInfo( } int typeParamColumns = Math.max(lTypeParams.length, rTypeParams.length); - @Language("HTML") @NonNls String requiredRow = ""; - @Language("HTML") @NonNls String foundRow = ""; + @Language("HTML") String requiredRow = ""; + @Language("HTML") String foundRow = ""; for (int i = 0; i < typeParamColumns; i++) { PsiTypeParameter lTypeParameter = i >= lTypeParams.length ? null : lTypeParams[i]; PsiTypeParameter rTypeParameter = i >= rTypeParams.length ? null : rTypeParams[i]; PsiType lSubstitutedType = lTypeParameter == null ? null : lTypeSubstitutor.substitute(lTypeParameter); PsiType rSubstitutedType = rTypeParameter == null ? null : rTypeSubstitutor.substitute(rTypeParameter); boolean matches = Comparing.equal(lSubstitutedType, rSubstitutedType); - @NonNls String openBrace = i == 0 ? "<" : ""; - @NonNls String closeBrace = i == typeParamColumns - 1 ? ">" : ","; + String openBrace = i == 0 ? "<" : ""; + String closeBrace = i == typeParamColumns - 1 ? ">" : ","; requiredRow += "" + (lTypeParams.length == 0 ? "" : openBrace) + redIfNotMatch(lSubstitutedType, matches) + (i < lTypeParams.length ? closeBrace : "") + ""; @@ -3377,11 +3442,12 @@ public static HighlightInfo createIncompatibleTypeHighlightInfo( redIfNotMatch(rSubstitutedType, matches) + (i < rTypeParams.length ? closeBrace : "") + ""; } - PsiType lRawType = lType1 instanceof PsiClassType ? ((PsiClassType)lType1).rawType() : lType1; - PsiType rRawType = rType1 instanceof PsiClassType ? ((PsiClassType)rType1).rawType() : rType1; + PsiType lRawType = lType1 instanceof PsiClassType lClassType1 ? lClassType1.rawType() : lType1; + PsiType rRawType = rType1 instanceof PsiClassType rClassType1 ? rClassType1.rawType() : rType1; boolean assignable = lRawType == null || rRawType == null || TypeConversionUtil.isAssignable(lRawType, rRawType); - LocalizeValue toolTip = JavaErrorLocalize.incompatibleTypesHtmlTooltip(redIfNotMatch(lRawType, assignable), + LocalizeValue toolTip = JavaErrorLocalize.incompatibleTypesHtmlTooltip( + redIfNotMatch(lRawType, assignable), requiredRow, redIfNotMatch(rRawType, assignable), foundRow @@ -3389,7 +3455,8 @@ public static HighlightInfo createIncompatibleTypeHighlightInfo( return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(textRange) - .description(JavaErrorLocalize.incompatibleTypes(JavaHighlightUtil.formatType(lType1), JavaHighlightUtil.formatType(rType1)).get()) + .description(JavaErrorLocalize.incompatibleTypes(JavaHighlightUtil.formatType(lType1), JavaHighlightUtil.formatType(rType1)) + .get()) .escapedToolTip(toolTip.get()) .navigationShift(navigationShift) .create(); @@ -3454,7 +3521,7 @@ public static HighlightInfo checkMustBeThrowable(@Nullable PsiType type, @Nonnul ); } - final PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(type); + PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(type); if (aClass != null) { QuickFixAction.registerQuickFixAction( highlightInfo, @@ -3515,9 +3582,8 @@ public static HighlightInfo checkReference( } PsiElement refParent = ref.getParent(); - PsiElement granny; - if (refParent instanceof PsiReferenceExpression && (granny = refParent.getParent()) instanceof PsiMethodCallExpression) { - PsiReferenceExpression referenceToMethod = ((PsiMethodCallExpression)granny).getMethodExpression(); + if (refParent instanceof PsiReferenceExpression && refParent.getParent() instanceof PsiMethodCallExpression methodCall) { + PsiReferenceExpression referenceToMethod = methodCall.getMethodExpression(); PsiExpression qualifierExpression = referenceToMethod.getQualifierExpression(); if (qualifierExpression == ref && resolved != null && !(resolved instanceof PsiClass) && !(resolved instanceof PsiVariable)) { return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF) @@ -3533,8 +3599,10 @@ else if (refParent instanceof PsiMethodCallExpression) { if (resolved == null) { // do not highlight unknown packages (javac does not care), Javadoc, and module references (checked elsewhere) PsiElement outerParent = getOuterReferenceParent(ref); - if (outerParent instanceof PsiPackageStatement || result.isPackagePrefixPackageReference() || PsiUtil.isInsideJavadocComment(ref) || outerParent instanceof - PsiPackageAccessibilityStatement) { + if (outerParent instanceof PsiPackageStatement + || result.isPackagePrefixPackageReference() + || PsiUtil.isInsideJavadocComment(ref) + || outerParent instanceof PsiPackageAccessibilityStatement) { return null; } @@ -3565,10 +3633,10 @@ else if (refParent instanceof PsiMethodCallExpression) { .create(); if (result.isStaticsScopeCorrect()) { registerAccessQuickFixAction((PsiMember)resolved, ref, info, result.getCurrentFileResolveScope()); - if (ref instanceof PsiReferenceExpression) { + if (ref instanceof PsiReferenceExpression refExpr) { QuickFixAction.registerQuickFixAction( info, - QuickFixFactory.getInstance().createRenameWrongRefFix((PsiReferenceExpression)ref) + QuickFixFactory.getInstance().createRenameWrongRefFix(refExpr) ); } } @@ -3584,10 +3652,10 @@ else if (refParent instanceof PsiMethodCallExpression) { .descriptionAndTooltip(buildProblemWithStaticDescription(resolved)) .create(); registerStaticProblemQuickFixAction(resolved, info, ref); - if (ref instanceof PsiReferenceExpression) { + if (ref instanceof PsiReferenceExpression refExpr) { QuickFixAction.registerQuickFixAction( info, - QuickFixFactory.getInstance().createRenameWrongRefFix((PsiReferenceExpression)ref) + QuickFixFactory.getInstance().createRenameWrongRefFix(refExpr) ); } return info; @@ -3597,9 +3665,9 @@ else if (refParent instanceof PsiMethodCallExpression) { if ((resolved instanceof PsiLocalVariable || resolved instanceof PsiParameter) && !(resolved instanceof ImplicitVariable)) { return HighlightControlFlowUtil.checkVariableMustBeFinal((PsiVariable)resolved, ref, languageLevel); } - if (resolved instanceof PsiClass && ((PsiClass)resolved).getContainingClass() == null + if (resolved instanceof PsiClass resolvedClass && resolvedClass.getContainingClass() == null && PsiTreeUtil.getParentOfType(ref, PsiImportStatementBase.class) != null - && PsiUtil.isFromDefaultPackage((PsiClass)resolved)) { + && PsiUtil.isFromDefaultPackage(resolvedClass)) { return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF) .range(refName) .descriptionAndTooltip(JavaErrorLocalize.cannotResolveSymbol(refName.getText())) @@ -3611,14 +3679,14 @@ else if (refParent instanceof PsiMethodCallExpression) { @Nonnull private static String format(@Nonnull PsiElement element) { - if (element instanceof PsiClass) { - return formatClass((PsiClass)element); + if (element instanceof PsiClass psiClass) { + return formatClass(psiClass); } - if (element instanceof PsiMethod) { - return JavaHighlightUtil.formatMethod((PsiMethod)element); + if (element instanceof PsiMethod method) { + return JavaHighlightUtil.formatMethod(method); } - if (element instanceof PsiField) { - return formatField((PsiField)element); + if (element instanceof PsiField field) { + return formatField(field); } return ElementDescriptionUtil.getElementDescription(element, HighlightUsagesDescriptionLocation.INSTANCE); } @@ -3655,6 +3723,7 @@ public static HighlightInfo checkPackageAndClassConflict(@Nonnull PsiJavaCodeRef } @Nullable + @RequiredReadAction public static HighlightInfo checkElementInReferenceList( @Nonnull PsiJavaCodeReferenceElement ref, @Nonnull PsiReferenceList referenceList, @@ -3691,19 +3760,20 @@ else if (refGrandParent instanceof PsiMethod method && method.getThrowsList() == } } else if (refGrandParent instanceof PsiMethod method && referenceList == method.getThrowsList()) { - String description = JavaErrorBundle.message("class.name.expected"); - highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(ref).descriptionAndTooltip(description).create(); + highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(ref) + .descriptionAndTooltip(JavaErrorLocalize.classNameExpected()) + .create(); } return highlightInfo; } - public static boolean isSerializationImplicitlyUsedField(@Nonnull PsiField field) { - final String name = field.getName(); + String name = field.getName(); if (!SERIAL_VERSION_UID_FIELD_NAME.equals(name) && !SERIAL_PERSISTENT_FIELDS_FIELD_NAME.equals(name)) { return false; } - if (!field.hasModifierProperty(PsiModifier.STATIC)) { + if (!field.isStatic()) { return false; } PsiClass aClass = field.getContainingClass(); @@ -3711,31 +3781,32 @@ public static boolean isSerializationImplicitlyUsedField(@Nonnull PsiField field } @Nullable - public static HighlightInfo checkClassReferenceAfterQualifier( - @Nonnull final PsiReferenceExpression expression, - final PsiElement resolved - ) { - if (!(resolved instanceof PsiClass)) { + @RequiredReadAction + public static HighlightInfo checkClassReferenceAfterQualifier(@Nonnull PsiReferenceExpression expression, PsiElement resolved) { + if (!(resolved instanceof PsiClass resolvedClass)) { return null; } - final PsiExpression qualifier = expression.getQualifierExpression(); + PsiExpression qualifier = expression.getQualifierExpression(); if (qualifier == null) { return null; } - if (qualifier instanceof PsiReferenceExpression) { - PsiElement qualifierResolved = ((PsiReferenceExpression)qualifier).resolve(); + if (qualifier instanceof PsiReferenceExpression qRefExpr) { + PsiElement qualifierResolved = qRefExpr.resolve(); if (qualifierResolved instanceof PsiClass || qualifierResolved instanceof PsiPackage) { return null; } } - String description = JavaErrorBundle.message("expected.class.or.package"); - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(qualifier).descriptionAndTooltip(description).create(); - QuickFixAction.registerQuickFixAction( - info, - QuickFixFactory.getInstance().createRemoveQualifierFix(qualifier, expression, (PsiClass)resolved) - ); - return info; + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(qualifier) + .descriptionAndTooltip(JavaErrorBundle.message("expected.class.or.package")) + .registerFix( + QuickFixFactory.getInstance().createRemoveQualifierFix(qualifier, expression, resolvedClass), + null, + null, + null, + null + ) + .create(); } public static void registerChangeVariableTypeFixes( @@ -3747,8 +3818,8 @@ public static void registerChangeVariableTypeFixes( for (IntentionAction action : getChangeVariableTypeFixes(parameter, itemType)) { QuickFixAction.registerQuickFixAction(highlightInfo, action); } - if (expr instanceof PsiMethodCallExpression) { - final PsiMethod method = ((PsiMethodCallExpression)expr).resolveMethod(); + if (expr instanceof PsiMethodCallExpression methodCall) { + PsiMethod method = methodCall.resolveMethod(); if (method != null) { QuickFixAction.registerQuickFixAction( highlightInfo, @@ -3784,32 +3855,33 @@ public static List getChangeVariableTypeFixes(@Nonnull PsiVaria } @Nullable + @RequiredReadAction public static HighlightInfo checkAnnotationMethodParameters(@Nonnull PsiParameterList list) { - final PsiElement parent = list.getParent(); + PsiElement parent = list.getParent(); if (PsiUtil.isAnnotationMethod(parent) && list.getParametersCount() > 0) { - final String message = JavaErrorBundle.message("annotation.interface.members.may.not.have.parameters"); - final HighlightInfo highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list).descriptionAndTooltip(message).create(); - QuickFixAction.registerQuickFixAction( - highlightInfo, - QuickFixFactory.getInstance().createRemoveParameterListFix((PsiMethod)parent) - ); - return highlightInfo; + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(list) + .descriptionAndTooltip(JavaErrorLocalize.annotationInterfaceMembersMayNotHaveParameters()) + .registerFix(QuickFixFactory.getInstance().createRemoveParameterListFix((PsiMethod)parent), null, null, null, null) + .create(); } return null; } @Nullable + @RequiredReadAction public static HighlightInfo checkForStatement(@Nonnull PsiForStatement statement) { PsiStatement init = statement.getInitialization(); - if (init == null || init instanceof PsiEmptyStatement || init instanceof PsiDeclarationStatement && ArrayUtil.getFirstElement(((PsiDeclarationStatement)init) - .getDeclaredElements()) + if (init == null || init instanceof PsiEmptyStatement + || init instanceof PsiDeclarationStatement declaration && ArrayUtil.getFirstElement(declaration.getDeclaredElements()) instanceof PsiLocalVariable || init instanceof PsiExpressionStatement || init instanceof PsiExpressionListStatement) { return null; } - String message = JavaErrorBundle.message("invalid.statement"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(init).descriptionAndTooltip(message).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(init) + .descriptionAndTooltip(JavaErrorLocalize.invalidStatement()) + .create(); } private static void registerChangeParameterClassFix(PsiType lType, PsiType rType, HighlightInfo info) { @@ -3818,8 +3890,8 @@ private static void registerChangeParameterClassFix(PsiType lType, PsiType rType @Nullable private static IntentionAction getChangeParameterClassFix(PsiType lType, PsiType rType) { - final PsiClass lClass = PsiUtil.resolveClassInClassTypeOnly(lType); - final PsiClass rClass = PsiUtil.resolveClassInClassTypeOnly(rType); + PsiClass lClass = PsiUtil.resolveClassInClassTypeOnly(lType); + PsiClass rClass = PsiUtil.resolveClassInClassTypeOnly(rType); if (rClass == null || lClass == null) { return null; @@ -3846,20 +3918,19 @@ private static void registerReplaceInaccessibleFieldWithGetterSetterFix( PsiClass accessObjectClass, HighlightInfo error ) { - if (refElement instanceof PsiField && place instanceof PsiReferenceExpression) { - final PsiField psiField = (PsiField)refElement; - final PsiClass containingClass = psiField.getContainingClass(); + if (refElement instanceof PsiField field && place instanceof PsiReferenceExpression placeRefExpr) { + PsiClass containingClass = field.getContainingClass(); if (containingClass != null) { - if (PsiUtil.isOnAssignmentLeftHand((PsiExpression)place)) { - final PsiMethod setterPrototype = PropertyUtil.generateSetterPrototype(psiField); - final PsiMethod setter = containingClass.findMethodBySignature(setterPrototype, true); - if (setter != null && PsiUtil.isAccessible(setter, place, accessObjectClass)) { - final PsiElement element = PsiTreeUtil.skipParentsOfType(place, PsiParenthesizedExpression.class); - if (element instanceof PsiAssignmentExpression && ((PsiAssignmentExpression)element).getOperationTokenType() == JavaTokenType.EQ) { + if (PsiUtil.isOnAssignmentLeftHand(placeRefExpr)) { + PsiMethod setterPrototype = PropertyUtil.generateSetterPrototype(field); + PsiMethod setter = containingClass.findMethodBySignature(setterPrototype, true); + if (setter != null && PsiUtil.isAccessible(setter, placeRefExpr, accessObjectClass)) { + PsiElement element = PsiTreeUtil.skipParentsOfType(placeRefExpr, PsiParenthesizedExpression.class); + if (element instanceof PsiAssignmentExpression assignment && assignment.getOperationTokenType() == JavaTokenType.EQ) { QuickFixAction.registerQuickFixAction( error, QuickFixFactory.getInstance().createReplaceInaccessibleFieldWithGetterSetterFix( - place, + placeRefExpr, setter, true ) @@ -3867,13 +3938,13 @@ private static void registerReplaceInaccessibleFieldWithGetterSetterFix( } } } - else if (PsiUtil.isAccessedForReading((PsiExpression)place)) { - final PsiMethod getterPrototype = PropertyUtil.generateGetterPrototype(psiField); - final PsiMethod getter = containingClass.findMethodBySignature(getterPrototype, true); - if (getter != null && PsiUtil.isAccessible(getter, place, accessObjectClass)) { + else if (PsiUtil.isAccessedForReading(placeRefExpr)) { + PsiMethod getterPrototype = PropertyUtil.generateGetterPrototype(field); + PsiMethod getter = containingClass.findMethodBySignature(getterPrototype, true); + if (getter != null && PsiUtil.isAccessible(getter, placeRefExpr, accessObjectClass)) { QuickFixAction.registerQuickFixAction( error, - QuickFixFactory.getInstance().createReplaceInaccessibleFieldWithGetterSetterFix(place, getter, false) + QuickFixFactory.getInstance().createReplaceInaccessibleFieldWithGetterSetterFix(placeRefExpr, getter, false) ); } } @@ -3882,6 +3953,7 @@ else if (PsiUtil.isAccessedForReading((PsiExpression)place)) { } @Nullable + @RequiredReadAction public static HighlightInfo checkFeature( @Nonnull PsiElement element, @Nonnull JavaFeature feature, @@ -3889,35 +3961,38 @@ public static HighlightInfo checkFeature( @Nonnull PsiFile file ) { if (file.getManager().isInProject(file) && !level.isAtLeast(feature.getMinimumLevel())) { - String message = getUnsupportedFeatureMessage(element, feature, level, file); - HighlightInfo info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(message).create(); - QuickFixAction.registerQuickFixAction( - info, - QuickFixFactory.getInstance().createIncreaseLanguageLevelFix(feature.getMinimumLevel()) - ); - QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createShowModulePropertiesFix(element)); - return info; + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(element) + .descriptionAndTooltip(getUnsupportedFeatureMessage(element, feature, level, file)) + .registerFix( + QuickFixFactory.getInstance().createIncreaseLanguageLevelFix(feature.getMinimumLevel()), + null, + null, + null, + null + ) + .registerFix(QuickFixFactory.getInstance().createShowModulePropertiesFix(element), null, null, null, null) + .create(); } return null; } @RequiredReadAction - private static String getUnsupportedFeatureMessage(PsiElement element, JavaFeature feature, LanguageLevel level, PsiFile file) { + private static LocalizeValue getUnsupportedFeatureMessage(PsiElement element, JavaFeature feature, LanguageLevel level, PsiFile file) { String name = feature.getFeatureName(); - String message = JavaErrorBundle.message("insufficient.language.level", name, level.getCompilerComplianceDefaultOption()); + LocalizeValue message = JavaErrorLocalize.insufficientLanguageLevel(name, level.getCompilerComplianceDefaultOption()); Module module = element.getModule(); if (module != null) { LanguageLevel moduleLanguageLevel = EffectiveLanguageLevelUtil.getEffectiveLanguageLevel(module); if (moduleLanguageLevel.isAtLeast(feature.getMinimumLevel())) { for (FilePropertyPusher pusher : FilePropertyPusher.EP_NAME.getExtensionList()) { - if (pusher instanceof JavaLanguageLevelPusher) { + if (pusher instanceof JavaLanguageLevelPusher languageLevelPusher) { String newMessage = - ((JavaLanguageLevelPusher)pusher).getInconsistencyLanguageLevelMessage(message, element, level, file); + languageLevelPusher.getInconsistencyLanguageLevelMessage(message.get(), element, level, file); if (newMessage != null) { - return newMessage; + return LocalizeValue.localizeTODO(newMessage); } } } 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 3a7d14cf61..efdeceed40 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 @@ -1848,6 +1848,7 @@ private void checkFunctionalInterfaceTypeAccessible(@Nonnull PsiFunctionalExpres } @Override + @RequiredReadAction public void visitReferenceList(PsiReferenceList list) { if (list.getFirstChild() == null) { return; @@ -1871,6 +1872,7 @@ public void visitReferenceList(PsiReferenceList list) { } @Override + @RequiredReadAction public void visitReferenceParameterList(PsiReferenceParameterList list) { if (list.getTextLength() == 0) { return; @@ -1893,7 +1895,8 @@ public void visitReferenceParameterList(PsiReferenceParameterList list) { } @Override - public void visitReturnStatement(PsiReturnStatement statement) { + @RequiredReadAction + public void visitReturnStatement(@Nonnull PsiReturnStatement statement) { try { myHolder.add(HighlightUtil.checkReturnStatementType(statement)); } @@ -1902,7 +1905,8 @@ public void visitReturnStatement(PsiReturnStatement statement) { } @Override - public void visitStatement(PsiStatement statement) { + @RequiredReadAction + public void visitStatement(@Nonnull PsiStatement statement) { super.visitStatement(statement); if (!myHolder.hasErrorResults()) { myHolder.add(HighlightUtil.checkNotAStatement(statement)); @@ -1910,7 +1914,8 @@ public void visitStatement(PsiStatement statement) { } @Override - public void visitSuperExpression(PsiSuperExpression expr) { + @RequiredReadAction + public void visitSuperExpression(@Nonnull PsiSuperExpression expr) { myHolder.add(HighlightUtil.checkThisOrSuperExpressionInIllegalContext(expr, expr.getQualifier(), myLanguageLevel)); if (!myHolder.hasErrorResults()) { visitExpression(expr); @@ -1918,7 +1923,8 @@ public void visitSuperExpression(PsiSuperExpression expr) { } @Override - public void visitSwitchLabelStatement(PsiSwitchLabelStatement statement) { + @RequiredReadAction + public void visitSwitchLabelStatement(@Nonnull PsiSwitchLabelStatement statement) { super.visitSwitchLabelStatement(statement); if (!myHolder.hasErrorResults()) { myHolder.add(HighlightUtil.checkCaseStatement(statement)); @@ -1926,7 +1932,8 @@ public void visitSwitchLabelStatement(PsiSwitchLabelStatement statement) { } @Override - public void visitSwitchLabeledRuleStatement(PsiSwitchLabeledRuleStatement statement) { + @RequiredReadAction + public void visitSwitchLabeledRuleStatement(@Nonnull PsiSwitchLabeledRuleStatement statement) { super.visitSwitchLabeledRuleStatement(statement); if (!myHolder.hasErrorResults()) { myHolder.add(HighlightUtil.checkCaseStatement(statement)); @@ -1935,11 +1942,13 @@ public void visitSwitchLabeledRuleStatement(PsiSwitchLabeledRuleStatement statem @Override - public void visitSwitchStatement(PsiSwitchStatement statement) { + @RequiredReadAction + public void visitSwitchStatement(@Nonnull PsiSwitchStatement statement) { super.visitSwitchStatement(statement); checkSwitchBlock(statement); } + @RequiredReadAction private void checkSwitchBlock(PsiSwitchBlock switchBlock) { if (!myHolder.hasErrorResults()) { myHolder.add(HighlightUtil.checkSwitchBlockStatements(switchBlock, myLanguageLevel, myFile)); @@ -1953,6 +1962,7 @@ private void checkSwitchBlock(PsiSwitchBlock switchBlock) { } @Override + @RequiredReadAction public void visitThisExpression(PsiThisExpression expr) { if (!(expr.getParent() instanceof PsiReceiverParameter)) { myHolder.add(HighlightUtil.checkThisOrSuperExpressionInIllegalContext(expr, expr.getQualifier(), myLanguageLevel)); @@ -1966,7 +1976,8 @@ public void visitThisExpression(PsiThisExpression expr) { } @Override - public void visitThrowStatement(PsiThrowStatement statement) { + @RequiredReadAction + public void visitThrowStatement(@Nonnull PsiThrowStatement statement) { myHolder.add(HighlightUtil.checkUnhandledExceptions(statement, null)); if (!myHolder.hasErrorResults()) { visitStatement(statement); @@ -1974,7 +1985,8 @@ public void visitThrowStatement(PsiThrowStatement statement) { } @Override - public void visitTryStatement(PsiTryStatement statement) { + @RequiredReadAction + public void visitTryStatement(@Nonnull PsiTryStatement statement) { super.visitTryStatement(statement); if (!myHolder.hasErrorResults()) { final Set thrownTypes = HighlightUtil.collectUnhandledExceptions(statement); @@ -1991,7 +2003,7 @@ public void visitTryStatement(PsiTryStatement statement) { } @Override - public void visitResourceList(PsiResourceList resourceList) { + public void visitResourceList(@Nonnull PsiResourceList resourceList) { super.visitResourceList(resourceList); if (!myHolder.hasErrorResults()) { myHolder.add(checkFeature(resourceList, JavaFeature.TRY_WITH_RESOURCES)); @@ -1999,7 +2011,8 @@ public void visitResourceList(PsiResourceList resourceList) { } @Override - public void visitResourceVariable(PsiResourceVariable resource) { + @RequiredReadAction + public void visitResourceVariable(@Nonnull PsiResourceVariable resource) { super.visitResourceVariable(resource); if (!myHolder.hasErrorResults()) { myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resource)); @@ -2010,7 +2023,8 @@ public void visitResourceVariable(PsiResourceVariable resource) { } @Override - public void visitResourceExpression(PsiResourceExpression resource) { + @RequiredReadAction + public void visitResourceExpression(@Nonnull PsiResourceExpression resource) { super.visitResourceExpression(resource); if (!myHolder.hasErrorResults()) { myHolder.add(checkFeature(resource, JavaFeature.REFS_AS_RESOURCE)); @@ -2027,7 +2041,7 @@ public void visitResourceExpression(PsiResourceExpression resource) { } @Override - public void visitTypeElement(PsiTypeElement type) { + public void visitTypeElement(@Nonnull PsiTypeElement type) { if (!myHolder.hasErrorResults()) { myHolder.add(HighlightUtil.checkIllegalType(type)); } diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/quickfix/QualifySuperArgumentFix.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/quickfix/QualifySuperArgumentFix.java index f054caa4cb..d3b7a09f3d 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/quickfix/QualifySuperArgumentFix.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInsight/daemon/impl/quickfix/QualifySuperArgumentFix.java @@ -25,6 +25,8 @@ import com.intellij.java.language.impl.refactoring.util.RefactoringChangeUtil; import com.intellij.java.language.psi.*; +import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; import consulo.language.editor.intention.QuickFixAction; import consulo.language.editor.rawHighlight.HighlightInfo; import consulo.language.psi.PsiManager; @@ -43,32 +45,35 @@ protected String getQualifierText() { } @Override + @RequiredWriteAction protected PsiExpression getQualifier(PsiManager manager) { return RefactoringChangeUtil.createSuperExpression(manager, myPsiClass); } + @RequiredReadAction public static void registerQuickFixAction(@Nonnull PsiSuperExpression expr, HighlightInfo highlightInfo) { LOG.assertTrue(expr.getQualifier() == null); - final PsiClass containingClass = PsiTreeUtil.getParentOfType(expr, PsiClass.class); + PsiClass containingClass = PsiTreeUtil.getParentOfType(expr, PsiClass.class); if (containingClass != null && containingClass.isInterface()) { - final PsiMethodCallExpression callExpression = PsiTreeUtil.getParentOfType( + PsiMethodCallExpression callExpression = PsiTreeUtil.getParentOfType( expr, PsiMethodCallExpression.class ); if (callExpression != null) { - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(callExpression.getProject()); + PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(callExpression.getProject()); for (PsiClass superClass : containingClass.getSupers()) { if (superClass.isInterface()) { - final PsiMethodCallExpression copy = (PsiMethodCallExpression)callExpression.copy(); - final PsiExpression superQualifierCopy = copy.getMethodExpression().getQualifierExpression(); + PsiMethodCallExpression copy = (PsiMethodCallExpression)callExpression.copy(); + PsiExpression superQualifierCopy = copy.getMethodExpression().getQualifierExpression(); LOG.assertTrue(superQualifierCopy != null); superQualifierCopy.delete(); - if (((PsiMethodCallExpression)elementFactory.createExpressionFromText(copy.getText(), superClass)) - .resolveMethod() != null) { - QuickFixAction.registerQuickFixAction(highlightInfo, new QualifySuperArgumentFix( - expr, - superClass - )); + PsiMethodCallExpression expressionFromText = + (PsiMethodCallExpression)elementFactory.createExpressionFromText(copy.getText(), superClass); + if (expressionFromText.resolveMethod() != null) { + QuickFixAction.registerQuickFixAction( + highlightInfo, + new QualifySuperArgumentFix(expr, superClass) + ); } } } From a01bd825ccc08e2bbb39313fe9eaa9c6d2b5b469 Mon Sep 17 00:00:00 2001 From: UNV Date: Sat, 3 May 2025 16:51:41 +0300 Subject: [PATCH 3/4] Reformatting. --- .../impl/JavaLanguageLevelPusher.java | 172 +++++++++--------- 1 file changed, 89 insertions(+), 83 deletions(-) diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/JavaLanguageLevelPusher.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/JavaLanguageLevelPusher.java index b9fd09c0c0..f3819c51dd 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/JavaLanguageLevelPusher.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/JavaLanguageLevelPusher.java @@ -35,6 +35,7 @@ import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -44,95 +45,100 @@ */ @ExtensionImpl public class JavaLanguageLevelPusher implements FilePropertyPusher { + public static void pushLanguageLevel(final Project project) { + PushedFilePropertiesUpdater.getInstance(project).pushAll(new JavaLanguageLevelPusher()); + } + + @Override + @Nonnull + public Key getFileDataKey() { + return LanguageLevel.KEY; + } - public static void pushLanguageLevel(final Project project) { - PushedFilePropertiesUpdater.getInstance(project).pushAll(new JavaLanguageLevelPusher()); - } - - @Override - @Nonnull - public Key getFileDataKey() { - return LanguageLevel.KEY; - } - - @Override - public boolean pushDirectoriesOnly() { - return true; - } - - @Override - @Nonnull - public LanguageLevel getDefaultValue() { - return LanguageLevel.HIGHEST; - } - - @Override - public LanguageLevel getImmediateValue(@Nonnull Project project, VirtualFile file) { - if (file == null) { - return null; + @Override + public boolean pushDirectoriesOnly() { + return true; } - final Module moduleForFile = ModuleUtilCore.findModuleForFile(file, project); - if (moduleForFile == null) { - return null; + + @Override + @Nonnull + public LanguageLevel getDefaultValue() { + return LanguageLevel.HIGHEST; } - return getImmediateValue(moduleForFile); - } - - @Override - public LanguageLevel getImmediateValue(@Nonnull Module module) { - ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); - - final JavaModuleExtension extension = moduleRootManager.getExtension(JavaModuleExtension.class); - return extension == null ? null : extension.getLanguageLevel(); - } - - @Override - public boolean acceptsDirectory(@Nonnull VirtualFile file, @Nonnull Project project) { - return ProjectFileIndex.getInstance(project).isInSourceContent(file); - } - - private static final FileAttribute PERSISTENCE = new FileAttribute("language_level_persistence", 2, true); - - @Override - public void persistAttribute(@Nonnull Project project, @Nonnull VirtualFile fileOrDir, @Nonnull LanguageLevel level) throws IOException { - final DataInputStream iStream = PERSISTENCE.readAttribute(fileOrDir); - if (iStream != null) { - try { - final int oldLevelOrdinal = DataInputOutputUtil.readINT(iStream); - if (oldLevelOrdinal == level.ordinal()) { - return; + + @Override + public LanguageLevel getImmediateValue(@Nonnull Project project, VirtualFile file) { + if (file == null) { + return null; } - } - finally { - iStream.close(); - } + final Module moduleForFile = ModuleUtilCore.findModuleForFile(file, project); + if (moduleForFile == null) { + return null; + } + return getImmediateValue(moduleForFile); } - final DataOutputStream oStream = PERSISTENCE.writeAttribute(fileOrDir); - DataInputOutputUtil.writeINT(oStream, level.ordinal()); - oStream.close(); + @Override + public LanguageLevel getImmediateValue(@Nonnull Module module) { + ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); + + final JavaModuleExtension extension = moduleRootManager.getExtension(JavaModuleExtension.class); + return extension == null ? null : extension.getLanguageLevel(); + } + + @Override + public boolean acceptsDirectory(@Nonnull VirtualFile file, @Nonnull Project project) { + return ProjectFileIndex.getInstance(project).isInSourceContent(file); + } + + private static final FileAttribute PERSISTENCE = new FileAttribute("language_level_persistence", 2, true); + + @Override + public void persistAttribute( + @Nonnull Project project, + @Nonnull VirtualFile fileOrDir, + @Nonnull LanguageLevel level + ) throws IOException { + final DataInputStream iStream = PERSISTENCE.readAttribute(fileOrDir); + if (iStream != null) { + try { + final int oldLevelOrdinal = DataInputOutputUtil.readINT(iStream); + if (oldLevelOrdinal == level.ordinal()) { + return; + } + } + finally { + iStream.close(); + } + } + + final DataOutputStream oStream = PERSISTENCE.writeAttribute(fileOrDir); + DataInputOutputUtil.writeINT(oStream, level.ordinal()); + oStream.close(); + + for (VirtualFile child : fileOrDir.getChildren()) { + if (!child.isDirectory() && JavaFileType.INSTANCE == child.getFileType()) { + PushedFilePropertiesUpdater.getInstance(project).filePropertiesChanged(child); + } + } + } + + @Override + public void afterRootsChanged(@Nonnull Project project) { + } + + @Override + public boolean acceptsFile(@Nonnull VirtualFile file, @Nonnull Project project) { + return false; + } - for (VirtualFile child : fileOrDir.getChildren()) { - if (!child.isDirectory() && JavaFileType.INSTANCE == child.getFileType()) { - PushedFilePropertiesUpdater.getInstance(project).filePropertiesChanged(child); - } + @Nullable + public String getInconsistencyLanguageLevelMessage( + @Nonnull String message, + @Nonnull PsiElement element, + @Nonnull LanguageLevel level, + @Nonnull PsiFile file + ) { + return null; } - } - - @Override - public void afterRootsChanged(@Nonnull Project project) { - } - - @Override - public boolean acceptsFile(@Nonnull VirtualFile file, @Nonnull Project project) { - return false; - } - - @Nullable - public String getInconsistencyLanguageLevelMessage(@Nonnull String message, - @Nonnull PsiElement element, - @Nonnull LanguageLevel level, - @Nonnull PsiFile file) { - return null; - } } From 9fddba33d0f16564db2a4fc9655de5c5fdeaa192 Mon Sep 17 00:00:00 2001 From: UNV Date: Sat, 3 May 2025 16:57:08 +0300 Subject: [PATCH 4/4] Localizing JavaLanguageLevelPusher. --- .../java/analysis/impl/JavaLanguageLevelPusher.java | 10 +++++----- .../daemon/impl/analysis/HighlightUtil.java | 7 +++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/JavaLanguageLevelPusher.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/JavaLanguageLevelPusher.java index f3819c51dd..b72f8c08b2 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/JavaLanguageLevelPusher.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/JavaLanguageLevelPusher.java @@ -23,6 +23,7 @@ import consulo.language.psi.PsiElement; import consulo.language.psi.PsiFile; import consulo.language.util.ModuleUtilCore; +import consulo.localize.LocalizeValue; import consulo.module.Module; import consulo.module.content.FilePropertyPusher; import consulo.module.content.ModuleRootManager; @@ -34,7 +35,6 @@ import consulo.virtualFileSystem.VirtualFile; import jakarta.annotation.Nonnull; -import jakarta.annotation.Nullable; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -132,13 +132,13 @@ public boolean acceptsFile(@Nonnull VirtualFile file, @Nonnull Project project) return false; } - @Nullable - public String getInconsistencyLanguageLevelMessage( - @Nonnull String message, + @Nonnull + public LocalizeValue getInconsistencyLanguageLevelMessage( + @Nonnull LocalizeValue message, @Nonnull PsiElement element, @Nonnull LanguageLevel level, @Nonnull PsiFile file ) { - return null; + return LocalizeValue.empty(); } } 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 4640860bc0..5d0b9faa8d 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 @@ -3989,10 +3989,9 @@ private static LocalizeValue getUnsupportedFeatureMessage(PsiElement element, Ja if (moduleLanguageLevel.isAtLeast(feature.getMinimumLevel())) { for (FilePropertyPusher pusher : FilePropertyPusher.EP_NAME.getExtensionList()) { if (pusher instanceof JavaLanguageLevelPusher languageLevelPusher) { - String newMessage = - languageLevelPusher.getInconsistencyLanguageLevelMessage(message.get(), element, level, file); - if (newMessage != null) { - return LocalizeValue.localizeTODO(newMessage); + LocalizeValue newMessage = languageLevelPusher.getInconsistencyLanguageLevelMessage(message, element, level, file); + if (newMessage != LocalizeValue.empty()) { + return newMessage; } } }